mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-31 21:51:22 +00:00 
			
		
		
		
	Massive rewrite to AnimationTree. Many APIs changed in order to:
-Reuse resources -Expose properties in AnimationTree
This commit is contained in:
		
							parent
							
								
									1b66b08fdb
								
							
						
					
					
						commit
						c7e4527a88
					
				
					 34 changed files with 3856 additions and 2937 deletions
				
			
		|  | @ -1476,9 +1476,14 @@ Error Object::connect(const StringName &p_signal, Object *p_to_object, const Str | ||||||
| 
 | 
 | ||||||
| 	Signal::Target target(p_to_object->get_instance_id(), p_to_method); | 	Signal::Target target(p_to_object->get_instance_id(), p_to_method); | ||||||
| 	if (s->slot_map.has(target)) { | 	if (s->slot_map.has(target)) { | ||||||
|  | 		if (p_flags & CONNECT_REFERENCE_COUNTED) { | ||||||
|  | 			s->slot_map[target].reference_count++; | ||||||
|  | 			return OK; | ||||||
|  | 		} else { | ||||||
| 			ERR_EXPLAIN("Signal '" + p_signal + "' is already connected to given method '" + p_to_method + "' in that object."); | 			ERR_EXPLAIN("Signal '" + p_signal + "' is already connected to given method '" + p_to_method + "' in that object."); | ||||||
| 			ERR_FAIL_COND_V(s->slot_map.has(target), ERR_INVALID_PARAMETER); | 			ERR_FAIL_COND_V(s->slot_map.has(target), ERR_INVALID_PARAMETER); | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	Signal::Slot slot; | 	Signal::Slot slot; | ||||||
| 
 | 
 | ||||||
|  | @ -1491,6 +1496,10 @@ Error Object::connect(const StringName &p_signal, Object *p_to_object, const Str | ||||||
| 	conn.binds = p_binds; | 	conn.binds = p_binds; | ||||||
| 	slot.conn = conn; | 	slot.conn = conn; | ||||||
| 	slot.cE = p_to_object->connections.push_back(conn); | 	slot.cE = p_to_object->connections.push_back(conn); | ||||||
|  | 	if (p_flags & CONNECT_REFERENCE_COUNTED) { | ||||||
|  | 		slot.reference_count = 1; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	s->slot_map[target] = slot; | 	s->slot_map[target] = slot; | ||||||
| 
 | 
 | ||||||
| 	return OK; | 	return OK; | ||||||
|  | @ -1539,7 +1548,14 @@ void Object::disconnect(const StringName &p_signal, Object *p_to_object, const S | ||||||
| 		ERR_FAIL(); | 		ERR_FAIL(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	p_to_object->connections.erase(s->slot_map[target].cE); | 	Signal::Slot *slot = &s->slot_map[target]; | ||||||
|  | 
 | ||||||
|  | 	slot->reference_count--; // by default is zero, if it was not referenced it will go below it
 | ||||||
|  | 	if (slot->reference_count >= 0) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	p_to_object->connections.erase(slot->cE); | ||||||
| 	s->slot_map.erase(target); | 	s->slot_map.erase(target); | ||||||
| 
 | 
 | ||||||
| 	if (s->slot_map.empty() && ClassDB::has_signal(get_class_name(), p_signal)) { | 	if (s->slot_map.empty() && ClassDB::has_signal(get_class_name(), p_signal)) { | ||||||
|  | @ -1761,6 +1777,7 @@ void Object::_bind_methods() { | ||||||
| 	BIND_ENUM_CONSTANT(CONNECT_DEFERRED); | 	BIND_ENUM_CONSTANT(CONNECT_DEFERRED); | ||||||
| 	BIND_ENUM_CONSTANT(CONNECT_PERSIST); | 	BIND_ENUM_CONSTANT(CONNECT_PERSIST); | ||||||
| 	BIND_ENUM_CONSTANT(CONNECT_ONESHOT); | 	BIND_ENUM_CONSTANT(CONNECT_ONESHOT); | ||||||
|  | 	BIND_ENUM_CONSTANT(CONNECT_REFERENCE_COUNTED); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Object::call_deferred(const StringName &p_method, VARIANT_ARG_DECLARE) { | void Object::call_deferred(const StringName &p_method, VARIANT_ARG_DECLARE) { | ||||||
|  |  | ||||||
|  | @ -392,7 +392,8 @@ public: | ||||||
| 
 | 
 | ||||||
| 		CONNECT_DEFERRED = 1, | 		CONNECT_DEFERRED = 1, | ||||||
| 		CONNECT_PERSIST = 2, // hint for scene to save this connection
 | 		CONNECT_PERSIST = 2, // hint for scene to save this connection
 | ||||||
| 		CONNECT_ONESHOT = 4 | 		CONNECT_ONESHOT = 4, | ||||||
|  | 		CONNECT_REFERENCE_COUNTED = 8, | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	struct Connection { | 	struct Connection { | ||||||
|  | @ -443,8 +444,10 @@ private: | ||||||
| 
 | 
 | ||||||
| 		struct Slot { | 		struct Slot { | ||||||
| 
 | 
 | ||||||
|  | 			int reference_count; | ||||||
| 			Connection conn; | 			Connection conn; | ||||||
| 			List<Connection>::Element *cE; | 			List<Connection>::Element *cE; | ||||||
|  | 			Slot() { reference_count = 0; } | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		MethodInfo user; | 		MethodInfo user; | ||||||
|  |  | ||||||
|  | @ -1533,9 +1533,10 @@ void EditorInspector::update_tree() { | ||||||
| 
 | 
 | ||||||
| 					if (capitalize_paths) | 					if (capitalize_paths) | ||||||
| 						path_name = path_name.capitalize(); | 						path_name = path_name.capitalize(); | ||||||
|  | 
 | ||||||
| 					Color c = sscolor; | 					Color c = sscolor; | ||||||
| 					c.a /= level; | 					c.a /= level; | ||||||
| 					section->setup(path_name, acc_path, object, c, use_folding); | 					section->setup(path_name, path_name, object, c, use_folding); | ||||||
| 
 | 
 | ||||||
| 					item_path[acc_path] = section->get_vbox(); | 					item_path[acc_path] = section->get_vbox(); | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
|  | @ -74,6 +74,7 @@ | ||||||
| #include "editor/plugins/animation_player_editor_plugin.h" | #include "editor/plugins/animation_player_editor_plugin.h" | ||||||
| #include "editor/plugins/animation_state_machine_editor.h" | #include "editor/plugins/animation_state_machine_editor.h" | ||||||
| #include "editor/plugins/animation_tree_editor_plugin.h" | #include "editor/plugins/animation_tree_editor_plugin.h" | ||||||
|  | #include "editor/plugins/animation_tree_player_editor_plugin.h" | ||||||
| #include "editor/plugins/asset_library_editor_plugin.h" | #include "editor/plugins/asset_library_editor_plugin.h" | ||||||
| #include "editor/plugins/audio_stream_editor_plugin.h" | #include "editor/plugins/audio_stream_editor_plugin.h" | ||||||
| #include "editor/plugins/baked_lightmap_editor_plugin.h" | #include "editor/plugins/baked_lightmap_editor_plugin.h" | ||||||
|  | @ -5589,16 +5590,13 @@ EditorNode::EditorNode() { | ||||||
| 
 | 
 | ||||||
| 	add_editor_plugin(memnew(ShaderEditorPlugin(this))); | 	add_editor_plugin(memnew(ShaderEditorPlugin(this))); | ||||||
| 	add_editor_plugin(memnew(VisualShaderEditorPlugin(this))); | 	add_editor_plugin(memnew(VisualShaderEditorPlugin(this))); | ||||||
| 	add_editor_plugin(memnew(AnimationNodeBlendTreeEditorPlugin(this))); |  | ||||||
| 	add_editor_plugin(memnew(AnimationNodeBlendSpace1DEditorPlugin(this))); |  | ||||||
| 	add_editor_plugin(memnew(AnimationNodeBlendSpace2DEditorPlugin(this))); |  | ||||||
| 	add_editor_plugin(memnew(AnimationNodeStateMachineEditorPlugin(this))); |  | ||||||
| 
 | 
 | ||||||
| 	add_editor_plugin(memnew(CameraEditorPlugin(this))); | 	add_editor_plugin(memnew(CameraEditorPlugin(this))); | ||||||
| 	add_editor_plugin(memnew(ThemeEditorPlugin(this))); | 	add_editor_plugin(memnew(ThemeEditorPlugin(this))); | ||||||
| 	add_editor_plugin(memnew(MultiMeshEditorPlugin(this))); | 	add_editor_plugin(memnew(MultiMeshEditorPlugin(this))); | ||||||
| 	add_editor_plugin(memnew(MeshInstanceEditorPlugin(this))); | 	add_editor_plugin(memnew(MeshInstanceEditorPlugin(this))); | ||||||
| 	add_editor_plugin(memnew(AnimationTreeEditorPlugin(this))); | 	add_editor_plugin(memnew(AnimationTreeEditorPlugin(this))); | ||||||
|  | 	add_editor_plugin(memnew(AnimationTreePlayerEditorPlugin(this))); | ||||||
| 	add_editor_plugin(memnew(MeshLibraryEditorPlugin(this))); | 	add_editor_plugin(memnew(MeshLibraryEditorPlugin(this))); | ||||||
| 	add_editor_plugin(memnew(StyleBoxEditorPlugin(this))); | 	add_editor_plugin(memnew(StyleBoxEditorPlugin(this))); | ||||||
| 	add_editor_plugin(memnew(SpriteEditorPlugin(this))); | 	add_editor_plugin(memnew(SpriteEditorPlugin(this))); | ||||||
|  |  | ||||||
|  | @ -36,6 +36,16 @@ | ||||||
| 
 | 
 | ||||||
| void InspectorDock::_menu_option(int p_option) { | void InspectorDock::_menu_option(int p_option) { | ||||||
| 	switch (p_option) { | 	switch (p_option) { | ||||||
|  | 		case RESOURCE_MAKE_BUILT_IN: { | ||||||
|  | 			_unref_resource(); | ||||||
|  | 		} break; | ||||||
|  | 		case RESOURCE_COPY: { | ||||||
|  | 			_copy_resource(); | ||||||
|  | 		} break; | ||||||
|  | 		case RESOURCE_EDIT_CLIPBOARD: { | ||||||
|  | 			_paste_resource(); | ||||||
|  | 		} break; | ||||||
|  | 
 | ||||||
| 		case RESOURCE_SAVE: { | 		case RESOURCE_SAVE: { | ||||||
| 			_save_resource(false); | 			_save_resource(false); | ||||||
| 		} break; | 		} break; | ||||||
|  | @ -400,10 +410,11 @@ void InspectorDock::update(Object *p_object) { | ||||||
| 	p->add_shortcut(ED_SHORTCUT("property_editor/copy_params", TTR("Copy Params")), OBJECT_COPY_PARAMS); | 	p->add_shortcut(ED_SHORTCUT("property_editor/copy_params", TTR("Copy Params")), OBJECT_COPY_PARAMS); | ||||||
| 	p->add_shortcut(ED_SHORTCUT("property_editor/paste_params", TTR("Paste Params")), OBJECT_PASTE_PARAMS); | 	p->add_shortcut(ED_SHORTCUT("property_editor/paste_params", TTR("Paste Params")), OBJECT_PASTE_PARAMS); | ||||||
| 	p->add_separator(); | 	p->add_separator(); | ||||||
| 	p->add_shortcut(ED_SHORTCUT("property_editor/paste_resource", TTR("Paste Resource")), RESOURCE_PASTE); | 
 | ||||||
|  | 	p->add_shortcut(ED_SHORTCUT("property_editor/paste_resource", TTR("Edit Resource Clipboard")), RESOURCE_EDIT_CLIPBOARD); | ||||||
| 	if (is_resource) { | 	if (is_resource) { | ||||||
| 		p->add_shortcut(ED_SHORTCUT("property_editor/copy_resource", TTR("Copy Resource")), RESOURCE_COPY); | 		p->add_shortcut(ED_SHORTCUT("property_editor/copy_resource", TTR("Copy Resource")), RESOURCE_COPY); | ||||||
| 		p->add_shortcut(ED_SHORTCUT("property_editor/unref_resource", TTR("Make Built-In")), RESOURCE_UNREF); | 		p->add_shortcut(ED_SHORTCUT("property_editor/unref_resource", TTR("Make Built-In")), RESOURCE_MAKE_BUILT_IN); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (is_resource || is_node) { | 	if (is_resource || is_node) { | ||||||
|  |  | ||||||
|  | @ -51,13 +51,12 @@ class InspectorDock : public VBoxContainer { | ||||||
| 	GDCLASS(InspectorDock, VBoxContainer); | 	GDCLASS(InspectorDock, VBoxContainer); | ||||||
| 
 | 
 | ||||||
| 	enum MenuOptions { | 	enum MenuOptions { | ||||||
| 		RESOURCE_NEW, |  | ||||||
| 		RESOURCE_LOAD, | 		RESOURCE_LOAD, | ||||||
| 		RESOURCE_SAVE, | 		RESOURCE_SAVE, | ||||||
| 		RESOURCE_SAVE_AS, | 		RESOURCE_SAVE_AS, | ||||||
| 		RESOURCE_UNREF, | 		RESOURCE_MAKE_BUILT_IN, | ||||||
| 		RESOURCE_COPY, | 		RESOURCE_COPY, | ||||||
| 		RESOURCE_PASTE, | 		RESOURCE_EDIT_CLIPBOARD, | ||||||
| 		OBJECT_COPY_PARAMS, | 		OBJECT_COPY_PARAMS, | ||||||
| 		OBJECT_PASTE_PARAMS, | 		OBJECT_PASTE_PARAMS, | ||||||
| 		OBJECT_UNIQUE_RESOURCES, | 		OBJECT_UNIQUE_RESOURCES, | ||||||
|  |  | ||||||
|  | @ -3,41 +3,11 @@ | ||||||
| #include "os/keyboard.h" | #include "os/keyboard.h" | ||||||
| #include "scene/animation/animation_blend_tree.h" | #include "scene/animation/animation_blend_tree.h" | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendSpace1DEditorPlugin::edit(Object *p_object) { | StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const { | ||||||
| 	anim_tree_editor->edit(Object::cast_to<AnimationNodeBlendSpace1D>(p_object)); | 	StringName path = AnimationTreeEditor::get_singleton()->get_base_path()+"blend_position"; | ||||||
|  | 	return path; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool AnimationNodeBlendSpace1DEditorPlugin::handles(Object *p_object) const { |  | ||||||
| 	return p_object->is_class("AnimationNodeBlendSpace1D"); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void AnimationNodeBlendSpace1DEditorPlugin::make_visible(bool p_visible) { |  | ||||||
| 
 |  | ||||||
| 	if (p_visible) { |  | ||||||
| 		button->show(); |  | ||||||
| 		editor->make_bottom_panel_item_visible(anim_tree_editor); |  | ||||||
| 		anim_tree_editor->set_process(true); |  | ||||||
| 	} else { |  | ||||||
| 		if (anim_tree_editor->is_visible_in_tree()) { |  | ||||||
| 			editor->hide_bottom_panel(); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		button->hide(); |  | ||||||
| 		anim_tree_editor->set_process(false); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| AnimationNodeBlendSpace1DEditorPlugin::AnimationNodeBlendSpace1DEditorPlugin(EditorNode *p_node) { |  | ||||||
| 	editor = p_node; |  | ||||||
| 	anim_tree_editor = memnew(AnimationNodeBlendSpace1DEditor); |  | ||||||
| 	anim_tree_editor->set_custom_minimum_size(Size2(0, 150 * EDSCALE)); |  | ||||||
| 
 |  | ||||||
| 	button = editor->add_bottom_panel_item(TTR("BlendSpace1D"), anim_tree_editor); |  | ||||||
| 	button->hide(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| AnimationNodeBlendSpace1DEditorPlugin::~AnimationNodeBlendSpace1DEditorPlugin() { |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) { | void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) { | ||||||
| 	Ref<InputEventKey> k = p_event; | 	Ref<InputEventKey> k = p_event; | ||||||
|  | @ -62,7 +32,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven | ||||||
| 
 | 
 | ||||||
| 		menu->add_submenu_item(TTR("Add Animation"), "animations"); | 		menu->add_submenu_item(TTR("Add Animation"), "animations"); | ||||||
| 
 | 
 | ||||||
| 		AnimationTree *gp = blend_space->get_tree(); | 		AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree(); | ||||||
| 		ERR_FAIL_COND(!gp); | 		ERR_FAIL_COND(!gp); | ||||||
| 
 | 
 | ||||||
| 		if (gp->has_node(gp->get_animation_player())) { | 		if (gp->has_node(gp->get_animation_player())) { | ||||||
|  | @ -85,10 +55,18 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven | ||||||
| 				continue; | 				continue; | ||||||
| 
 | 
 | ||||||
| 			int idx = menu->get_item_count(); | 			int idx = menu->get_item_count(); | ||||||
| 			menu->add_item(vformat("Add %s", name)); | 			menu->add_item(vformat("Add %s", name),idx); | ||||||
| 			menu->set_item_metadata(idx, E->get()); | 			menu->set_item_metadata(idx, E->get()); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard(); | ||||||
|  | 		if (clipb.is_valid()) { | ||||||
|  | 			menu->add_separator(); | ||||||
|  | 			menu->add_item(TTR("Paste"), MENU_PASTE); | ||||||
|  | 		} | ||||||
|  | 		menu->add_separator(); | ||||||
|  | 		menu->add_item(TTR("Load.."), MENU_LOAD_FILE); | ||||||
|  | 
 | ||||||
| 		menu->set_global_position(blend_space_draw->get_global_transform().xform(mb->get_position())); | 		menu->set_global_position(blend_space_draw->get_global_transform().xform(mb->get_position())); | ||||||
| 		menu->popup(); | 		menu->popup(); | ||||||
| 
 | 
 | ||||||
|  | @ -158,7 +136,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven | ||||||
| 		blend_pos *= blend_space->get_max_space() - blend_space->get_min_space(); | 		blend_pos *= blend_space->get_max_space() - blend_space->get_min_space(); | ||||||
| 		blend_pos += blend_space->get_min_space(); | 		blend_pos += blend_space->get_min_space(); | ||||||
| 
 | 
 | ||||||
| 		blend_space->set_blend_pos(blend_pos); | 		AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(),blend_pos); | ||||||
| 		blend_space_draw->update(); | 		blend_space_draw->update(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -181,7 +159,8 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven | ||||||
| 		blend_pos *= blend_space->get_max_space() - blend_space->get_min_space(); | 		blend_pos *= blend_space->get_max_space() - blend_space->get_min_space(); | ||||||
| 		blend_pos += blend_space->get_min_space(); | 		blend_pos += blend_space->get_min_space(); | ||||||
| 
 | 
 | ||||||
| 		blend_space->set_blend_pos(blend_pos); | 		AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(),blend_pos); | ||||||
|  | 
 | ||||||
| 		blend_space_draw->update(); | 		blend_space_draw->update(); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -277,7 +256,9 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() { | ||||||
| 			color.a *= 0.5; | 			color.a *= 0.5; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		float point = blend_space->get_blend_pos(); | 		float point = AnimationTreeEditor::get_singleton()->get_tree()->get(get_blend_position_path()); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 		point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); | 		point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); | ||||||
| 		point *= s.width; | 		point *= s.width; | ||||||
| 
 | 
 | ||||||
|  | @ -299,12 +280,6 @@ void AnimationNodeBlendSpace1DEditor::_update_space() { | ||||||
| 
 | 
 | ||||||
| 	updating = true; | 	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()); | 	max_value->set_value(blend_space->get_max_space()); | ||||||
| 	min_value->set_value(blend_space->get_min_space()); | 	min_value->set_value(blend_space->get_min_space()); | ||||||
| 
 | 
 | ||||||
|  | @ -355,7 +330,33 @@ void AnimationNodeBlendSpace1DEditor::_snap_toggled() { | ||||||
| 	blend_space_draw->update(); | 	blend_space_draw->update(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void AnimationNodeBlendSpace1DEditor::_file_opened(const String &p_file) { | ||||||
|  | 
 | ||||||
|  | 	file_loaded = ResourceLoader::load(p_file); | ||||||
|  | 	if (file_loaded.is_valid()) { | ||||||
|  | 		_add_menu_type(MENU_LOAD_FILE_CONFIRM); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) { | void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) { | ||||||
|  | 	Ref<AnimationRootNode> node; | ||||||
|  | 	if (p_index == MENU_LOAD_FILE) { | ||||||
|  | 
 | ||||||
|  | 		open_file->clear_filters(); | ||||||
|  | 		List<String> filters; | ||||||
|  | 		ResourceLoader::get_recognized_extensions_for_type("AnimationRootNode", &filters); | ||||||
|  | 		for (List<String>::Element *E = filters.front(); E; E = E->next()) { | ||||||
|  | 			open_file->add_filter("*." + E->get()); | ||||||
|  | 		} | ||||||
|  | 		open_file->popup_centered_ratio(); | ||||||
|  | 		return; | ||||||
|  | 	} else if (p_index == MENU_LOAD_FILE_CONFIRM) { | ||||||
|  | 		node = file_loaded; | ||||||
|  | 		file_loaded.unref(); | ||||||
|  | 	} else if (p_index == MENU_PASTE) { | ||||||
|  | 
 | ||||||
|  | 		node = EditorSettings::get_singleton()->get_resource_clipboard(); | ||||||
|  | 	} else { | ||||||
| 		String type = menu->get_item_metadata(p_index); | 		String type = menu->get_item_metadata(p_index); | ||||||
| 
 | 
 | ||||||
| 		Object *obj = ClassDB::instance(type); | 		Object *obj = ClassDB::instance(type); | ||||||
|  | @ -363,7 +364,13 @@ void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) { | ||||||
| 		AnimationNode *an = Object::cast_to<AnimationNode>(obj); | 		AnimationNode *an = Object::cast_to<AnimationNode>(obj); | ||||||
| 		ERR_FAIL_COND(!an); | 		ERR_FAIL_COND(!an); | ||||||
| 
 | 
 | ||||||
| 	Ref<AnimationNode> node(an); | 		node = Ref<AnimationNode>(an); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!node.is_valid()) { | ||||||
|  | 		EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only root nodes are allowed.")); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	updating = true; | 	updating = true; | ||||||
| 	undo_redo->create_action("Add Node Point"); | 	undo_redo->create_action("Add Node Point"); | ||||||
|  | @ -438,7 +445,7 @@ void AnimationNodeBlendSpace1DEditor::_update_tool_erase() { | ||||||
| 	if (point_valid) { | 	if (point_valid) { | ||||||
| 		Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point); | 		Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point); | ||||||
| 
 | 
 | ||||||
| 		if (EditorNode::get_singleton()->item_has_editor(an.ptr())) { | 		if (AnimationTreeEditor::get_singleton()->can_edit(an)) { | ||||||
| 			open_editor->show(); | 			open_editor->show(); | ||||||
| 		} else { | 		} else { | ||||||
| 			open_editor->hide(); | 			open_editor->hide(); | ||||||
|  | @ -490,17 +497,11 @@ void AnimationNodeBlendSpace1DEditor::_open_editor() { | ||||||
| 	if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) { | 	if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) { | ||||||
| 		Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point); | 		Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point); | ||||||
| 		ERR_FAIL_COND(an.is_null()); | 		ERR_FAIL_COND(an.is_null()); | ||||||
| 		EditorNode::get_singleton()->edit_item(an.ptr()); | 		AnimationTreeEditor::get_singleton()->enter_editor(itos(selected_point)); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendSpace1DEditor::_goto_parent() { |  | ||||||
| 	EditorNode::get_singleton()->edit_item(blend_space->get_parent().ptr()); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendSpace1DEditor::_removed_from_graph() { |  | ||||||
| 	EditorNode::get_singleton()->edit_item(NULL); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendSpace1DEditor::_notification(int p_what) { | void AnimationNodeBlendSpace1DEditor::_notification(int p_what) { | ||||||
| 	if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { | 	if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { | ||||||
|  | @ -513,18 +514,16 @@ void AnimationNodeBlendSpace1DEditor::_notification(int p_what) { | ||||||
| 		tool_erase->set_icon(get_icon("Remove", "EditorIcons")); | 		tool_erase->set_icon(get_icon("Remove", "EditorIcons")); | ||||||
| 		snap->set_icon(get_icon("SnapGrid", "EditorIcons")); | 		snap->set_icon(get_icon("SnapGrid", "EditorIcons")); | ||||||
| 		open_editor->set_icon(get_icon("Edit", "EditorIcons")); | 		open_editor->set_icon(get_icon("Edit", "EditorIcons")); | ||||||
| 		goto_parent->set_icon(get_icon("MoveUp", "EditorIcons")); | 
 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (p_what == NOTIFICATION_PROCESS) { | 	if (p_what == NOTIFICATION_PROCESS) { | ||||||
| 		String error; | 		String error; | ||||||
| 
 | 
 | ||||||
| 		if (!blend_space->get_tree()) { | 		if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) { | ||||||
| 			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."); | 			error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails."); | ||||||
| 		} else if (blend_space->get_tree()->is_state_invalid()) { | 		} else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) { | ||||||
| 			error = blend_space->get_tree()->get_invalid_state_reason(); | 			error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason(); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (error != error_label->get_text()) { | 		if (error != error_label->get_text()) { | ||||||
|  | @ -536,6 +535,10 @@ void AnimationNodeBlendSpace1DEditor::_notification(int p_what) { | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	if (p_what==NOTIFICATION_VISIBILITY_CHANGED) { | ||||||
|  | 		set_process(is_visible_in_tree()); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendSpace1DEditor::_bind_methods() { | void AnimationNodeBlendSpace1DEditor::_bind_methods() { | ||||||
|  | @ -556,28 +559,26 @@ void AnimationNodeBlendSpace1DEditor::_bind_methods() { | ||||||
| 	ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace1DEditor::_update_edited_point_pos); | 	ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace1DEditor::_update_edited_point_pos); | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method("_open_editor", &AnimationNodeBlendSpace1DEditor::_open_editor); | 	ClassDB::bind_method("_open_editor", &AnimationNodeBlendSpace1DEditor::_open_editor); | ||||||
| 	ClassDB::bind_method("_goto_parent", &AnimationNodeBlendSpace1DEditor::_goto_parent); |  | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendSpace1DEditor::_removed_from_graph); | 	ClassDB::bind_method("_file_opened", &AnimationNodeBlendSpace1DEditor::_file_opened); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendSpace1DEditor::edit(AnimationNodeBlendSpace1D *p_blend_space) { | bool AnimationNodeBlendSpace1DEditor::can_edit(const Ref<AnimationNode> &p_node) { | ||||||
| 
 | 
 | ||||||
| 	if (blend_space.is_valid()) { | 	Ref<AnimationNodeBlendSpace1D> b1d=p_node; | ||||||
| 		blend_space->disconnect("removed_from_graph", this, "_removed_from_graph"); | 	return b1d.is_valid(); | ||||||
| 	} | } | ||||||
| 
 | 
 | ||||||
| 	if (p_blend_space) { | void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) { | ||||||
| 		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"); |  | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | 	blend_space=p_node; | ||||||
|  | 
 | ||||||
|  | 	if (!blend_space.is_null()) { | ||||||
| 		_update_space(); | 		_update_space(); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -594,14 +595,6 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { | ||||||
| 	Ref<ButtonGroup> bg; | 	Ref<ButtonGroup> bg; | ||||||
| 	bg.instance(); | 	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 = memnew(ToolButton); | ||||||
| 	tool_blend->set_toggle_mode(true); | 	tool_blend->set_toggle_mode(true); | ||||||
|  | @ -726,13 +719,20 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { | ||||||
| 
 | 
 | ||||||
| 	menu = memnew(PopupMenu); | 	menu = memnew(PopupMenu); | ||||||
| 	add_child(menu); | 	add_child(menu); | ||||||
| 	menu->connect("index_pressed", this, "_add_menu_type"); | 	menu->connect("id_pressed", this, "_add_menu_type"); | ||||||
| 
 | 
 | ||||||
| 	animations_menu = memnew(PopupMenu); | 	animations_menu = memnew(PopupMenu); | ||||||
| 	menu->add_child(animations_menu); | 	menu->add_child(animations_menu); | ||||||
| 	animations_menu->set_name("animations"); | 	animations_menu->set_name("animations"); | ||||||
| 	animations_menu->connect("index_pressed", this, "_add_animation_type"); | 	animations_menu->connect("index_pressed", this, "_add_animation_type"); | ||||||
| 
 | 
 | ||||||
|  | 	open_file = memnew(EditorFileDialog); | ||||||
|  | 	add_child(open_file); | ||||||
|  | 	open_file->set_title(TTR("Open Animation Node")); | ||||||
|  | 	open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE); | ||||||
|  | 	open_file->connect("file_selected", this, "_file_opened"); | ||||||
|  | 	undo_redo = EditorNode::get_singleton()->get_undo_redo(); | ||||||
|  | 
 | ||||||
| 	selected_point = -1; | 	selected_point = -1; | ||||||
| 	dragging_selected = false; | 	dragging_selected = false; | ||||||
| 	dragging_selected_attempt = false; | 	dragging_selected_attempt = false; | ||||||
|  |  | ||||||
|  | @ -9,10 +9,11 @@ | ||||||
| #include "scene/gui/graph_edit.h" | #include "scene/gui/graph_edit.h" | ||||||
| #include "scene/gui/popup.h" | #include "scene/gui/popup.h" | ||||||
| #include "scene/gui/tree.h" | #include "scene/gui/tree.h" | ||||||
|  | #include "editor/plugins/animation_tree_editor_plugin.h" | ||||||
| 
 | 
 | ||||||
| class AnimationNodeBlendSpace1DEditor : public VBoxContainer { | class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin { | ||||||
| 
 | 
 | ||||||
| 	GDCLASS(AnimationNodeBlendSpace1DEditor, VBoxContainer) | 	GDCLASS(AnimationNodeBlendSpace1DEditor, AnimationTreeNodeEditorPlugin) | ||||||
| 
 | 
 | ||||||
| 	Ref<AnimationNodeBlendSpace1D> blend_space; | 	Ref<AnimationNodeBlendSpace1D> blend_space; | ||||||
| 
 | 
 | ||||||
|  | @ -81,7 +82,17 @@ class AnimationNodeBlendSpace1DEditor : public VBoxContainer { | ||||||
| 
 | 
 | ||||||
| 	void _goto_parent(); | 	void _goto_parent(); | ||||||
| 
 | 
 | ||||||
| 	void _removed_from_graph(); | 	EditorFileDialog *open_file; | ||||||
|  | 	Ref<AnimationNode> file_loaded; | ||||||
|  | 	void _file_opened(const String &p_file); | ||||||
|  | 
 | ||||||
|  | 	enum { | ||||||
|  | 		MENU_LOAD_FILE = 1000, | ||||||
|  | 		MENU_PASTE = 1001, | ||||||
|  | 		MENU_LOAD_FILE_CONFIRM = 1002 | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	StringName get_blend_position_path() const; | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
| 	void _notification(int p_what); | 	void _notification(int p_what); | ||||||
|  | @ -89,29 +100,9 @@ protected: | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 	static AnimationNodeBlendSpace1DEditor *get_singleton() { return singleton; } | 	static AnimationNodeBlendSpace1DEditor *get_singleton() { return singleton; } | ||||||
| 	void edit(AnimationNodeBlendSpace1D *p_blend_space); | 	virtual bool can_edit(const Ref<AnimationNode> &p_node); | ||||||
|  | 	virtual void edit(const Ref<AnimationNode> &p_node); | ||||||
| 	AnimationNodeBlendSpace1DEditor(); | 	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
 | #endif // ANIMATION_BLEND_SPACE_1D_EDITOR_H
 | ||||||
|  |  | ||||||
|  | @ -11,27 +11,26 @@ | ||||||
| #include "scene/gui/panel.h" | #include "scene/gui/panel.h" | ||||||
| #include "scene/main/viewport.h" | #include "scene/main/viewport.h" | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendSpace2DEditor::edit(AnimationNodeBlendSpace2D *p_blend_space) { | bool AnimationNodeBlendSpace2DEditor::can_edit(const Ref<AnimationNode> &p_node) { | ||||||
| 
 | 
 | ||||||
| 	if (blend_space.is_valid()) { | 	Ref<AnimationNodeBlendSpace2D> bs2d=p_node; | ||||||
| 		blend_space->disconnect("removed_from_graph", this, "_removed_from_graph"); | 	return bs2d.is_valid(); | ||||||
| 	} | } | ||||||
| 
 | 
 | ||||||
| 	if (p_blend_space) { | void AnimationNodeBlendSpace2DEditor::edit(const Ref<AnimationNode> &p_node) { | ||||||
| 		blend_space = Ref<AnimationNodeBlendSpace2D>(p_blend_space); |  | ||||||
| 	} else { |  | ||||||
| 		blend_space.unref(); |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	if (blend_space.is_null()) { | 	blend_space = p_node; | ||||||
| 		hide(); |  | ||||||
| 	} else { |  | ||||||
| 		blend_space->connect("removed_from_graph", this, "_removed_from_graph"); |  | ||||||
| 
 | 
 | ||||||
|  | 	if (!blend_space.is_null()) { | ||||||
| 		_update_space(); | 		_update_space(); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | StringName AnimationNodeBlendSpace2DEditor::get_blend_position_path() const { | ||||||
|  | 	StringName path = AnimationTreeEditor::get_singleton()->get_base_path()+"blend_position"; | ||||||
|  | 	return path; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) { | void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) { | ||||||
| 
 | 
 | ||||||
| 	Ref<InputEventKey> k = p_event; | 	Ref<InputEventKey> k = p_event; | ||||||
|  | @ -54,7 +53,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven | ||||||
| 		ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); | 		ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); | ||||||
| 		menu->add_submenu_item(TTR("Add Animation"), "animations"); | 		menu->add_submenu_item(TTR("Add Animation"), "animations"); | ||||||
| 
 | 
 | ||||||
| 		AnimationTree *gp = blend_space->get_tree(); | 		AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree(); | ||||||
| 		ERR_FAIL_COND(!gp); | 		ERR_FAIL_COND(!gp); | ||||||
| 		if (gp && gp->has_node(gp->get_animation_player())) { | 		if (gp && gp->has_node(gp->get_animation_player())) { | ||||||
| 			AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player())); | 			AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player())); | ||||||
|  | @ -74,10 +73,19 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven | ||||||
| 			if (name == "Animation") | 			if (name == "Animation") | ||||||
| 				continue; // nope
 | 				continue; // nope
 | ||||||
| 			int idx = menu->get_item_count(); | 			int idx = menu->get_item_count(); | ||||||
| 			menu->add_item(vformat("Add %s", name)); | 			menu->add_item(vformat("Add %s", name),idx); | ||||||
| 			menu->set_item_metadata(idx, E->get()); | 			menu->set_item_metadata(idx, E->get()); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard(); | ||||||
|  | 		if (clipb.is_valid()) { | ||||||
|  | 			menu->add_separator(); | ||||||
|  | 			menu->add_item(TTR("Paste"), MENU_PASTE); | ||||||
|  | 		} | ||||||
|  | 		menu->add_separator(); | ||||||
|  | 		menu->add_item(TTR("Load.."), MENU_LOAD_FILE); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 		menu->set_global_position(blend_space_draw->get_global_transform().xform(mb->get_position())); | 		menu->set_global_position(blend_space_draw->get_global_transform().xform(mb->get_position())); | ||||||
| 		menu->popup(); | 		menu->popup(); | ||||||
| 		add_point_pos = (mb->get_position() / blend_space_draw->get_size()); | 		add_point_pos = (mb->get_position() / blend_space_draw->get_size()); | ||||||
|  | @ -203,7 +211,8 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven | ||||||
| 		blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); | 		blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); | ||||||
| 		blend_pos += blend_space->get_min_space(); | 		blend_pos += blend_space->get_min_space(); | ||||||
| 
 | 
 | ||||||
| 		blend_space->set_blend_position(blend_pos); | 		AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(),blend_pos); | ||||||
|  | 
 | ||||||
| 		blend_space_draw->update(); | 		blend_space_draw->update(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -237,13 +246,40 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven | ||||||
| 		blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); | 		blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); | ||||||
| 		blend_pos += blend_space->get_min_space(); | 		blend_pos += blend_space->get_min_space(); | ||||||
| 
 | 
 | ||||||
| 		blend_space->set_blend_position(blend_pos); | 		AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(),blend_pos); | ||||||
|  | 
 | ||||||
| 		blend_space_draw->update(); | 		blend_space_draw->update(); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void AnimationNodeBlendSpace2DEditor::_file_opened(const String &p_file) { | ||||||
|  | 
 | ||||||
|  | 	file_loaded = ResourceLoader::load(p_file); | ||||||
|  | 	if (file_loaded.is_valid()) { | ||||||
|  | 		_add_menu_type(MENU_LOAD_FILE_CONFIRM); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) { | void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) { | ||||||
| 
 | 
 | ||||||
|  | 	Ref<AnimationRootNode> node; | ||||||
|  | 	if (p_index == MENU_LOAD_FILE) { | ||||||
|  | 
 | ||||||
|  | 		open_file->clear_filters(); | ||||||
|  | 		List<String> filters; | ||||||
|  | 		ResourceLoader::get_recognized_extensions_for_type("AnimationRootNode", &filters); | ||||||
|  | 		for (List<String>::Element *E = filters.front(); E; E = E->next()) { | ||||||
|  | 			open_file->add_filter("*." + E->get()); | ||||||
|  | 		} | ||||||
|  | 		open_file->popup_centered_ratio(); | ||||||
|  | 		return; | ||||||
|  | 	} else if (p_index == MENU_LOAD_FILE_CONFIRM) { | ||||||
|  | 		node = file_loaded; | ||||||
|  | 		file_loaded.unref(); | ||||||
|  | 	} else if (p_index == MENU_PASTE) { | ||||||
|  | 
 | ||||||
|  | 		node = EditorSettings::get_singleton()->get_resource_clipboard(); | ||||||
|  | 	} else { | ||||||
| 		String type = menu->get_item_metadata(p_index); | 		String type = menu->get_item_metadata(p_index); | ||||||
| 
 | 
 | ||||||
| 		Object *obj = ClassDB::instance(type); | 		Object *obj = ClassDB::instance(type); | ||||||
|  | @ -251,7 +287,13 @@ void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) { | ||||||
| 		AnimationNode *an = Object::cast_to<AnimationNode>(obj); | 		AnimationNode *an = Object::cast_to<AnimationNode>(obj); | ||||||
| 		ERR_FAIL_COND(!an); | 		ERR_FAIL_COND(!an); | ||||||
| 
 | 
 | ||||||
| 	Ref<AnimationNode> node(an); | 		node = Ref<AnimationNode>(an); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!node.is_valid()) { | ||||||
|  | 		EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only root nodes are allowed.")); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	updating = true; | 	updating = true; | ||||||
| 	undo_redo->create_action("Add Node Point"); | 	undo_redo->create_action("Add Node Point"); | ||||||
|  | @ -288,7 +330,7 @@ void AnimationNodeBlendSpace2DEditor::_update_tool_erase() { | ||||||
| 	tool_erase->set_disabled(!(selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) && !(selected_triangle >= 0 && selected_triangle < blend_space->get_triangle_count())); | 	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()) { | 	if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) { | ||||||
| 		Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point); | 		Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point); | ||||||
| 		if (EditorNode::get_singleton()->item_has_editor(an.ptr())) { | 		if (AnimationTreeEditor::get_singleton()->can_edit(an)) { | ||||||
| 			open_editor->show(); | 			open_editor->show(); | ||||||
| 		} else { | 		} else { | ||||||
| 			open_editor->hide(); | 			open_editor->hide(); | ||||||
|  | @ -490,13 +532,15 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { | ||||||
| 			color.a *= 0.5; | 			color.a *= 0.5; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		Vector2 point = blend_space->get_blend_position(); | 		Vector2 blend_pos = AnimationTreeEditor::get_singleton()->get_tree()->get(get_blend_position_path()); | ||||||
|  | 		Vector2 point = blend_pos; | ||||||
|  | 
 | ||||||
| 		point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); | 		point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); | ||||||
| 		point *= s; | 		point *= s; | ||||||
| 		point.y = s.height - point.y; | 		point.y = s.height - point.y; | ||||||
| 
 | 
 | ||||||
| 		if (blend_space->get_triangle_count()) { | 		if (blend_space->get_triangle_count()) { | ||||||
| 			Vector2 closest = blend_space->get_closest_point(blend_space->get_blend_position()); | 			Vector2 closest = blend_space->get_closest_point(blend_pos); | ||||||
| 			closest = (closest - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); | 			closest = (closest - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); | ||||||
| 			closest *= s; | 			closest *= s; | ||||||
| 			closest.y = s.height - closest.y; | 			closest.y = s.height - closest.y; | ||||||
|  | @ -527,12 +571,6 @@ void AnimationNodeBlendSpace2DEditor::_update_space() { | ||||||
| 
 | 
 | ||||||
| 	updating = true; | 	updating = true; | ||||||
| 
 | 
 | ||||||
| 	if (blend_space->get_parent().is_valid()) { |  | ||||||
| 		goto_parent_hb->show(); |  | ||||||
| 	} else { |  | ||||||
| 		goto_parent_hb->hide(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (blend_space->get_auto_triangles()) { | 	if (blend_space->get_auto_triangles()) { | ||||||
| 		tool_triangle->hide(); | 		tool_triangle->hide(); | ||||||
| 	} else { | 	} else { | ||||||
|  | @ -685,7 +723,6 @@ void AnimationNodeBlendSpace2DEditor::_notification(int p_what) { | ||||||
| 		tool_erase->set_icon(get_icon("Remove", "EditorIcons")); | 		tool_erase->set_icon(get_icon("Remove", "EditorIcons")); | ||||||
| 		snap->set_icon(get_icon("SnapGrid", "EditorIcons")); | 		snap->set_icon(get_icon("SnapGrid", "EditorIcons")); | ||||||
| 		open_editor->set_icon(get_icon("Edit", "EditorIcons")); | 		open_editor->set_icon(get_icon("Edit", "EditorIcons")); | ||||||
| 		goto_parent->set_icon(get_icon("MoveUp", "EditorIcons")); |  | ||||||
| 		auto_triangles->set_icon(get_icon("AutoTriangle", "EditorIcons")); | 		auto_triangles->set_icon(get_icon("AutoTriangle", "EditorIcons")); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -693,12 +730,12 @@ void AnimationNodeBlendSpace2DEditor::_notification(int p_what) { | ||||||
| 
 | 
 | ||||||
| 		String error; | 		String error; | ||||||
| 
 | 
 | ||||||
| 		if (!blend_space->get_tree()) { | 		if (!AnimationTreeEditor::get_singleton()->get_tree()) { | ||||||
| 			error = TTR("BlendSpace2D does not belong to an AnimationTree node."); | 			error = TTR("BlendSpace2D does not belong to an AnimationTree node."); | ||||||
| 		} else if (!blend_space->get_tree()->is_active()) { | 		} else if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) { | ||||||
| 			error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails."); | 			error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails."); | ||||||
| 		} else if (blend_space->get_tree()->is_state_invalid()) { | 		} else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) { | ||||||
| 			error = blend_space->get_tree()->get_invalid_state_reason(); | 			error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason(); | ||||||
| 		} else if (blend_space->get_triangle_count() == 0) { | 		} else if (blend_space->get_triangle_count() == 0) { | ||||||
| 			error = TTR("No triangles exist, so no blending can take place."); | 			error = TTR("No triangles exist, so no blending can take place."); | ||||||
| 		} | 		} | ||||||
|  | @ -712,22 +749,22 @@ void AnimationNodeBlendSpace2DEditor::_notification(int p_what) { | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	if (p_what==NOTIFICATION_VISIBILITY_CHANGED) { | ||||||
|  | 		set_process(is_visible_in_tree()); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| void AnimationNodeBlendSpace2DEditor::_open_editor() { | void AnimationNodeBlendSpace2DEditor::_open_editor() { | ||||||
| 
 | 
 | ||||||
| 	if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) { | 	if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) { | ||||||
| 		Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point); | 		Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point); | ||||||
| 		ERR_FAIL_COND(!an.is_valid()); | 		ERR_FAIL_COND(an.is_null()); | ||||||
| 		EditorNode::get_singleton()->edit_item(an.ptr()); | 		AnimationTreeEditor::get_singleton()->enter_editor(itos(selected_point)); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendSpace2DEditor::_goto_parent() { |  | ||||||
| 
 |  | ||||||
| 	EditorNode::get_singleton()->edit_item(blend_space->get_parent().ptr()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void AnimationNodeBlendSpace2DEditor::_removed_from_graph() { | void AnimationNodeBlendSpace2DEditor::_removed_from_graph() { | ||||||
| 	EditorNode::get_singleton()->edit_item(NULL); | 	EditorNode::get_singleton()->edit_item(NULL); | ||||||
| } | } | ||||||
|  | @ -761,11 +798,13 @@ void AnimationNodeBlendSpace2DEditor::_bind_methods() { | ||||||
| 	ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace2DEditor::_update_edited_point_pos); | 	ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace2DEditor::_update_edited_point_pos); | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method("_open_editor", &AnimationNodeBlendSpace2DEditor::_open_editor); | 	ClassDB::bind_method("_open_editor", &AnimationNodeBlendSpace2DEditor::_open_editor); | ||||||
| 	ClassDB::bind_method("_goto_parent", &AnimationNodeBlendSpace2DEditor::_goto_parent); |  | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendSpace2DEditor::_removed_from_graph); | 	ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendSpace2DEditor::_removed_from_graph); | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method("_auto_triangles_toggled", &AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled); | 	ClassDB::bind_method("_auto_triangles_toggled", &AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled); | ||||||
|  | 
 | ||||||
|  | 	ClassDB::bind_method("_file_opened", &AnimationNodeBlendSpace2DEditor::_file_opened); | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AnimationNodeBlendSpace2DEditor *AnimationNodeBlendSpace2DEditor::singleton = NULL; | AnimationNodeBlendSpace2DEditor *AnimationNodeBlendSpace2DEditor::singleton = NULL; | ||||||
|  | @ -781,14 +820,6 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { | ||||||
| 	Ref<ButtonGroup> bg; | 	Ref<ButtonGroup> bg; | ||||||
| 	bg.instance(); | 	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 = memnew(ToolButton); | ||||||
| 	tool_blend->set_toggle_mode(true); | 	tool_blend->set_toggle_mode(true); | ||||||
| 	tool_blend->set_button_group(bg); | 	tool_blend->set_button_group(bg); | ||||||
|  | @ -968,13 +999,20 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { | ||||||
| 
 | 
 | ||||||
| 	menu = memnew(PopupMenu); | 	menu = memnew(PopupMenu); | ||||||
| 	add_child(menu); | 	add_child(menu); | ||||||
| 	menu->connect("index_pressed", this, "_add_menu_type"); | 	menu->connect("id_pressed", this, "_add_menu_type"); | ||||||
| 
 | 
 | ||||||
| 	animations_menu = memnew(PopupMenu); | 	animations_menu = memnew(PopupMenu); | ||||||
| 	menu->add_child(animations_menu); | 	menu->add_child(animations_menu); | ||||||
| 	animations_menu->set_name("animations"); | 	animations_menu->set_name("animations"); | ||||||
| 	animations_menu->connect("index_pressed", this, "_add_animation_type"); | 	animations_menu->connect("index_pressed", this, "_add_animation_type"); | ||||||
| 
 | 
 | ||||||
|  | 	open_file = memnew(EditorFileDialog); | ||||||
|  | 	add_child(open_file); | ||||||
|  | 	open_file->set_title(TTR("Open Animation Node")); | ||||||
|  | 	open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE); | ||||||
|  | 	open_file->connect("file_selected", this, "_file_opened"); | ||||||
|  | 	undo_redo = EditorNode::get_singleton()->get_undo_redo(); | ||||||
|  | 
 | ||||||
| 	selected_point = -1; | 	selected_point = -1; | ||||||
| 	selected_triangle = -1; | 	selected_triangle = -1; | ||||||
| 
 | 
 | ||||||
|  | @ -982,42 +1020,3 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { | ||||||
| 	dragging_selected_attempt = false; | 	dragging_selected_attempt = false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendSpace2DEditorPlugin::edit(Object *p_object) { |  | ||||||
| 
 |  | ||||||
| 	anim_tree_editor->edit(Object::cast_to<AnimationNodeBlendSpace2D>(p_object)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool AnimationNodeBlendSpace2DEditorPlugin::handles(Object *p_object) const { |  | ||||||
| 
 |  | ||||||
| 	return p_object->is_class("AnimationNodeBlendSpace2D"); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void AnimationNodeBlendSpace2DEditorPlugin::make_visible(bool p_visible) { |  | ||||||
| 
 |  | ||||||
| 	if (p_visible) { |  | ||||||
| 		//editor->hide_animation_player_editors();
 |  | ||||||
| 		//editor->animation_panel_make_visible(true);
 |  | ||||||
| 		button->show(); |  | ||||||
| 		editor->make_bottom_panel_item_visible(anim_tree_editor); |  | ||||||
| 		anim_tree_editor->set_process(true); |  | ||||||
| 	} else { |  | ||||||
| 
 |  | ||||||
| 		if (anim_tree_editor->is_visible_in_tree()) |  | ||||||
| 			editor->hide_bottom_panel(); |  | ||||||
| 		button->hide(); |  | ||||||
| 		anim_tree_editor->set_process(false); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| AnimationNodeBlendSpace2DEditorPlugin::AnimationNodeBlendSpace2DEditorPlugin(EditorNode *p_node) { |  | ||||||
| 
 |  | ||||||
| 	editor = p_node; |  | ||||||
| 	anim_tree_editor = memnew(AnimationNodeBlendSpace2DEditor); |  | ||||||
| 	anim_tree_editor->set_custom_minimum_size(Size2(0, 300)); |  | ||||||
| 
 |  | ||||||
| 	button = editor->add_bottom_panel_item(TTR("BlendSpace2D"), anim_tree_editor); |  | ||||||
| 	button->hide(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| AnimationNodeBlendSpace2DEditorPlugin::~AnimationNodeBlendSpace2DEditorPlugin() { |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -9,18 +9,17 @@ | ||||||
| #include "scene/gui/graph_edit.h" | #include "scene/gui/graph_edit.h" | ||||||
| #include "scene/gui/popup.h" | #include "scene/gui/popup.h" | ||||||
| #include "scene/gui/tree.h" | #include "scene/gui/tree.h" | ||||||
|  | #include "editor/plugins/animation_tree_editor_plugin.h" | ||||||
| /**
 | /**
 | ||||||
| 	@author Juan Linietsky <reduzio@gmail.com> | 	@author Juan Linietsky <reduzio@gmail.com> | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| class AnimationNodeBlendSpace2DEditor : public VBoxContainer { | class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin { | ||||||
| 
 | 
 | ||||||
| 	GDCLASS(AnimationNodeBlendSpace2DEditor, VBoxContainer); | 	GDCLASS(AnimationNodeBlendSpace2DEditor, AnimationTreeNodeEditorPlugin); | ||||||
| 
 | 
 | ||||||
| 	Ref<AnimationNodeBlendSpace2D> blend_space; | 	Ref<AnimationNodeBlendSpace2D> blend_space; | ||||||
| 
 | 
 | ||||||
| 	HBoxContainer *goto_parent_hb; |  | ||||||
| 	ToolButton *goto_parent; |  | ||||||
| 
 | 
 | ||||||
| 	PanelContainer *panel; | 	PanelContainer *panel; | ||||||
| 	ToolButton *tool_blend; | 	ToolButton *tool_blend; | ||||||
|  | @ -93,38 +92,32 @@ class AnimationNodeBlendSpace2DEditor : public VBoxContainer { | ||||||
| 	void _edit_point_pos(double); | 	void _edit_point_pos(double); | ||||||
| 	void _open_editor(); | 	void _open_editor(); | ||||||
| 
 | 
 | ||||||
| 	void _goto_parent(); |  | ||||||
| 
 |  | ||||||
| 	void _removed_from_graph(); | 	void _removed_from_graph(); | ||||||
| 
 | 
 | ||||||
| 	void _auto_triangles_toggled(); | 	void _auto_triangles_toggled(); | ||||||
| 
 | 
 | ||||||
|  | 	StringName get_blend_position_path() const; | ||||||
|  | 
 | ||||||
|  | 	EditorFileDialog *open_file; | ||||||
|  | 	Ref<AnimationNode> file_loaded; | ||||||
|  | 	void _file_opened(const String &p_file); | ||||||
|  | 
 | ||||||
|  | 	enum { | ||||||
|  | 		MENU_LOAD_FILE = 1000, | ||||||
|  | 		MENU_PASTE = 1001, | ||||||
|  | 		MENU_LOAD_FILE_CONFIRM = 1002 | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
| 	void _notification(int p_what); | 	void _notification(int p_what); | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 	static AnimationNodeBlendSpace2DEditor *get_singleton() { return singleton; } | 	static AnimationNodeBlendSpace2DEditor *get_singleton() { return singleton; } | ||||||
| 	void edit(AnimationNodeBlendSpace2D *p_blend_space); | 	virtual bool can_edit(const Ref<AnimationNode> &p_node); | ||||||
|  | 	virtual void edit(const Ref<AnimationNode> &p_node); | ||||||
| 	AnimationNodeBlendSpace2DEditor(); | 	AnimationNodeBlendSpace2DEditor(); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class AnimationNodeBlendSpace2DEditorPlugin : public EditorPlugin { |  | ||||||
| 
 | 
 | ||||||
| 	GDCLASS(AnimationNodeBlendSpace2DEditorPlugin, EditorPlugin); |  | ||||||
| 
 |  | ||||||
| 	AnimationNodeBlendSpace2DEditor *anim_tree_editor; |  | ||||||
| 	EditorNode *editor; |  | ||||||
| 	Button *button; |  | ||||||
| 
 |  | ||||||
| public: |  | ||||||
| 	virtual String get_name() const { return "BlendSpace2D"; } |  | ||||||
| 	bool has_main_screen() const { return false; } |  | ||||||
| 	virtual void edit(Object *p_object); |  | ||||||
| 	virtual bool handles(Object *p_object) const; |  | ||||||
| 	virtual void make_visible(bool p_visible); |  | ||||||
| 
 |  | ||||||
| 	AnimationNodeBlendSpace2DEditorPlugin(EditorNode *p_node); |  | ||||||
| 	~AnimationNodeBlendSpace2DEditorPlugin(); |  | ||||||
| }; |  | ||||||
| #endif // ANIMATION_BLEND_SPACE_2D_EDITOR_H
 | #endif // ANIMATION_BLEND_SPACE_2D_EDITOR_H
 | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "core/io/resource_loader.h" | #include "core/io/resource_loader.h" | ||||||
| #include "core/project_settings.h" | #include "core/project_settings.h" | ||||||
|  | #include "editor/editor_inspector.h" | ||||||
| #include "os/input.h" | #include "os/input.h" | ||||||
| #include "os/keyboard.h" | #include "os/keyboard.h" | ||||||
| #include "scene/animation/animation_player.h" | #include "scene/animation/animation_player.h" | ||||||
|  | @ -9,27 +10,6 @@ | ||||||
| #include "scene/gui/panel.h" | #include "scene/gui/panel.h" | ||||||
| #include "scene/main/viewport.h" | #include "scene/main/viewport.h" | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendTreeEditor::edit(AnimationNodeBlendTree *p_blend_tree) { |  | ||||||
| 
 |  | ||||||
| 	if (blend_tree.is_valid()) { |  | ||||||
| 		blend_tree->disconnect("removed_from_graph", this, "_removed_from_graph"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (p_blend_tree) { |  | ||||||
| 		blend_tree = Ref<AnimationNodeBlendTree>(p_blend_tree); |  | ||||||
| 	} else { |  | ||||||
| 		blend_tree.unref(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (blend_tree.is_null()) { |  | ||||||
| 		hide(); |  | ||||||
| 	} else { |  | ||||||
| 		blend_tree->connect("removed_from_graph", this, "_removed_from_graph"); |  | ||||||
| 
 |  | ||||||
| 		_update_graph(); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void AnimationNodeBlendTreeEditor::add_custom_type(const String &p_name, const Ref<Script> &p_script) { | void AnimationNodeBlendTreeEditor::add_custom_type(const String &p_name, const Ref<Script> &p_script) { | ||||||
| 
 | 
 | ||||||
| 	for (int i = 0; i < add_options.size(); i++) { | 	for (int i = 0; i < add_options.size(); i++) { | ||||||
|  | @ -58,10 +38,19 @@ void AnimationNodeBlendTreeEditor::remove_custom_type(const Ref<Script> &p_scrip | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendTreeEditor::_update_options_menu() { | void AnimationNodeBlendTreeEditor::_update_options_menu() { | ||||||
| 
 | 
 | ||||||
|  | 	print_line("update options"); | ||||||
| 	add_node->get_popup()->clear(); | 	add_node->get_popup()->clear(); | ||||||
| 	for (int i = 0; i < add_options.size(); i++) { | 	for (int i = 0; i < add_options.size(); i++) { | ||||||
| 		add_node->get_popup()->add_item(add_options[i].name); | 		add_node->get_popup()->add_item(add_options[i].name, i); | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard(); | ||||||
|  | 	if (clipb.is_valid()) { | ||||||
|  | 		add_node->get_popup()->add_separator(); | ||||||
|  | 		add_node->get_popup()->add_item(TTR("Paste"), MENU_PASTE); | ||||||
|  | 	} | ||||||
|  | 	add_node->get_popup()->add_separator(); | ||||||
|  | 	add_node->get_popup()->add_item(TTR("Load.."), MENU_LOAD_FILE); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Size2 AnimationNodeBlendTreeEditor::get_minimum_size() const { | Size2 AnimationNodeBlendTreeEditor::get_minimum_size() const { | ||||||
|  | @ -69,18 +58,28 @@ Size2 AnimationNodeBlendTreeEditor::get_minimum_size() const { | ||||||
| 	return Size2(10, 200); | 	return Size2(10, 200); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_property, const Variant &p_value) { | ||||||
|  | 
 | ||||||
|  | 	AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_tree(); | ||||||
|  | 	updating = true; | ||||||
|  | 	undo_redo->create_action("Parameter Changed: " + String(p_property), UndoRedo::MERGE_ENDS); | ||||||
|  | 	undo_redo->add_do_property(tree, p_property, p_value); | ||||||
|  | 	undo_redo->add_undo_property(tree, p_property, tree->get(p_property)); | ||||||
|  | 	undo_redo->add_do_method(this, "_update_graph"); | ||||||
|  | 	undo_redo->add_undo_method(this, "_update_graph"); | ||||||
|  | 	undo_redo->commit_action(); | ||||||
|  | 	updating = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void AnimationNodeBlendTreeEditor::_update_graph() { | void AnimationNodeBlendTreeEditor::_update_graph() { | ||||||
| 
 | 
 | ||||||
| 	if (updating) | 	if (updating) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
|  | 	visible_properties.clear(); | ||||||
|  | 
 | ||||||
| 	graph->set_scroll_ofs(blend_tree->get_graph_offset() * EDSCALE); | 	graph->set_scroll_ofs(blend_tree->get_graph_offset() * EDSCALE); | ||||||
| 
 | 
 | ||||||
| 	if (blend_tree->get_parent().is_valid()) { |  | ||||||
| 		goto_parent->show(); |  | ||||||
| 	} else { |  | ||||||
| 		goto_parent->hide(); |  | ||||||
| 	} |  | ||||||
| 	graph->clear_connections(); | 	graph->clear_connections(); | ||||||
| 	//erase all nodes
 | 	//erase all nodes
 | ||||||
| 	for (int i = 0; i < graph->get_child_count(); i++) { | 	for (int i = 0; i < graph->get_child_count(); i++) { | ||||||
|  | @ -107,7 +106,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() { | ||||||
| 			agnode->connect("changed", this, "_node_changed", varray(agnode->get_instance_id()), CONNECT_DEFERRED); | 			agnode->connect("changed", this, "_node_changed", varray(agnode->get_instance_id()), CONNECT_DEFERRED); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		node->set_offset(agnode->get_position() * EDSCALE); | 		node->set_offset(blend_tree->get_node_position(E->get()) * EDSCALE); | ||||||
| 
 | 
 | ||||||
| 		node->set_title(agnode->get_caption()); | 		node->set_title(agnode->get_caption()); | ||||||
| 		node->set_name(E->get()); | 		node->set_name(E->get()); | ||||||
|  | @ -133,9 +132,28 @@ void AnimationNodeBlendTreeEditor::_update_graph() { | ||||||
| 			node->set_slot(base + i, true, 0, get_color("font_color", "Label"), false, 0, Color()); | 			node->set_slot(base + i, true, 0, get_color("font_color", "Label"), false, 0, Color()); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		node->connect("dragged", this, "_node_dragged", varray(agnode)); | 		List<PropertyInfo> pinfo; | ||||||
|  | 		agnode->get_parameter_list(&pinfo); | ||||||
|  | 		for (List<PropertyInfo>::Element *F = pinfo.front(); F; F = F->next()) { | ||||||
| 
 | 
 | ||||||
| 		if (EditorNode::get_singleton()->item_has_editor(agnode.ptr())) { | 			if (!(F->get().usage & PROPERTY_USAGE_EDITOR)) { | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			String base_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E->get()) + "/" + F->get().name; | ||||||
|  | 			EditorProperty *prop = EditorInspector::instantiate_property_editor(AnimationTreeEditor::get_singleton()->get_tree(), F->get().type, base_path, F->get().hint, F->get().hint_string, F->get().usage); | ||||||
|  | 			if (prop) { | ||||||
|  | 				prop->set_object_and_property(AnimationTreeEditor::get_singleton()->get_tree(), base_path); | ||||||
|  | 				prop->update_property(); | ||||||
|  | 				prop->set_name_split_ratio(0); | ||||||
|  | 				prop->connect("property_changed", this, "_property_changed"); | ||||||
|  | 				node->add_child(prop); | ||||||
|  | 				visible_properties.push_back(prop); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		node->connect("dragged", this, "_node_dragged", varray(E->get())); | ||||||
|  | 
 | ||||||
|  | 		if (AnimationTreeEditor::get_singleton()->can_edit(agnode)) { | ||||||
| 			node->add_child(memnew(HSeparator)); | 			node->add_child(memnew(HSeparator)); | ||||||
| 			Button *open_in_editor = memnew(Button); | 			Button *open_in_editor = memnew(Button); | ||||||
| 			open_in_editor->set_text(TTR("Open Editor")); | 			open_in_editor->set_text(TTR("Open Editor")); | ||||||
|  | @ -169,7 +187,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() { | ||||||
| 
 | 
 | ||||||
| 			ProgressBar *pb = memnew(ProgressBar); | 			ProgressBar *pb = memnew(ProgressBar); | ||||||
| 
 | 
 | ||||||
| 			AnimationTree *player = anim->get_tree(); | 			AnimationTree *player = AnimationTreeEditor::get_singleton()->get_tree(); | ||||||
| 			if (player->has_node(player->get_animation_player())) { | 			if (player->has_node(player->get_animation_player())) { | ||||||
| 				AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(player->get_node(player->get_animation_player())); | 				AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(player->get_node(player->get_animation_player())); | ||||||
| 				if (ap) { | 				if (ap) { | ||||||
|  | @ -194,6 +212,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() { | ||||||
| 			mb->get_popup()->connect("index_pressed", this, "_anim_selected", varray(options, E->get()), CONNECT_DEFERRED); | 			mb->get_popup()->connect("index_pressed", this, "_anim_selected", varray(options, E->get()), CONNECT_DEFERRED); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		/* should be no longer necesary, as the boolean works
 | ||||||
| 		Ref<AnimationNodeOneShot> oneshot = agnode; | 		Ref<AnimationNodeOneShot> oneshot = agnode; | ||||||
| 		if (oneshot.is_valid()) { | 		if (oneshot.is_valid()) { | ||||||
| 
 | 
 | ||||||
|  | @ -209,7 +228,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() { | ||||||
| 			play_stop->add_child(stop); | 			play_stop->add_child(stop); | ||||||
| 			play_stop->add_spacer(); | 			play_stop->add_spacer(); | ||||||
| 			node->add_child(play_stop); | 			node->add_child(play_stop); | ||||||
| 		} | 		} */ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	List<AnimationNodeBlendTree::NodeConnection> connections; | 	List<AnimationNodeBlendTree::NodeConnection> connections; | ||||||
|  | @ -225,16 +244,44 @@ void AnimationNodeBlendTreeEditor::_update_graph() { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendTreeEditor::_add_node(int p_idx) { | void AnimationNodeBlendTreeEditor::_file_opened(const String &p_file) { | ||||||
| 
 | 
 | ||||||
| 	ERR_FAIL_INDEX(p_idx, add_options.size()); | 	file_loaded = ResourceLoader::load(p_file); | ||||||
|  | 	if (file_loaded.is_valid()) { | ||||||
|  | 		_add_node(MENU_LOAD_FILE_CONFIRM); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AnimationNodeBlendTreeEditor::_add_node(int p_idx) { | ||||||
| 
 | 
 | ||||||
| 	Ref<AnimationNode> anode; | 	Ref<AnimationNode> anode; | ||||||
| 
 | 
 | ||||||
| 	if (add_options[p_idx].type != String()) { | 	String base_name; | ||||||
|  | 
 | ||||||
|  | 	if (p_idx == MENU_LOAD_FILE) { | ||||||
|  | 
 | ||||||
|  | 		open_file->clear_filters(); | ||||||
|  | 		List<String> filters; | ||||||
|  | 		ResourceLoader::get_recognized_extensions_for_type("AnimationNode", &filters); | ||||||
|  | 		for (List<String>::Element *E = filters.front(); E; E = E->next()) { | ||||||
|  | 			open_file->add_filter("*." + E->get()); | ||||||
|  | 		} | ||||||
|  | 		open_file->popup_centered_ratio(); | ||||||
|  | 		return; | ||||||
|  | 	} else if (p_idx == MENU_LOAD_FILE_CONFIRM) { | ||||||
|  | 		anode = file_loaded; | ||||||
|  | 		file_loaded.unref(); | ||||||
|  | 		base_name = anode->get_class(); | ||||||
|  | 	} else if (p_idx == MENU_PASTE) { | ||||||
|  | 
 | ||||||
|  | 		anode = EditorSettings::get_singleton()->get_resource_clipboard(); | ||||||
|  | 		ERR_FAIL_COND(!anode.is_valid()); | ||||||
|  | 		base_name = anode->get_class(); | ||||||
|  | 	} else if (add_options[p_idx].type != String()) { | ||||||
| 		AnimationNode *an = Object::cast_to<AnimationNode>(ClassDB::instance(add_options[p_idx].type)); | 		AnimationNode *an = Object::cast_to<AnimationNode>(ClassDB::instance(add_options[p_idx].type)); | ||||||
| 		ERR_FAIL_COND(!an); | 		ERR_FAIL_COND(!an); | ||||||
| 		anode = Ref<AnimationNode>(an); | 		anode = Ref<AnimationNode>(an); | ||||||
|  | 		base_name = add_options[p_idx].name; | ||||||
| 	} else { | 	} else { | ||||||
| 		ERR_FAIL_COND(add_options[p_idx].script.is_null()); | 		ERR_FAIL_COND(add_options[p_idx].script.is_null()); | ||||||
| 		String base_type = add_options[p_idx].script->get_instance_base_type(); | 		String base_type = add_options[p_idx].script->get_instance_base_type(); | ||||||
|  | @ -242,13 +289,16 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) { | ||||||
| 		ERR_FAIL_COND(!an); | 		ERR_FAIL_COND(!an); | ||||||
| 		anode = Ref<AnimationNode>(an); | 		anode = Ref<AnimationNode>(an); | ||||||
| 		anode->set_script(add_options[p_idx].script.get_ref_ptr()); | 		anode->set_script(add_options[p_idx].script.get_ref_ptr()); | ||||||
|  | 		base_name = add_options[p_idx].name; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	Ref<AnimationNodeOutput> out = anode; | ||||||
|  | 	if (out.is_valid()) { | ||||||
|  | 		EditorNode::get_singleton()->show_warning(TTR("Output node can't be added to the blend tree.")); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
| 	Point2 instance_pos = graph->get_scroll_ofs() + graph->get_size() * 0.5; | 	Point2 instance_pos = graph->get_scroll_ofs() + graph->get_size() * 0.5; | ||||||
| 
 | 
 | ||||||
| 	anode->set_position(instance_pos / EDSCALE); |  | ||||||
| 
 |  | ||||||
| 	String base_name = add_options[p_idx].name; |  | ||||||
| 	int base = 1; | 	int base = 1; | ||||||
| 	String name = base_name; | 	String name = base_name; | ||||||
| 	while (blend_tree->has_node(name)) { | 	while (blend_tree->has_node(name)) { | ||||||
|  | @ -257,19 +307,19 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	undo_redo->create_action("Add Node to BlendTree"); | 	undo_redo->create_action("Add Node to BlendTree"); | ||||||
| 	undo_redo->add_do_method(blend_tree.ptr(), "add_node", name, anode); | 	undo_redo->add_do_method(blend_tree.ptr(), "add_node", name, anode, instance_pos / EDSCALE); | ||||||
| 	undo_redo->add_undo_method(blend_tree.ptr(), "remove_node", name); | 	undo_redo->add_undo_method(blend_tree.ptr(), "remove_node", name); | ||||||
| 	undo_redo->add_do_method(this, "_update_graph"); | 	undo_redo->add_do_method(this, "_update_graph"); | ||||||
| 	undo_redo->add_undo_method(this, "_update_graph"); | 	undo_redo->add_undo_method(this, "_update_graph"); | ||||||
| 	undo_redo->commit_action(); | 	undo_redo->commit_action(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_to, Ref<AnimationNode> p_node) { | void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_to, const StringName &p_which) { | ||||||
| 
 | 
 | ||||||
| 	updating = true; | 	updating = true; | ||||||
| 	undo_redo->create_action("Node Moved"); | 	undo_redo->create_action("Node Moved"); | ||||||
| 	undo_redo->add_do_method(p_node.ptr(), "set_position", p_to / EDSCALE); | 	undo_redo->add_do_method(blend_tree.ptr(), "set_node_position", p_which, p_to / EDSCALE); | ||||||
| 	undo_redo->add_undo_method(p_node.ptr(), "set_position", p_from / EDSCALE); | 	undo_redo->add_undo_method(blend_tree.ptr(), "set_node_position", p_which, p_from / EDSCALE); | ||||||
| 	undo_redo->add_do_method(this, "_update_graph"); | 	undo_redo->add_do_method(this, "_update_graph"); | ||||||
| 	undo_redo->add_undo_method(this, "_update_graph"); | 	undo_redo->add_undo_method(this, "_update_graph"); | ||||||
| 	undo_redo->commit_action(); | 	undo_redo->commit_action(); | ||||||
|  | @ -342,20 +392,6 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) { | ||||||
| 	undo_redo->commit_action(); | 	undo_redo->commit_action(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendTreeEditor::_oneshot_start(const StringName &p_name) { |  | ||||||
| 
 |  | ||||||
| 	Ref<AnimationNodeOneShot> os = blend_tree->get_node(p_name); |  | ||||||
| 	ERR_FAIL_COND(!os.is_valid()); |  | ||||||
| 	os->start(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void AnimationNodeBlendTreeEditor::_oneshot_stop(const StringName &p_name) { |  | ||||||
| 
 |  | ||||||
| 	Ref<AnimationNodeOneShot> os = blend_tree->get_node(p_name); |  | ||||||
| 	ERR_FAIL_COND(!os.is_valid()); |  | ||||||
| 	os->stop(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void AnimationNodeBlendTreeEditor::_node_selected(Object *p_node) { | void AnimationNodeBlendTreeEditor::_node_selected(Object *p_node) { | ||||||
| 
 | 
 | ||||||
| 	GraphNode *gn = Object::cast_to<GraphNode>(p_node); | 	GraphNode *gn = Object::cast_to<GraphNode>(p_node); | ||||||
|  | @ -373,13 +409,7 @@ void AnimationNodeBlendTreeEditor::_open_in_editor(const String &p_which) { | ||||||
| 
 | 
 | ||||||
| 	Ref<AnimationNode> an = blend_tree->get_node(p_which); | 	Ref<AnimationNode> an = blend_tree->get_node(p_which); | ||||||
| 	ERR_FAIL_COND(!an.is_valid()) | 	ERR_FAIL_COND(!an.is_valid()) | ||||||
| 	EditorNode::get_singleton()->edit_item(an.ptr()); | 	AnimationTreeEditor::get_singleton()->enter_editor(p_which); | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void AnimationNodeBlendTreeEditor::_open_parent() { |  | ||||||
| 	if (blend_tree->get_parent().is_valid()) { |  | ||||||
| 		EditorNode::get_singleton()->edit_item(blend_tree->get_parent().ptr()); |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendTreeEditor::_filter_toggled() { | void AnimationNodeBlendTreeEditor::_filter_toggled() { | ||||||
|  | @ -417,14 +447,14 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano | ||||||
| 	if (updating || _filter_edit != anode) | 	if (updating || _filter_edit != anode) | ||||||
| 		return false; | 		return false; | ||||||
| 
 | 
 | ||||||
| 	NodePath player_path = anode->get_tree()->get_animation_player(); | 	NodePath player_path = AnimationTreeEditor::get_singleton()->get_tree()->get_animation_player(); | ||||||
| 
 | 
 | ||||||
| 	if (!anode->get_tree()->has_node(player_path)) { | 	if (!AnimationTreeEditor::get_singleton()->get_tree()->has_node(player_path)) { | ||||||
| 		EditorNode::get_singleton()->show_warning(TTR("No animation player set, so unable to retrieve track names.")); | 		EditorNode::get_singleton()->show_warning(TTR("No animation player set, so unable to retrieve track names.")); | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	AnimationPlayer *player = Object::cast_to<AnimationPlayer>(anode->get_tree()->get_node(player_path)); | 	AnimationPlayer *player = Object::cast_to<AnimationPlayer>(AnimationTreeEditor::get_singleton()->get_tree()->get_node(player_path)); | ||||||
| 	if (!player) { | 	if (!player) { | ||||||
| 		EditorNode::get_singleton()->show_warning(TTR("Player path set is invalid, so unable to retrieve track names.")); | 		EditorNode::get_singleton()->show_warning(TTR("Player path set is invalid, so unable to retrieve track names.")); | ||||||
| 		return false; | 		return false; | ||||||
|  | @ -593,8 +623,6 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { | ||||||
| 
 | 
 | ||||||
| 	if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { | 	if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { | ||||||
| 
 | 
 | ||||||
| 		goto_parent->set_icon(get_icon("MoveUp", "EditorIcons")); |  | ||||||
| 
 |  | ||||||
| 		error_panel->add_style_override("panel", get_stylebox("bg", "Tree")); | 		error_panel->add_style_override("panel", get_stylebox("bg", "Tree")); | ||||||
| 		error_label->add_color_override("font_color", get_color("error_color", "Editor")); | 		error_label->add_color_override("font_color", get_color("error_color", "Editor")); | ||||||
| 	} | 	} | ||||||
|  | @ -603,12 +631,10 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { | ||||||
| 
 | 
 | ||||||
| 		String error; | 		String error; | ||||||
| 
 | 
 | ||||||
| 		if (!blend_tree->get_tree()) { | 		if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) { | ||||||
| 			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."); | 			error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails."); | ||||||
| 		} else if (blend_tree->get_tree()->is_state_invalid()) { | 		} else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) { | ||||||
| 			error = blend_tree->get_tree()->get_invalid_state_reason(); | 			error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason(); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (error != error_label->get_text()) { | 		if (error != error_label->get_text()) { | ||||||
|  | @ -624,13 +650,13 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { | ||||||
| 		blend_tree->get_node_connections(&conns); | 		blend_tree->get_node_connections(&conns); | ||||||
| 		for (List<AnimationNodeBlendTree::NodeConnection>::Element *E = conns.front(); E; E = E->next()) { | 		for (List<AnimationNodeBlendTree::NodeConnection>::Element *E = conns.front(); E; E = E->next()) { | ||||||
| 			float activity = 0; | 			float activity = 0; | ||||||
| 			if (blend_tree->get_tree() && !blend_tree->get_tree()->is_state_invalid()) { | 			if (AnimationTreeEditor::get_singleton()->get_tree() && !AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) { | ||||||
| 				activity = blend_tree->get_connection_activity(E->get().input_node, E->get().input_index); | 				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); | 			graph->set_connection_activity(E->get().output_node, 0, E->get().input_node, E->get().input_index, activity); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		AnimationTree *graph_player = blend_tree->get_tree(); | 		AnimationTree *graph_player = AnimationTreeEditor::get_singleton()->get_tree(); | ||||||
| 		AnimationPlayer *player = NULL; | 		AnimationPlayer *player = NULL; | ||||||
| 		if (graph_player->has_node(graph_player->get_animation_player())) { | 		if (graph_player->has_node(graph_player->get_animation_player())) { | ||||||
| 			player = Object::cast_to<AnimationPlayer>(graph_player->get_node(graph_player->get_animation_player())); | 			player = Object::cast_to<AnimationPlayer>(graph_player->get_node(graph_player->get_animation_player())); | ||||||
|  | @ -650,6 +676,14 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		for (int i = 0; i < visible_properties.size(); i++) { | ||||||
|  | 			visible_properties[i]->update_property(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { | ||||||
|  | 		set_process(is_visible_in_tree()); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -664,9 +698,9 @@ void AnimationNodeBlendTreeEditor::_scroll_changed(const Vector2 &p_scroll) { | ||||||
| void AnimationNodeBlendTreeEditor::_node_changed(ObjectID p_node) { | void AnimationNodeBlendTreeEditor::_node_changed(ObjectID p_node) { | ||||||
| 
 | 
 | ||||||
| 	AnimationNode *an = Object::cast_to<AnimationNode>(ObjectDB::get_instance(p_node)); | 	AnimationNode *an = Object::cast_to<AnimationNode>(ObjectDB::get_instance(p_node)); | ||||||
| 	if (an && an->get_parent() == blend_tree) { | 	//if (an && an->get_parent() == blend_tree) {
 | ||||||
| 	_update_graph(); | 	_update_graph(); | ||||||
| 	} | 	//}
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendTreeEditor::_bind_methods() { | void AnimationNodeBlendTreeEditor::_bind_methods() { | ||||||
|  | @ -680,17 +714,17 @@ void AnimationNodeBlendTreeEditor::_bind_methods() { | ||||||
| 	ClassDB::bind_method("_disconnection_request", &AnimationNodeBlendTreeEditor::_disconnection_request); | 	ClassDB::bind_method("_disconnection_request", &AnimationNodeBlendTreeEditor::_disconnection_request); | ||||||
| 	ClassDB::bind_method("_node_selected", &AnimationNodeBlendTreeEditor::_node_selected); | 	ClassDB::bind_method("_node_selected", &AnimationNodeBlendTreeEditor::_node_selected); | ||||||
| 	ClassDB::bind_method("_open_in_editor", &AnimationNodeBlendTreeEditor::_open_in_editor); | 	ClassDB::bind_method("_open_in_editor", &AnimationNodeBlendTreeEditor::_open_in_editor); | ||||||
| 	ClassDB::bind_method("_open_parent", &AnimationNodeBlendTreeEditor::_open_parent); |  | ||||||
| 	ClassDB::bind_method("_scroll_changed", &AnimationNodeBlendTreeEditor::_scroll_changed); | 	ClassDB::bind_method("_scroll_changed", &AnimationNodeBlendTreeEditor::_scroll_changed); | ||||||
| 	ClassDB::bind_method("_delete_request", &AnimationNodeBlendTreeEditor::_delete_request); | 	ClassDB::bind_method("_delete_request", &AnimationNodeBlendTreeEditor::_delete_request); | ||||||
| 	ClassDB::bind_method("_edit_filters", &AnimationNodeBlendTreeEditor::_edit_filters); | 	ClassDB::bind_method("_edit_filters", &AnimationNodeBlendTreeEditor::_edit_filters); | ||||||
| 	ClassDB::bind_method("_update_filters", &AnimationNodeBlendTreeEditor::_update_filters); | 	ClassDB::bind_method("_update_filters", &AnimationNodeBlendTreeEditor::_update_filters); | ||||||
| 	ClassDB::bind_method("_filter_edited", &AnimationNodeBlendTreeEditor::_filter_edited); | 	ClassDB::bind_method("_filter_edited", &AnimationNodeBlendTreeEditor::_filter_edited); | ||||||
| 	ClassDB::bind_method("_filter_toggled", &AnimationNodeBlendTreeEditor::_filter_toggled); | 	ClassDB::bind_method("_filter_toggled", &AnimationNodeBlendTreeEditor::_filter_toggled); | ||||||
| 	ClassDB::bind_method("_oneshot_start", &AnimationNodeBlendTreeEditor::_oneshot_start); |  | ||||||
| 	ClassDB::bind_method("_oneshot_stop", &AnimationNodeBlendTreeEditor::_oneshot_stop); |  | ||||||
| 	ClassDB::bind_method("_node_changed", &AnimationNodeBlendTreeEditor::_node_changed); | 	ClassDB::bind_method("_node_changed", &AnimationNodeBlendTreeEditor::_node_changed); | ||||||
| 	ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendTreeEditor::_removed_from_graph); | 	ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendTreeEditor::_removed_from_graph); | ||||||
|  | 	ClassDB::bind_method("_property_changed", &AnimationNodeBlendTreeEditor::_property_changed); | ||||||
|  | 	ClassDB::bind_method("_file_opened", &AnimationNodeBlendTreeEditor::_file_opened); | ||||||
|  | 	ClassDB::bind_method("_update_options_menu", &AnimationNodeBlendTreeEditor::_update_options_menu); | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method("_anim_selected", &AnimationNodeBlendTreeEditor::_anim_selected); | 	ClassDB::bind_method("_anim_selected", &AnimationNodeBlendTreeEditor::_anim_selected); | ||||||
| } | } | ||||||
|  | @ -708,7 +742,9 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima | ||||||
| 
 | 
 | ||||||
| 	ERR_FAIL_COND(new_name == "" || new_name.find(".") != -1 || new_name.find("/") != -1) | 	ERR_FAIL_COND(new_name == "" || new_name.find(".") != -1 || new_name.find("/") != -1) | ||||||
| 
 | 
 | ||||||
| 	ERR_FAIL_COND(new_name == prev_name); | 	if (new_name == prev_name) { | ||||||
|  | 		return; //nothing to do
 | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	String base_name = new_name; | 	String base_name = new_name; | ||||||
| 	int base = 1; | 	int base = 1; | ||||||
|  | @ -718,22 +754,61 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima | ||||||
| 		name = base_name + " " + itos(base); | 		name = base_name + " " + itos(base); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	String base_path = AnimationTreeEditor::get_singleton()->get_base_path(); | ||||||
|  | 
 | ||||||
| 	updating = true; | 	updating = true; | ||||||
| 	undo_redo->create_action("Node Renamed"); | 	undo_redo->create_action("Node Renamed"); | ||||||
| 	undo_redo->add_do_method(blend_tree.ptr(), "rename_node", prev_name, name); | 	undo_redo->add_do_method(blend_tree.ptr(), "rename_node", prev_name, name); | ||||||
| 	undo_redo->add_undo_method(blend_tree.ptr(), "rename_node", name, prev_name); | 	undo_redo->add_undo_method(blend_tree.ptr(), "rename_node", name, prev_name); | ||||||
|  | 	undo_redo->add_do_method(AnimationTreeEditor::get_singleton()->get_tree(), "rename_parameter", base_path + prev_name, base_path + name); | ||||||
|  | 	undo_redo->add_undo_method(AnimationTreeEditor::get_singleton()->get_tree(), "rename_parameter", base_path + name, base_path + prev_name); | ||||||
| 	undo_redo->add_do_method(this, "_update_graph"); | 	undo_redo->add_do_method(this, "_update_graph"); | ||||||
| 	undo_redo->add_undo_method(this, "_update_graph"); | 	undo_redo->add_undo_method(this, "_update_graph"); | ||||||
| 	undo_redo->commit_action(); | 	undo_redo->commit_action(); | ||||||
| 	updating = false; | 	updating = false; | ||||||
| 	gn->set_name(new_name); | 	gn->set_name(new_name); | ||||||
| 	gn->set_size(gn->get_minimum_size()); | 	gn->set_size(gn->get_minimum_size()); | ||||||
|  | 
 | ||||||
|  | 	//change editors accordingly
 | ||||||
|  | 	for (int i = 0; i < visible_properties.size(); i++) { | ||||||
|  | 		String pname = visible_properties[i]->get_edited_property().operator String(); | ||||||
|  | 		if (pname.begins_with(base_path + prev_name)) { | ||||||
|  | 			String new_name = pname.replace_first(base_path + prev_name, base_path + name); | ||||||
|  | 			visible_properties[i]->set_object_and_property(visible_properties[i]->get_edited_object(), new_name); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendTreeEditor::_node_renamed_focus_out(Node *le, Ref<AnimationNode> p_node) { | void AnimationNodeBlendTreeEditor::_node_renamed_focus_out(Node *le, Ref<AnimationNode> p_node) { | ||||||
| 	_node_renamed(le->call("get_text"), p_node); | 	_node_renamed(le->call("get_text"), p_node); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool AnimationNodeBlendTreeEditor::can_edit(const Ref<AnimationNode> &p_node) { | ||||||
|  | 	Ref<AnimationNodeBlendTree> bt = p_node; | ||||||
|  | 	return bt.is_valid(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) { | ||||||
|  | 
 | ||||||
|  | 	if (blend_tree.is_valid()) { | ||||||
|  | 		blend_tree->disconnect("removed_from_graph", this, "_removed_from_graph"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (p_node.is_valid()) { | ||||||
|  | 		blend_tree = p_node; | ||||||
|  | 	} else { | ||||||
|  | 		blend_tree.unref(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (blend_tree.is_null()) { | ||||||
|  | 		hide(); | ||||||
|  | 	} else { | ||||||
|  | 		blend_tree->connect("removed_from_graph", this, "_removed_from_graph"); | ||||||
|  | 
 | ||||||
|  | 		_update_graph(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { | AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { | ||||||
| 
 | 
 | ||||||
| 	singleton = this; | 	singleton = this; | ||||||
|  | @ -757,13 +832,8 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { | ||||||
| 	graph->get_zoom_hbox()->add_child(add_node); | 	graph->get_zoom_hbox()->add_child(add_node); | ||||||
| 	add_node->set_text(TTR("Add Node..")); | 	add_node->set_text(TTR("Add Node..")); | ||||||
| 	graph->get_zoom_hbox()->move_child(add_node, 0); | 	graph->get_zoom_hbox()->move_child(add_node, 0); | ||||||
| 	add_node->get_popup()->connect("index_pressed", this, "_add_node"); | 	add_node->get_popup()->connect("id_pressed", this, "_add_node"); | ||||||
| 
 | 	add_node->connect("about_to_show", this, "_update_options_menu"); | ||||||
| 	goto_parent = memnew(Button); |  | ||||||
| 	graph->get_zoom_hbox()->add_child(goto_parent); |  | ||||||
| 	graph->get_zoom_hbox()->move_child(goto_parent, 0); |  | ||||||
| 	goto_parent->hide(); |  | ||||||
| 	goto_parent->connect("pressed", this, "_open_parent"); |  | ||||||
| 
 | 
 | ||||||
| 	add_options.push_back(AddOption("Animation", "AnimationNodeAnimation")); | 	add_options.push_back(AddOption("Animation", "AnimationNodeAnimation")); | ||||||
| 	add_options.push_back(AddOption("OneShot", "AnimationNodeOneShot")); | 	add_options.push_back(AddOption("OneShot", "AnimationNodeOneShot")); | ||||||
|  | @ -804,45 +874,10 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { | ||||||
| 	filters->set_hide_root(true); | 	filters->set_hide_root(true); | ||||||
| 	filters->connect("item_edited", this, "_filter_edited"); | 	filters->connect("item_edited", this, "_filter_edited"); | ||||||
| 
 | 
 | ||||||
|  | 	open_file = memnew(EditorFileDialog); | ||||||
|  | 	add_child(open_file); | ||||||
|  | 	open_file->set_title(TTR("Open Animation Node")); | ||||||
|  | 	open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE); | ||||||
|  | 	open_file->connect("file_selected", this, "_file_opened"); | ||||||
| 	undo_redo = EditorNode::get_singleton()->get_undo_redo(); | 	undo_redo = EditorNode::get_singleton()->get_undo_redo(); | ||||||
| } | } | ||||||
| 
 |  | ||||||
| void AnimationNodeBlendTreeEditorPlugin::edit(Object *p_object) { |  | ||||||
| 
 |  | ||||||
| 	anim_tree_editor->edit(Object::cast_to<AnimationNodeBlendTree>(p_object)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool AnimationNodeBlendTreeEditorPlugin::handles(Object *p_object) const { |  | ||||||
| 
 |  | ||||||
| 	return p_object->is_class("AnimationNodeBlendTree"); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void AnimationNodeBlendTreeEditorPlugin::make_visible(bool p_visible) { |  | ||||||
| 
 |  | ||||||
| 	if (p_visible) { |  | ||||||
| 		//editor->hide_animation_player_editors();
 |  | ||||||
| 		//editor->animation_panel_make_visible(true);
 |  | ||||||
| 		button->show(); |  | ||||||
| 		editor->make_bottom_panel_item_visible(anim_tree_editor); |  | ||||||
| 		anim_tree_editor->set_process(true); |  | ||||||
| 	} else { |  | ||||||
| 
 |  | ||||||
| 		if (anim_tree_editor->is_visible_in_tree()) |  | ||||||
| 			editor->hide_bottom_panel(); |  | ||||||
| 		button->hide(); |  | ||||||
| 		anim_tree_editor->set_process(false); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| AnimationNodeBlendTreeEditorPlugin::AnimationNodeBlendTreeEditorPlugin(EditorNode *p_node) { |  | ||||||
| 
 |  | ||||||
| 	editor = p_node; |  | ||||||
| 	anim_tree_editor = memnew(AnimationNodeBlendTreeEditor); |  | ||||||
| 	anim_tree_editor->set_custom_minimum_size(Size2(0, 300)); |  | ||||||
| 
 |  | ||||||
| 	button = editor->add_bottom_panel_item(TTR("BlendTree"), anim_tree_editor); |  | ||||||
| 	button->hide(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| AnimationNodeBlendTreeEditorPlugin::~AnimationNodeBlendTreeEditorPlugin() { |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "editor/editor_node.h" | #include "editor/editor_node.h" | ||||||
| #include "editor/editor_plugin.h" | #include "editor/editor_plugin.h" | ||||||
|  | #include "editor/plugins/animation_tree_editor_plugin.h" | ||||||
| #include "editor/property_editor.h" | #include "editor/property_editor.h" | ||||||
| #include "scene/animation/animation_blend_tree.h" | #include "scene/animation/animation_blend_tree.h" | ||||||
| #include "scene/gui/button.h" | #include "scene/gui/button.h" | ||||||
|  | @ -13,14 +14,13 @@ | ||||||
| 	@author Juan Linietsky <reduzio@gmail.com> | 	@author Juan Linietsky <reduzio@gmail.com> | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| class AnimationNodeBlendTreeEditor : public VBoxContainer { | class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { | ||||||
| 
 | 
 | ||||||
| 	GDCLASS(AnimationNodeBlendTreeEditor, VBoxContainer); | 	GDCLASS(AnimationNodeBlendTreeEditor, AnimationTreeNodeEditorPlugin); | ||||||
| 
 | 
 | ||||||
| 	Ref<AnimationNodeBlendTree> blend_tree; | 	Ref<AnimationNodeBlendTree> blend_tree; | ||||||
| 	GraphEdit *graph; | 	GraphEdit *graph; | ||||||
| 	MenuButton *add_node; | 	MenuButton *add_node; | ||||||
| 	Button *goto_parent; |  | ||||||
| 
 | 
 | ||||||
| 	PanelContainer *error_panel; | 	PanelContainer *error_panel; | ||||||
| 	Label *error_label; | 	Label *error_label; | ||||||
|  | @ -32,6 +32,7 @@ class AnimationNodeBlendTreeEditor : public VBoxContainer { | ||||||
| 	CheckBox *filter_enabled; | 	CheckBox *filter_enabled; | ||||||
| 
 | 
 | ||||||
| 	Map<StringName, ProgressBar *> animations; | 	Map<StringName, ProgressBar *> animations; | ||||||
|  | 	Vector<EditorProperty *> visible_properties; | ||||||
| 
 | 
 | ||||||
| 	void _update_graph(); | 	void _update_graph(); | ||||||
| 
 | 
 | ||||||
|  | @ -52,7 +53,7 @@ class AnimationNodeBlendTreeEditor : public VBoxContainer { | ||||||
| 
 | 
 | ||||||
| 	static AnimationNodeBlendTreeEditor *singleton; | 	static AnimationNodeBlendTreeEditor *singleton; | ||||||
| 
 | 
 | ||||||
| 	void _node_dragged(const Vector2 &p_from, const Vector2 &p_to, Ref<AnimationNode> p_node); | 	void _node_dragged(const Vector2 &p_from, const Vector2 &p_to, const StringName &p_which); | ||||||
| 	void _node_renamed(const String &p_text, Ref<AnimationNode> p_node); | 	void _node_renamed(const String &p_text, Ref<AnimationNode> p_node); | ||||||
| 	void _node_renamed_focus_out(Node *le, Ref<AnimationNode> p_node); | 	void _node_renamed_focus_out(Node *le, Ref<AnimationNode> p_node); | ||||||
| 
 | 
 | ||||||
|  | @ -64,11 +65,8 @@ class AnimationNodeBlendTreeEditor : public VBoxContainer { | ||||||
| 	void _scroll_changed(const Vector2 &p_scroll); | 	void _scroll_changed(const Vector2 &p_scroll); | ||||||
| 	void _node_selected(Object *p_node); | 	void _node_selected(Object *p_node); | ||||||
| 	void _open_in_editor(const String &p_which); | 	void _open_in_editor(const String &p_which); | ||||||
| 	void _open_parent(); |  | ||||||
| 	void _anim_selected(int p_index, Array p_options, const String &p_node); | 	void _anim_selected(int p_index, Array p_options, const String &p_node); | ||||||
| 	void _delete_request(const String &p_which); | 	void _delete_request(const String &p_which); | ||||||
| 	void _oneshot_start(const StringName &p_name); |  | ||||||
| 	void _oneshot_stop(const StringName &p_name); |  | ||||||
| 
 | 
 | ||||||
| 	bool _update_filters(const Ref<AnimationNode> &anode); | 	bool _update_filters(const Ref<AnimationNode> &anode); | ||||||
| 	void _edit_filters(const String &p_which); | 	void _edit_filters(const String &p_which); | ||||||
|  | @ -78,8 +76,19 @@ class AnimationNodeBlendTreeEditor : public VBoxContainer { | ||||||
| 
 | 
 | ||||||
| 	void _node_changed(ObjectID p_node); | 	void _node_changed(ObjectID p_node); | ||||||
| 
 | 
 | ||||||
|  | 	void _property_changed(const StringName &p_property, const Variant &p_value); | ||||||
| 	void _removed_from_graph(); | 	void _removed_from_graph(); | ||||||
| 
 | 
 | ||||||
|  | 	EditorFileDialog *open_file; | ||||||
|  | 	Ref<AnimationNode> file_loaded; | ||||||
|  | 	void _file_opened(const String &p_file); | ||||||
|  | 
 | ||||||
|  | 	enum { | ||||||
|  | 		MENU_LOAD_FILE = 1000, | ||||||
|  | 		MENU_PASTE = 1001, | ||||||
|  | 		MENU_LOAD_FILE_CONFIRM = 1002 | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
| 	void _notification(int p_what); | 	void _notification(int p_what); | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
|  | @ -91,27 +100,11 @@ public: | ||||||
| 	void remove_custom_type(const Ref<Script> &p_script); | 	void remove_custom_type(const Ref<Script> &p_script); | ||||||
| 
 | 
 | ||||||
| 	virtual Size2 get_minimum_size() const; | 	virtual Size2 get_minimum_size() const; | ||||||
| 	void edit(AnimationNodeBlendTree *p_blend_tree); | 
 | ||||||
|  | 	virtual bool can_edit(const Ref<AnimationNode> &p_node); | ||||||
|  | 	virtual void edit(const Ref<AnimationNode> &p_node); | ||||||
|  | 
 | ||||||
| 	AnimationNodeBlendTreeEditor(); | 	AnimationNodeBlendTreeEditor(); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class AnimationNodeBlendTreeEditorPlugin : public EditorPlugin { |  | ||||||
| 
 |  | ||||||
| 	GDCLASS(AnimationNodeBlendTreeEditorPlugin, EditorPlugin); |  | ||||||
| 
 |  | ||||||
| 	AnimationNodeBlendTreeEditor *anim_tree_editor; |  | ||||||
| 	EditorNode *editor; |  | ||||||
| 	Button *button; |  | ||||||
| 
 |  | ||||||
| public: |  | ||||||
| 	virtual String get_name() const { return "BlendTree"; } |  | ||||||
| 	bool has_main_screen() const { return false; } |  | ||||||
| 	virtual void edit(Object *p_object); |  | ||||||
| 	virtual bool handles(Object *p_object) const; |  | ||||||
| 	virtual void make_visible(bool p_visible); |  | ||||||
| 
 |  | ||||||
| 	AnimationNodeBlendTreeEditorPlugin(EditorNode *p_node); |  | ||||||
| 	~AnimationNodeBlendTreeEditorPlugin(); |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| #endif // ANIMATION_BLEND_TREE_EDITOR_PLUGIN_H
 | #endif // ANIMATION_BLEND_TREE_EDITOR_PLUGIN_H
 | ||||||
|  |  | ||||||
|  | @ -11,22 +11,17 @@ | ||||||
| #include "scene/gui/panel.h" | #include "scene/gui/panel.h" | ||||||
| #include "scene/main/viewport.h" | #include "scene/main/viewport.h" | ||||||
| 
 | 
 | ||||||
| void AnimationNodeStateMachineEditor::edit(AnimationNodeStateMachine *p_state_machine) { | bool AnimationNodeStateMachineEditor::can_edit(const Ref<AnimationNode> &p_node) { | ||||||
|  | 
 | ||||||
|  | 	Ref<AnimationNodeStateMachine> ansm = p_node; | ||||||
|  | 	return ansm.is_valid(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) { | ||||||
|  | 
 | ||||||
|  | 	state_machine = p_node; | ||||||
| 
 | 
 | ||||||
| 	if (state_machine.is_valid()) { | 	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_from = StringName(); | ||||||
| 		selected_transition_to = StringName(); | 		selected_transition_to = StringName(); | ||||||
|  | @ -38,6 +33,10 @@ void AnimationNodeStateMachineEditor::edit(AnimationNodeStateMachine *p_state_ma | ||||||
| 
 | 
 | ||||||
| void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEvent> &p_event) { | void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEvent> &p_event) { | ||||||
| 
 | 
 | ||||||
|  | 	Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); | ||||||
|  | 	if (playback.is_null()) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
| 	Ref<InputEventKey> k = p_event; | 	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 (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()) { | 		if (selected_node != StringName() || selected_transition_to != StringName() || selected_transition_from != StringName()) { | ||||||
|  | @ -59,7 +58,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv | ||||||
| 		ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); | 		ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); | ||||||
| 		menu->add_submenu_item(TTR("Add Animation"), "animations"); | 		menu->add_submenu_item(TTR("Add Animation"), "animations"); | ||||||
| 
 | 
 | ||||||
| 		AnimationTree *gp = state_machine->get_tree(); | 		AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree(); | ||||||
| 		ERR_FAIL_COND(!gp); | 		ERR_FAIL_COND(!gp); | ||||||
| 		if (gp && gp->has_node(gp->get_animation_player())) { | 		if (gp && gp->has_node(gp->get_animation_player())) { | ||||||
| 			AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player())); | 			AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player())); | ||||||
|  | @ -79,9 +78,17 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv | ||||||
| 			if (name == "Animation") | 			if (name == "Animation") | ||||||
| 				continue; // nope
 | 				continue; // nope
 | ||||||
| 			int idx = menu->get_item_count(); | 			int idx = menu->get_item_count(); | ||||||
| 			menu->add_item(vformat("Add %s", name)); | 			menu->add_item(vformat("Add %s", name), idx); | ||||||
| 			menu->set_item_metadata(idx, E->get()); | 			menu->set_item_metadata(idx, E->get()); | ||||||
| 		} | 		} | ||||||
|  | 		Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard(); | ||||||
|  | 
 | ||||||
|  | 		if (clipb.is_valid()) { | ||||||
|  | 			menu->add_separator(); | ||||||
|  | 			menu->add_item(TTR("Paste"), MENU_PASTE); | ||||||
|  | 		} | ||||||
|  | 		menu->add_separator(); | ||||||
|  | 		menu->add_item(TTR("Load.."), MENU_LOAD_FILE); | ||||||
| 
 | 
 | ||||||
| 		menu->set_global_position(state_machine_draw->get_global_transform().xform(mb->get_position())); | 		menu->set_global_position(state_machine_draw->get_global_transform().xform(mb->get_position())); | ||||||
| 		menu->popup(); | 		menu->popup(); | ||||||
|  | @ -98,18 +105,12 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv | ||||||
| 		for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order
 | 		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 (node_rects[i].play.has_point(mb->get_position())) { //edit name
 | ||||||
| 				if (play_mode->get_selected() == 1 || !state_machine->is_playing()) { | 				if (play_mode->get_selected() == 1 || !playback->is_playing()) { | ||||||
| 					//start
 | 					//start
 | ||||||
| 					state_machine->start(node_rects[i].node_name); | 					playback->start(node_rects[i].node_name); | ||||||
| 				} else { | 				} else { | ||||||
| 					//travel
 | 					//travel
 | ||||||
| 					if (!state_machine->travel(node_rects[i].node_name)) { | 					playback->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(); | 				state_machine_draw->update(); | ||||||
| 				return; | 				return; | ||||||
|  | @ -196,8 +197,8 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv | ||||||
| 			Ref<AnimationNode> an = state_machine->get_node(selected_node); | 			Ref<AnimationNode> an = state_machine->get_node(selected_node); | ||||||
| 			updating = true; | 			updating = true; | ||||||
| 			undo_redo->create_action("Move Node"); | 			undo_redo->create_action("Move Node"); | ||||||
| 			undo_redo->add_do_method(an.ptr(), "set_position", an->get_position() + drag_ofs / EDSCALE); | 			undo_redo->add_do_method(state_machine.ptr(), "set_node_position", selected_node, state_machine->get_node_position(selected_node) + drag_ofs / EDSCALE); | ||||||
| 			undo_redo->add_undo_method(an.ptr(), "set_position", an->get_position()); | 			undo_redo->add_undo_method(state_machine.ptr(), "set_node_position", selected_node, state_machine->get_node_position(selected_node)); | ||||||
| 			undo_redo->add_do_method(this, "_update_graph"); | 			undo_redo->add_do_method(this, "_update_graph"); | ||||||
| 			undo_redo->add_undo_method(this, "_update_graph"); | 			undo_redo->add_undo_method(this, "_update_graph"); | ||||||
| 			undo_redo->commit_action(); | 			undo_redo->commit_action(); | ||||||
|  | @ -293,7 +294,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv | ||||||
| 		snap_y = StringName(); | 		snap_y = StringName(); | ||||||
| 		{ | 		{ | ||||||
| 			//snap
 | 			//snap
 | ||||||
| 			Vector2 cpos = state_machine->get_node(selected_node)->get_position() + drag_ofs / EDSCALE; | 			Vector2 cpos = state_machine->get_node_position(selected_node) + drag_ofs / EDSCALE; | ||||||
| 			List<StringName> nodes; | 			List<StringName> nodes; | ||||||
| 			state_machine->get_node_list(&nodes); | 			state_machine->get_node_list(&nodes); | ||||||
| 
 | 
 | ||||||
|  | @ -303,7 +304,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv | ||||||
| 			for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) { | 			for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) { | ||||||
| 				if (E->get() == selected_node) | 				if (E->get() == selected_node) | ||||||
| 					continue; | 					continue; | ||||||
| 				Vector2 npos = state_machine->get_node(E->get())->get_position(); | 				Vector2 npos = state_machine->get_node_position(E->get()); | ||||||
| 
 | 
 | ||||||
| 				float d_x = ABS(npos.x - cpos.x); | 				float d_x = ABS(npos.x - cpos.x); | ||||||
| 				if (d_x < MIN(5, best_d_x)) { | 				if (d_x < MIN(5, best_d_x)) { | ||||||
|  | @ -372,8 +373,37 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void AnimationNodeStateMachineEditor::_file_opened(const String &p_file) { | ||||||
|  | 
 | ||||||
|  | 	file_loaded = ResourceLoader::load(p_file); | ||||||
|  | 	if (file_loaded.is_valid()) { | ||||||
|  | 		_add_menu_type(MENU_LOAD_FILE_CONFIRM); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) { | void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) { | ||||||
| 
 | 
 | ||||||
|  | 	String base_name; | ||||||
|  | 	Ref<AnimationRootNode> node; | ||||||
|  | 
 | ||||||
|  | 	if (p_index == MENU_LOAD_FILE) { | ||||||
|  | 
 | ||||||
|  | 		open_file->clear_filters(); | ||||||
|  | 		List<String> filters; | ||||||
|  | 		ResourceLoader::get_recognized_extensions_for_type("AnimationRootNode", &filters); | ||||||
|  | 		for (List<String>::Element *E = filters.front(); E; E = E->next()) { | ||||||
|  | 			open_file->add_filter("*." + E->get()); | ||||||
|  | 		} | ||||||
|  | 		open_file->popup_centered_ratio(); | ||||||
|  | 		return; | ||||||
|  | 	} else if (p_index == MENU_LOAD_FILE_CONFIRM) { | ||||||
|  | 		node = file_loaded; | ||||||
|  | 		file_loaded.unref(); | ||||||
|  | 	} else if (p_index == MENU_PASTE) { | ||||||
|  | 
 | ||||||
|  | 		node = EditorSettings::get_singleton()->get_resource_clipboard(); | ||||||
|  | 
 | ||||||
|  | 	} else { | ||||||
| 		String type = menu->get_item_metadata(p_index); | 		String type = menu->get_item_metadata(p_index); | ||||||
| 
 | 
 | ||||||
| 		Object *obj = ClassDB::instance(type); | 		Object *obj = ClassDB::instance(type); | ||||||
|  | @ -381,10 +411,20 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) { | ||||||
| 		AnimationNode *an = Object::cast_to<AnimationNode>(obj); | 		AnimationNode *an = Object::cast_to<AnimationNode>(obj); | ||||||
| 		ERR_FAIL_COND(!an); | 		ERR_FAIL_COND(!an); | ||||||
| 
 | 
 | ||||||
| 	Ref<AnimationNode> node(an); | 		node = Ref<AnimationNode>(an); | ||||||
| 	node->set_position(add_node_pos); | 		base_name = type.replace_first("AnimationNode", ""); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!node.is_valid()) { | ||||||
|  | 		EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only root nodes are allowed.")); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (base_name == String()) { | ||||||
|  | 
 | ||||||
|  | 		base_name = node->get_class().replace_first("AnimationNode", ""); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	String base_name = type.replace_first("AnimationNode", ""); |  | ||||||
| 	int base = 1; | 	int base = 1; | ||||||
| 	String name = base_name; | 	String name = base_name; | ||||||
| 	while (state_machine->has_node(name)) { | 	while (state_machine->has_node(name)) { | ||||||
|  | @ -394,7 +434,7 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) { | ||||||
| 
 | 
 | ||||||
| 	updating = true; | 	updating = true; | ||||||
| 	undo_redo->create_action("Add Node"); | 	undo_redo->create_action("Add Node"); | ||||||
| 	undo_redo->add_do_method(state_machine.ptr(), "add_node", name, node); | 	undo_redo->add_do_method(state_machine.ptr(), "add_node", name, node, add_node_pos); | ||||||
| 	undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name); | 	undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name); | ||||||
| 	undo_redo->add_do_method(this, "_update_graph"); | 	undo_redo->add_do_method(this, "_update_graph"); | ||||||
| 	undo_redo->add_undo_method(this, "_update_graph"); | 	undo_redo->add_undo_method(this, "_update_graph"); | ||||||
|  | @ -419,11 +459,9 @@ void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) { | ||||||
| 		name = base_name + " " + itos(base); | 		name = base_name + " " + itos(base); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	anim->set_position(add_node_pos); |  | ||||||
| 
 |  | ||||||
| 	updating = true; | 	updating = true; | ||||||
| 	undo_redo->create_action("Add Node"); | 	undo_redo->create_action("Add Node"); | ||||||
| 	undo_redo->add_do_method(state_machine.ptr(), "add_node", name, anim); | 	undo_redo->add_do_method(state_machine.ptr(), "add_node", name, anim, add_node_pos); | ||||||
| 	undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name); | 	undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name); | ||||||
| 	undo_redo->add_do_method(this, "_update_graph"); | 	undo_redo->add_do_method(this, "_update_graph"); | ||||||
| 	undo_redo->add_undo_method(this, "_update_graph"); | 	undo_redo->add_undo_method(this, "_update_graph"); | ||||||
|  | @ -502,6 +540,8 @@ void AnimationNodeStateMachineEditor::_clip_dst_line_to_rect(Vector2 &r_from, Ve | ||||||
| 
 | 
 | ||||||
| void AnimationNodeStateMachineEditor::_state_machine_draw() { | void AnimationNodeStateMachineEditor::_state_machine_draw() { | ||||||
| 
 | 
 | ||||||
|  | 	Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); | ||||||
|  | 
 | ||||||
| 	Ref<StyleBox> style = get_stylebox("frame", "GraphNode"); | 	Ref<StyleBox> style = get_stylebox("frame", "GraphNode"); | ||||||
| 	Ref<StyleBox> style_selected = get_stylebox("selectedframe", "GraphNode"); | 	Ref<StyleBox> style_selected = get_stylebox("selectedframe", "GraphNode"); | ||||||
| 
 | 
 | ||||||
|  | @ -515,10 +555,17 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { | ||||||
| 	linecolor.a *= 0.3; | 	linecolor.a *= 0.3; | ||||||
| 	Ref<StyleBox> playing_overlay = get_stylebox("position", "GraphNode"); | 	Ref<StyleBox> playing_overlay = get_stylebox("position", "GraphNode"); | ||||||
| 
 | 
 | ||||||
| 	bool playing = state_machine->is_playing(); | 	bool playing = false; | ||||||
| 	StringName current = state_machine->get_current_node(); | 	StringName current; | ||||||
| 	StringName blend_from = state_machine->get_blend_from_node(); | 	StringName blend_from; | ||||||
| 	Vector<StringName> travel_path = state_machine->get_travel_path(); | 	Vector<StringName> travel_path; | ||||||
|  | 
 | ||||||
|  | 	if (playback.is_valid()) { | ||||||
|  | 		playing = playback->is_playing(); | ||||||
|  | 		current = playback->get_current_node(); | ||||||
|  | 		blend_from = playback->get_blend_from_node(); | ||||||
|  | 		travel_path = playback->get_travel_path(); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if (state_machine_draw->has_focus()) { | 	if (state_machine_draw->has_focus()) { | ||||||
| 		state_machine_draw->draw_rect(Rect2(Point2(), state_machine_draw->get_size()), accent, false); | 		state_machine_draw->draw_rect(Rect2(Point2(), state_machine_draw->get_size()), accent, false); | ||||||
|  | @ -534,13 +581,13 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { | ||||||
| 	//snap lines
 | 	//snap lines
 | ||||||
| 	if (dragging_selected) { | 	if (dragging_selected) { | ||||||
| 
 | 
 | ||||||
| 		Vector2 from = (state_machine->get_node(selected_node)->get_position() * EDSCALE) + drag_ofs - state_machine->get_graph_offset() * EDSCALE; | 		Vector2 from = (state_machine->get_node_position(selected_node) * EDSCALE) + drag_ofs - state_machine->get_graph_offset() * EDSCALE; | ||||||
| 		if (snap_x != StringName()) { | 		if (snap_x != StringName()) { | ||||||
| 			Vector2 to = (state_machine->get_node(snap_x)->get_position() * EDSCALE) - state_machine->get_graph_offset() * EDSCALE; | 			Vector2 to = (state_machine->get_node_position(snap_x) * EDSCALE) - state_machine->get_graph_offset() * EDSCALE; | ||||||
| 			state_machine_draw->draw_line(from, to, linecolor, 2); | 			state_machine_draw->draw_line(from, to, linecolor, 2); | ||||||
| 		} | 		} | ||||||
| 		if (snap_y != StringName()) { | 		if (snap_y != StringName()) { | ||||||
| 			Vector2 to = (state_machine->get_node(snap_y)->get_position() * EDSCALE) - state_machine->get_graph_offset() * EDSCALE; | 			Vector2 to = (state_machine->get_node_position(snap_y) * EDSCALE) - state_machine->get_graph_offset() * EDSCALE; | ||||||
| 			state_machine_draw->draw_line(from, to, linecolor, 2); | 			state_machine_draw->draw_line(from, to, linecolor, 2); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -563,7 +610,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		Vector2 offset; | 		Vector2 offset; | ||||||
| 		offset += anode->get_position() * EDSCALE; | 		offset += state_machine->get_node_position(E->get()) * EDSCALE; | ||||||
| 		if (selected_node == E->get() && dragging_selected) { | 		if (selected_node == E->get() && dragging_selected) { | ||||||
| 			offset += drag_ofs; | 			offset += drag_ofs; | ||||||
| 		} | 		} | ||||||
|  | @ -588,10 +635,10 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { | ||||||
| 
 | 
 | ||||||
| 	//draw conecting line for potential new transition
 | 	//draw conecting line for potential new transition
 | ||||||
| 	if (connecting) { | 	if (connecting) { | ||||||
| 		Vector2 from = (state_machine->get_node(connecting_from)->get_position() * EDSCALE) - state_machine->get_graph_offset() * EDSCALE; | 		Vector2 from = (state_machine->get_node_position(connecting_from) * EDSCALE) - state_machine->get_graph_offset() * EDSCALE; | ||||||
| 		Vector2 to; | 		Vector2 to; | ||||||
| 		if (connecting_to_node != StringName()) { | 		if (connecting_to_node != StringName()) { | ||||||
| 			to = (state_machine->get_node(connecting_to_node)->get_position() * EDSCALE) - state_machine->get_graph_offset() * EDSCALE; | 			to = (state_machine->get_node_position(connecting_to_node) * EDSCALE) - state_machine->get_graph_offset() * EDSCALE; | ||||||
| 		} else { | 		} else { | ||||||
| 			to = connecting_to; | 			to = connecting_to; | ||||||
| 		} | 		} | ||||||
|  | @ -617,15 +664,17 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { | ||||||
| 		TransitionLine tl; | 		TransitionLine tl; | ||||||
| 		tl.from_node = state_machine->get_transition_from(i); | 		tl.from_node = state_machine->get_transition_from(i); | ||||||
| 		Vector2 ofs_from = (dragging_selected && tl.from_node == selected_node) ? drag_ofs : Vector2(); | 		Vector2 ofs_from = (dragging_selected && tl.from_node == selected_node) ? drag_ofs : Vector2(); | ||||||
| 		tl.from = (state_machine->get_node(tl.from_node)->get_position() * EDSCALE) + ofs_from - state_machine->get_graph_offset() * EDSCALE; | 		tl.from = (state_machine->get_node_position(tl.from_node) * EDSCALE) + ofs_from - state_machine->get_graph_offset() * EDSCALE; | ||||||
| 
 | 
 | ||||||
| 		tl.to_node = state_machine->get_transition_to(i); | 		tl.to_node = state_machine->get_transition_to(i); | ||||||
| 		Vector2 ofs_to = (dragging_selected && tl.to_node == selected_node) ? drag_ofs : Vector2(); | 		Vector2 ofs_to = (dragging_selected && tl.to_node == selected_node) ? drag_ofs : Vector2(); | ||||||
| 		tl.to = (state_machine->get_node(tl.to_node)->get_position() * EDSCALE) + ofs_to - state_machine->get_graph_offset() * EDSCALE; | 		tl.to = (state_machine->get_node_position(tl.to_node) * EDSCALE) + ofs_to - state_machine->get_graph_offset() * EDSCALE; | ||||||
| 
 | 
 | ||||||
| 		Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(i); | 		Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(i); | ||||||
| 		tl.disabled = tr->is_disabled(); | 		tl.disabled = tr->is_disabled(); | ||||||
| 		tl.auto_advance = tr->has_auto_advance(); | 		tl.auto_advance = tr->has_auto_advance(); | ||||||
|  | 		tl.advance_condition_name = tr->get_advance_condition_name(); | ||||||
|  | 		tl.advance_condition_state = false; | ||||||
| 		tl.mode = tr->get_switch_mode(); | 		tl.mode = tr->get_switch_mode(); | ||||||
| 		tl.width = tr_bidi_offset; | 		tl.width = tr_bidi_offset; | ||||||
| 
 | 
 | ||||||
|  | @ -665,7 +714,14 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		_connection_draw(tl.from, tl.to, tl.mode, !tl.disabled, selected, travel, tl.auto_advance); | 
 | ||||||
|  | 		bool auto_advance = tl.auto_advance; | ||||||
|  | 		StringName fullpath = AnimationTreeEditor::get_singleton()->get_base_path() + String(tl.advance_condition_name); | ||||||
|  | 		if (tl.advance_condition_name != StringName() && bool(AnimationTreeEditor::get_singleton()->get_tree()->get(fullpath))) { | ||||||
|  | 			tl.advance_condition_state = true; | ||||||
|  | 			auto_advance = true; | ||||||
|  | 		} | ||||||
|  | 		_connection_draw(tl.from, tl.to, tl.mode, !tl.disabled, selected, travel, auto_advance); | ||||||
| 
 | 
 | ||||||
| 		transition_lines.push_back(tl); | 		transition_lines.push_back(tl); | ||||||
| 	} | 	} | ||||||
|  | @ -675,7 +731,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { | ||||||
| 
 | 
 | ||||||
| 		String name = node_rects[i].node_name; | 		String name = node_rects[i].node_name; | ||||||
| 		Ref<AnimationNode> anode = state_machine->get_node(name); | 		Ref<AnimationNode> anode = state_machine->get_node(name); | ||||||
| 		bool needs_editor = EditorNode::get_singleton()->item_has_editor(anode.ptr()); | 		bool needs_editor = AnimationTreeEditor::get_singleton()->can_edit(anode); | ||||||
| 		Ref<StyleBox> sb = name == selected_node ? style_selected : style; | 		Ref<StyleBox> sb = name == selected_node ? style_selected : style; | ||||||
| 		int strsize = font->get_string_size(name).width; | 		int strsize = font->get_string_size(name).width; | ||||||
| 
 | 
 | ||||||
|  | @ -757,12 +813,14 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { | ||||||
| 
 | 
 | ||||||
| void AnimationNodeStateMachineEditor::_state_machine_pos_draw() { | void AnimationNodeStateMachineEditor::_state_machine_pos_draw() { | ||||||
| 
 | 
 | ||||||
| 	if (!state_machine->is_playing()) | 	Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); | ||||||
|  | 
 | ||||||
|  | 	if (!playback.is_valid() || !playback->is_playing()) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	int idx = -1; | 	int idx = -1; | ||||||
| 	for (int i = 0; node_rects.size(); i++) { | 	for (int i = 0; node_rects.size(); i++) { | ||||||
| 		if (node_rects[i].node_name == state_machine->get_current_node()) { | 		if (node_rects[i].node_name == playback->get_current_node()) { | ||||||
| 			idx = i; | 			idx = i; | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
|  | @ -785,9 +843,9 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw() { | ||||||
| 	} | 	} | ||||||
| 	to.y = from.y; | 	to.y = from.y; | ||||||
| 
 | 
 | ||||||
| 	float len = MAX(0.0001, state_machine->get_current_length()); | 	float len = MAX(0.0001, playback->get_current_length()); | ||||||
| 
 | 
 | ||||||
| 	float pos = CLAMP(state_machine->get_current_play_pos(), 0, len); | 	float pos = CLAMP(playback->get_current_play_pos(), 0, len); | ||||||
| 	float c = pos / len; | 	float c = pos / len; | ||||||
| 	Color fg = get_color("font_color", "Label"); | 	Color fg = get_color("font_color", "Label"); | ||||||
| 	Color bg = fg; | 	Color bg = fg; | ||||||
|  | @ -807,12 +865,6 @@ void AnimationNodeStateMachineEditor::_update_graph() { | ||||||
| 
 | 
 | ||||||
| 	updating = true; | 	updating = true; | ||||||
| 
 | 
 | ||||||
| 	if (state_machine->get_parent().is_valid()) { |  | ||||||
| 		goto_parent_hbox->show(); |  | ||||||
| 	} else { |  | ||||||
| 		goto_parent_hbox->hide(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	state_machine_draw->update(); | 	state_machine_draw->update(); | ||||||
| 
 | 
 | ||||||
| 	updating = false; | 	updating = false; | ||||||
|  | @ -824,7 +876,6 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { | ||||||
| 		error_panel->add_style_override("panel", get_stylebox("bg", "Tree")); | 		error_panel->add_style_override("panel", get_stylebox("bg", "Tree")); | ||||||
| 		error_label->add_color_override("font_color", get_color("error_color", "Editor")); | 		error_label->add_color_override("font_color", get_color("error_color", "Editor")); | ||||||
| 		panel->add_style_override("panel", get_stylebox("bg", "Tree")); | 		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_select->set_icon(get_icon("ToolSelect", "EditorIcons")); | ||||||
| 		tool_create->set_icon(get_icon("ToolAddNode", "EditorIcons")); | 		tool_create->set_icon(get_icon("ToolAddNode", "EditorIcons")); | ||||||
|  | @ -856,19 +907,21 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { | ||||||
| 
 | 
 | ||||||
| 		String error; | 		String error; | ||||||
| 
 | 
 | ||||||
|  | 		Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); | ||||||
|  | 
 | ||||||
| 		if (error_time > 0) { | 		if (error_time > 0) { | ||||||
| 			error = error_text; | 			error = error_text; | ||||||
| 			error_time -= get_process_delta_time(); | 			error_time -= get_process_delta_time(); | ||||||
| 		} else if (!state_machine->get_tree()) { | 		} else if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) { | ||||||
| 			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."); | 			error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails."); | ||||||
| 		} else if (state_machine->get_tree()->is_state_invalid()) { | 		} else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) { | ||||||
| 			error = state_machine->get_tree()->get_invalid_state_reason(); | 			error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason(); | ||||||
| 		} else if (state_machine->get_parent().is_valid() && state_machine->get_parent()->is_class("AnimationNodeStateMachine")) { | 			/*} 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()) { | 			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."); | 				error = TTR("Start and end nodes are needed for a sub-transition."); | ||||||
| 			} | 			}*/ | ||||||
|  | 		} else if (playback.is_null()) { | ||||||
|  | 			error = vformat(TTR("No playback resource set at path: %s."), AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (error != error_label->get_text()) { | 		if (error != error_label->get_text()) { | ||||||
|  | @ -904,14 +957,38 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | 			if (transition_lines[i].advance_condition_name != state_machine->get_transition(tidx)->get_advance_condition_name()) { | ||||||
|  | 				state_machine_draw->update(); | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
| 			if (transition_lines[i].mode != state_machine->get_transition(tidx)->get_switch_mode()) { | 			if (transition_lines[i].mode != state_machine->get_transition(tidx)->get_switch_mode()) { | ||||||
| 				state_machine_draw->update(); | 				state_machine_draw->update(); | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
|  | 
 | ||||||
|  | 			bool acstate = transition_lines[i].advance_condition_name != StringName() && bool(AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + String(transition_lines[i].advance_condition_name))); | ||||||
|  | 
 | ||||||
|  | 			if (transition_lines[i].advance_condition_state != acstate) { | ||||||
|  | 				state_machine_draw->update(); | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		bool same_travel_path = true; | 		bool same_travel_path = true; | ||||||
| 		Vector<StringName> tp = state_machine->get_travel_path(); | 		Vector<StringName> tp; | ||||||
|  | 		bool is_playing = false; | ||||||
|  | 		StringName current_node; | ||||||
|  | 		StringName blend_from_node; | ||||||
|  | 		float play_pos = 0; | ||||||
|  | 
 | ||||||
|  | 		if (playback.is_valid()) { | ||||||
|  | 			tp = playback->get_travel_path(); | ||||||
|  | 			is_playing = playback->is_playing(); | ||||||
|  | 			current_node = playback->get_current_node(); | ||||||
|  | 			blend_from_node = playback->get_blend_from_node(); | ||||||
|  | 			play_pos = playback->get_current_play_pos(); | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		{ | 		{ | ||||||
| 
 | 
 | ||||||
|  | @ -928,37 +1005,32 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		//update if travel state changed
 | 		//update if travel state changed
 | ||||||
| 		if (!same_travel_path || last_active != state_machine->is_playing() || last_current_node != state_machine->get_current_node() || last_blend_from_node != state_machine->get_blend_from_node()) { | 		if (!same_travel_path || last_active != is_playing || last_current_node != current_node || last_blend_from_node != blend_from_node) { | ||||||
| 
 | 
 | ||||||
| 			state_machine_draw->update(); | 			state_machine_draw->update(); | ||||||
| 			last_travel_path = tp; | 			last_travel_path = tp; | ||||||
| 			last_current_node = state_machine->get_current_node(); | 			last_current_node = current_node; | ||||||
| 			last_active = state_machine->is_playing(); | 			last_active = is_playing; | ||||||
| 			last_blend_from_node = state_machine->get_blend_from_node(); | 			last_blend_from_node = blend_from_node; | ||||||
| 			state_machine_play_pos->update(); | 			state_machine_play_pos->update(); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (last_play_pos != state_machine->get_current_play_pos()) { | 		if (last_play_pos != play_pos) { | ||||||
| 
 | 
 | ||||||
| 			last_play_pos = state_machine->get_current_play_pos(); | 			last_play_pos = play_pos; | ||||||
| 			state_machine_play_pos->update(); | 			state_machine_play_pos->update(); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { | 	if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { | ||||||
| 		over_node = StringName(); | 		over_node = StringName(); | ||||||
|  | 		set_process(is_visible_in_tree()); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeStateMachineEditor::_open_editor(const String &p_name) { | 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() { | 	AnimationTreeEditor::get_singleton()->enter_editor(p_name); | ||||||
| 
 |  | ||||||
| 	EditorNode::get_singleton()->edit_item(state_machine->get_parent().ptr()); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeStateMachineEditor::_removed_from_graph() { | void AnimationNodeStateMachineEditor::_removed_from_graph() { | ||||||
|  | @ -1114,7 +1186,6 @@ void AnimationNodeStateMachineEditor::_bind_methods() { | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method("_name_edited", &AnimationNodeStateMachineEditor::_name_edited); | 	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("_removed_from_graph", &AnimationNodeStateMachineEditor::_removed_from_graph); | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method("_open_editor", &AnimationNodeStateMachineEditor::_open_editor); | 	ClassDB::bind_method("_open_editor", &AnimationNodeStateMachineEditor::_open_editor); | ||||||
|  | @ -1124,6 +1195,7 @@ void AnimationNodeStateMachineEditor::_bind_methods() { | ||||||
| 	ClassDB::bind_method("_autoplay_selected", &AnimationNodeStateMachineEditor::_autoplay_selected); | 	ClassDB::bind_method("_autoplay_selected", &AnimationNodeStateMachineEditor::_autoplay_selected); | ||||||
| 	ClassDB::bind_method("_end_selected", &AnimationNodeStateMachineEditor::_end_selected); | 	ClassDB::bind_method("_end_selected", &AnimationNodeStateMachineEditor::_end_selected); | ||||||
| 	ClassDB::bind_method("_update_mode", &AnimationNodeStateMachineEditor::_update_mode); | 	ClassDB::bind_method("_update_mode", &AnimationNodeStateMachineEditor::_update_mode); | ||||||
|  | 	ClassDB::bind_method("_file_opened", &AnimationNodeStateMachineEditor::_file_opened); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AnimationNodeStateMachineEditor *AnimationNodeStateMachineEditor::singleton = NULL; | AnimationNodeStateMachineEditor *AnimationNodeStateMachineEditor::singleton = NULL; | ||||||
|  | @ -1136,13 +1208,6 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { | ||||||
| 	HBoxContainer *top_hb = memnew(HBoxContainer); | 	HBoxContainer *top_hb = memnew(HBoxContainer); | ||||||
| 	add_child(top_hb); | 	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; | 	Ref<ButtonGroup> bg; | ||||||
| 	bg.instance(); | 	bg.instance(); | ||||||
| 
 | 
 | ||||||
|  | @ -1248,7 +1313,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { | ||||||
| 
 | 
 | ||||||
| 	menu = memnew(PopupMenu); | 	menu = memnew(PopupMenu); | ||||||
| 	add_child(menu); | 	add_child(menu); | ||||||
| 	menu->connect("index_pressed", this, "_add_menu_type"); | 	menu->connect("id_pressed", this, "_add_menu_type"); | ||||||
| 
 | 
 | ||||||
| 	animations_menu = memnew(PopupMenu); | 	animations_menu = memnew(PopupMenu); | ||||||
| 	menu->add_child(animations_menu); | 	menu->add_child(animations_menu); | ||||||
|  | @ -1261,6 +1326,13 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { | ||||||
| 	name_edit->connect("text_entered", this, "_name_edited"); | 	name_edit->connect("text_entered", this, "_name_edited"); | ||||||
| 	name_edit->set_as_toplevel(true); | 	name_edit->set_as_toplevel(true); | ||||||
| 
 | 
 | ||||||
|  | 	open_file = memnew(EditorFileDialog); | ||||||
|  | 	add_child(open_file); | ||||||
|  | 	open_file->set_title(TTR("Open Animation Node")); | ||||||
|  | 	open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE); | ||||||
|  | 	open_file->connect("file_selected", this, "_file_opened"); | ||||||
|  | 	undo_redo = EditorNode::get_singleton()->get_undo_redo(); | ||||||
|  | 
 | ||||||
| 	over_text = false; | 	over_text = false; | ||||||
| 
 | 
 | ||||||
| 	over_node_what = -1; | 	over_node_what = -1; | ||||||
|  | @ -1271,43 +1343,3 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { | ||||||
| 
 | 
 | ||||||
| 	error_time = 0; | 	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() { |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "editor/editor_node.h" | #include "editor/editor_node.h" | ||||||
| #include "editor/editor_plugin.h" | #include "editor/editor_plugin.h" | ||||||
|  | #include "editor/plugins/animation_tree_editor_plugin.h" | ||||||
| #include "editor/property_editor.h" | #include "editor/property_editor.h" | ||||||
| #include "scene/animation/animation_node_state_machine.h" | #include "scene/animation/animation_node_state_machine.h" | ||||||
| #include "scene/gui/button.h" | #include "scene/gui/button.h" | ||||||
|  | @ -10,9 +11,9 @@ | ||||||
| #include "scene/gui/popup.h" | #include "scene/gui/popup.h" | ||||||
| #include "scene/gui/tree.h" | #include "scene/gui/tree.h" | ||||||
| 
 | 
 | ||||||
| class AnimationNodeStateMachineEditor : public VBoxContainer { | class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { | ||||||
| 
 | 
 | ||||||
| 	GDCLASS(AnimationNodeStateMachineEditor, VBoxContainer); | 	GDCLASS(AnimationNodeStateMachineEditor, AnimationTreeNodeEditorPlugin); | ||||||
| 
 | 
 | ||||||
| 	Ref<AnimationNodeStateMachine> state_machine; | 	Ref<AnimationNodeStateMachine> state_machine; | ||||||
| 
 | 
 | ||||||
|  | @ -29,9 +30,6 @@ class AnimationNodeStateMachineEditor : public VBoxContainer { | ||||||
| 	OptionButton *transition_mode; | 	OptionButton *transition_mode; | ||||||
| 	OptionButton *play_mode; | 	OptionButton *play_mode; | ||||||
| 
 | 
 | ||||||
| 	HBoxContainer *goto_parent_hbox; |  | ||||||
| 	ToolButton *goto_parent; |  | ||||||
| 
 |  | ||||||
| 	PanelContainer *panel; | 	PanelContainer *panel; | ||||||
| 
 | 
 | ||||||
| 	StringName selected_node; | 	StringName selected_node; | ||||||
|  | @ -79,8 +77,6 @@ class AnimationNodeStateMachineEditor : public VBoxContainer { | ||||||
| 	void _add_menu_type(int p_index); | 	void _add_menu_type(int p_index); | ||||||
| 	void _add_animation_type(int p_index); | 	void _add_animation_type(int p_index); | ||||||
| 
 | 
 | ||||||
| 	void _goto_parent(); |  | ||||||
| 
 |  | ||||||
| 	void _removed_from_graph(); | 	void _removed_from_graph(); | ||||||
| 
 | 
 | ||||||
| 	struct NodeRect { | 	struct NodeRect { | ||||||
|  | @ -99,6 +95,8 @@ class AnimationNodeStateMachineEditor : public VBoxContainer { | ||||||
| 		Vector2 from; | 		Vector2 from; | ||||||
| 		Vector2 to; | 		Vector2 to; | ||||||
| 		AnimationNodeStateMachineTransition::SwitchMode mode; | 		AnimationNodeStateMachineTransition::SwitchMode mode; | ||||||
|  | 		StringName advance_condition_name; | ||||||
|  | 		bool advance_condition_state; | ||||||
| 		bool disabled; | 		bool disabled; | ||||||
| 		bool auto_advance; | 		bool auto_advance; | ||||||
| 		float width; | 		float width; | ||||||
|  | @ -135,33 +133,25 @@ class AnimationNodeStateMachineEditor : public VBoxContainer { | ||||||
| 	float error_time; | 	float error_time; | ||||||
| 	String error_text; | 	String error_text; | ||||||
| 
 | 
 | ||||||
|  | 	EditorFileDialog *open_file; | ||||||
|  | 	Ref<AnimationNode> file_loaded; | ||||||
|  | 	void _file_opened(const String &p_file); | ||||||
|  | 
 | ||||||
|  | 	enum { | ||||||
|  | 		MENU_LOAD_FILE = 1000, | ||||||
|  | 		MENU_PASTE = 1001, | ||||||
|  | 		MENU_LOAD_FILE_CONFIRM = 1002 | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
| 	void _notification(int p_what); | 	void _notification(int p_what); | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 	static AnimationNodeStateMachineEditor *get_singleton() { return singleton; } | 	static AnimationNodeStateMachineEditor *get_singleton() { return singleton; } | ||||||
| 	void edit(AnimationNodeStateMachine *p_state_machine); | 	virtual bool can_edit(const Ref<AnimationNode> &p_node); | ||||||
|  | 	virtual void edit(const Ref<AnimationNode> &p_node); | ||||||
| 	AnimationNodeStateMachineEditor(); | 	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
 | #endif // ANIMATION_STATE_MACHINE_EDITOR_H
 | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -1,167 +1,65 @@ | ||||||
| /*************************************************************************/ |  | ||||||
| /*  animation_tree_editor_plugin.h                                       */ |  | ||||||
| /*************************************************************************/ |  | ||||||
| /*                       This file is part of:                           */ |  | ||||||
| /*                           GODOT ENGINE                                */ |  | ||||||
| /*                      https://godotengine.org                          */ |  | ||||||
| /*************************************************************************/ |  | ||||||
| /* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */ |  | ||||||
| /* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */ |  | ||||||
| /*                                                                       */ |  | ||||||
| /* Permission is hereby granted, free of charge, to any person obtaining */ |  | ||||||
| /* a copy of this software and associated documentation files (the       */ |  | ||||||
| /* "Software"), to deal in the Software without restriction, including   */ |  | ||||||
| /* without limitation the rights to use, copy, modify, merge, publish,   */ |  | ||||||
| /* distribute, sublicense, and/or sell copies of the Software, and to    */ |  | ||||||
| /* permit persons to whom the Software is furnished to do so, subject to */ |  | ||||||
| /* the following conditions:                                             */ |  | ||||||
| /*                                                                       */ |  | ||||||
| /* The above copyright notice and this permission notice shall be        */ |  | ||||||
| /* included in all copies or substantial portions of the Software.       */ |  | ||||||
| /*                                                                       */ |  | ||||||
| /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ |  | ||||||
| /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ |  | ||||||
| /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ |  | ||||||
| /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ |  | ||||||
| /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ |  | ||||||
| /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ |  | ||||||
| /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ |  | ||||||
| /*************************************************************************/ |  | ||||||
| 
 |  | ||||||
| #ifndef ANIMATION_TREE_EDITOR_PLUGIN_H | #ifndef ANIMATION_TREE_EDITOR_PLUGIN_H | ||||||
| #define ANIMATION_TREE_EDITOR_PLUGIN_H | #define ANIMATION_TREE_EDITOR_PLUGIN_H | ||||||
| 
 | 
 | ||||||
| #include "editor/editor_node.h" | #include "editor/editor_node.h" | ||||||
| #include "editor/editor_plugin.h" | #include "editor/editor_plugin.h" | ||||||
| #include "editor/property_editor.h" | #include "editor/property_editor.h" | ||||||
| #include "scene/animation/animation_tree_player.h" | #include "scene/animation/animation_tree.h" | ||||||
| #include "scene/gui/button.h" | #include "scene/gui/button.h" | ||||||
|  | #include "scene/gui/graph_edit.h" | ||||||
| #include "scene/gui/popup.h" | #include "scene/gui/popup.h" | ||||||
| #include "scene/gui/tree.h" | #include "scene/gui/tree.h" | ||||||
| /**
 |  | ||||||
| 	@author Juan Linietsky <reduzio@gmail.com> |  | ||||||
| */ |  | ||||||
| 
 | 
 | ||||||
| class AnimationTreeEditor : public Control { | class AnimationTreeNodeEditorPlugin : public VBoxContainer { | ||||||
|  | 	GDCLASS(AnimationTreeNodeEditorPlugin, VBoxContainer) | ||||||
|  | public: | ||||||
|  | 	virtual bool can_edit(const Ref<AnimationNode> &p_node) = 0; | ||||||
|  | 	virtual void edit(const Ref<AnimationNode> &p_node) = 0; | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| 	GDCLASS(AnimationTreeEditor, Control); | class AnimationTreeEditor : public VBoxContainer { | ||||||
| 
 | 
 | ||||||
| 	static const char *_node_type_names[]; | 	GDCLASS(AnimationTreeEditor, VBoxContainer); | ||||||
| 
 | 
 | ||||||
| 	enum ClickType { | 	ScrollContainer *path_edit; | ||||||
| 		CLICK_NONE, | 	HBoxContainer *path_hb; | ||||||
| 		CLICK_NAME, |  | ||||||
| 		CLICK_NODE, |  | ||||||
| 		CLICK_INPUT_SLOT, |  | ||||||
| 		CLICK_OUTPUT_SLOT, |  | ||||||
| 		CLICK_PARAMETER |  | ||||||
| 	}; |  | ||||||
| 
 | 
 | ||||||
| 	enum { | 	AnimationTree *tree; | ||||||
|  | 	PanelContainer *editor_base; | ||||||
| 
 | 
 | ||||||
| 		MENU_GRAPH_CLEAR = 100, | 	Vector<String> button_path; | ||||||
| 		MENU_IMPORT_ANIMATIONS = 101, | 	Vector<String> edited_path; | ||||||
| 		NODE_DISCONNECT, | 	Vector<AnimationTreeNodeEditorPlugin *> editors; | ||||||
| 		NODE_RENAME, |  | ||||||
| 		NODE_ERASE, |  | ||||||
| 		NODE_ADD_INPUT, |  | ||||||
| 		NODE_DELETE_INPUT, |  | ||||||
| 		NODE_SET_AUTOADVANCE, |  | ||||||
| 		NODE_CLEAR_AUTOADVANCE |  | ||||||
| 	}; |  | ||||||
| 
 | 
 | ||||||
| 	bool renaming_edit; | 	void _update_path(); | ||||||
| 	StringName edited_node; | 	void _about_to_show_root(); | ||||||
| 	bool updating_edit; | 	ObjectID current_root; | ||||||
| 	Popup *edit_dialog; |  | ||||||
| 	HSlider *edit_scroll[2]; |  | ||||||
| 	LineEdit *edit_line[4]; |  | ||||||
| 	OptionButton *edit_option; |  | ||||||
| 	Label *edit_label[4]; |  | ||||||
| 	Button *edit_button; |  | ||||||
| 	Button *filter_button; |  | ||||||
| 	CheckButton *edit_check; |  | ||||||
| 	EditorFileDialog *file_dialog; |  | ||||||
| 	int file_op; |  | ||||||
| 
 | 
 | ||||||
| 	void _popup_edit_dialog(); | 	void _path_button_pressed(int p_path); | ||||||
| 
 | 
 | ||||||
| 	void _setup_edit_dialog(const StringName &p_node); | 	static Vector<String> get_animation_list(); | ||||||
| 	PopupMenu *master_anim_popup; |  | ||||||
| 	PopupMenu *node_popup; |  | ||||||
| 	PopupMenu *add_popup; |  | ||||||
| 	HScrollBar *h_scroll; |  | ||||||
| 	VScrollBar *v_scroll; |  | ||||||
| 	MenuButton *add_menu; |  | ||||||
| 
 |  | ||||||
| 	CustomPropertyEditor *property_editor; |  | ||||||
| 
 |  | ||||||
| 	AnimationTreePlayer *anim_tree; |  | ||||||
| 	List<StringName> order; |  | ||||||
| 	Set<StringName> active_nodes; |  | ||||||
| 
 |  | ||||||
| 	int last_x, last_y; |  | ||||||
| 
 |  | ||||||
| 	Point2 offset; |  | ||||||
| 	ClickType click_type; |  | ||||||
| 	Point2 click_pos; |  | ||||||
| 	StringName click_node; |  | ||||||
| 	int click_slot; |  | ||||||
| 	Point2 click_motion; |  | ||||||
| 	ClickType rclick_type; |  | ||||||
| 	StringName rclick_node; |  | ||||||
| 	int rclick_slot; |  | ||||||
| 
 |  | ||||||
| 	Button *play_button; |  | ||||||
| 
 |  | ||||||
| 	Size2 _get_maximum_size(); |  | ||||||
| 	Size2 get_node_size(const StringName &p_node) const; |  | ||||||
| 	void _draw_node(const StringName &p_node); |  | ||||||
| 
 |  | ||||||
| 	AcceptDialog *filter_dialog; |  | ||||||
| 	Tree *filter; |  | ||||||
| 
 |  | ||||||
| 	void _draw_cos_line(const Vector2 &p_from, const Vector2 &p_to, const Color &p_color); |  | ||||||
| 	void _update_scrollbars(); |  | ||||||
| 	void _scroll_moved(float); |  | ||||||
| 	void _play_toggled(); |  | ||||||
| 	/*
 |  | ||||||
| 	void _node_param_changed(); |  | ||||||
| 	void _node_add_callback(); |  | ||||||
| 	void _node_add(VisualServer::AnimationTreeNodeType p_type); |  | ||||||
| 	void _node_edit_property(const StringName& p_node); |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| 	void _master_anim_menu_item(int p_item); |  | ||||||
| 	void _node_menu_item(int p_item); |  | ||||||
| 	void _add_menu_item(int p_item); |  | ||||||
| 
 |  | ||||||
| 	void _filter_edited(); |  | ||||||
| 	void _find_paths_for_filter(const StringName &p_node, Set<String> &paths); |  | ||||||
| 	void _edit_filters(); |  | ||||||
| 
 |  | ||||||
| 	void _edit_oneshot_start(); |  | ||||||
| 	void _edit_dialog_animation_changed(); |  | ||||||
| 	void _edit_dialog_edit_animation(); |  | ||||||
| 	void _edit_dialog_changeds(String); |  | ||||||
| 	void _edit_dialog_changede(String); |  | ||||||
| 	void _edit_dialog_changedf(float); |  | ||||||
| 	void _edit_dialog_changed(); |  | ||||||
| 	void _dialog_changed() const; |  | ||||||
| 	ClickType _locate_click(const Point2 &p_click, StringName *p_node_id, int *p_slot_index) const; |  | ||||||
| 	Point2 _get_slot_pos(const StringName &p_node_id, bool p_input, int p_slot); |  | ||||||
| 
 |  | ||||||
| 	StringName _add_node(int p_item); |  | ||||||
| 	void _file_dialog_selected(String p_path); |  | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
| 	void _notification(int p_what); | 	void _notification(int p_what); | ||||||
| 	void _gui_input(Ref<InputEvent> p_event); |  | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
| 
 | 
 | ||||||
|  | 	static AnimationTreeEditor *singleton; | ||||||
|  | 
 | ||||||
| public: | public: | ||||||
| 	virtual Size2 get_minimum_size() const; | 	AnimationTree *get_tree() { return tree; } | ||||||
| 	void edit(AnimationTreePlayer *p_anim_tree); | 	void add_plugin(AnimationTreeNodeEditorPlugin *p_editor); | ||||||
|  | 	void remove_plugin(AnimationTreeNodeEditorPlugin *p_editor); | ||||||
|  | 
 | ||||||
|  | 	String get_base_path(); | ||||||
|  | 
 | ||||||
|  | 	bool can_edit(const Ref<AnimationNode> &p_node) const; | ||||||
|  | 
 | ||||||
|  | 	void edit_path(const Vector<String> &p_path); | ||||||
|  | 	Vector<String> get_edited_path() const; | ||||||
|  | 
 | ||||||
|  | 	void enter_editor(const String &p_path = ""); | ||||||
|  | 	static AnimationTreeEditor *get_singleton() { return singleton; } | ||||||
|  | 	void edit(AnimationTree *p_tree); | ||||||
| 	AnimationTreeEditor(); | 	AnimationTreeEditor(); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -174,7 +72,7 @@ class AnimationTreeEditorPlugin : public EditorPlugin { | ||||||
| 	Button *button; | 	Button *button; | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 	virtual String get_name() const { return "AnimTree"; } | 	virtual String get_name() const { return "AnimationTree"; } | ||||||
| 	bool has_main_screen() const { return false; } | 	bool has_main_screen() const { return false; } | ||||||
| 	virtual void edit(Object *p_object); | 	virtual void edit(Object *p_object); | ||||||
| 	virtual bool handles(Object *p_object) const; | 	virtual bool handles(Object *p_object) const; | ||||||
|  |  | ||||||
							
								
								
									
										1446
									
								
								editor/plugins/animation_tree_player_editor_plugin.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1446
									
								
								editor/plugins/animation_tree_player_editor_plugin.cpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										187
									
								
								editor/plugins/animation_tree_player_editor_plugin.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								editor/plugins/animation_tree_player_editor_plugin.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,187 @@ | ||||||
|  | /*************************************************************************/ | ||||||
|  | /*  animation_tree_editor_plugin.h                                       */ | ||||||
|  | /*************************************************************************/ | ||||||
|  | /*                       This file is part of:                           */ | ||||||
|  | /*                           GODOT ENGINE                                */ | ||||||
|  | /*                      https://godotengine.org                          */ | ||||||
|  | /*************************************************************************/ | ||||||
|  | /* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */ | ||||||
|  | /* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */ | ||||||
|  | /*                                                                       */ | ||||||
|  | /* Permission is hereby granted, free of charge, to any person obtaining */ | ||||||
|  | /* a copy of this software and associated documentation files (the       */ | ||||||
|  | /* "Software"), to deal in the Software without restriction, including   */ | ||||||
|  | /* without limitation the rights to use, copy, modify, merge, publish,   */ | ||||||
|  | /* distribute, sublicense, and/or sell copies of the Software, and to    */ | ||||||
|  | /* permit persons to whom the Software is furnished to do so, subject to */ | ||||||
|  | /* the following conditions:                                             */ | ||||||
|  | /*                                                                       */ | ||||||
|  | /* The above copyright notice and this permission notice shall be        */ | ||||||
|  | /* included in all copies or substantial portions of the Software.       */ | ||||||
|  | /*                                                                       */ | ||||||
|  | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ | ||||||
|  | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ | ||||||
|  | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ | ||||||
|  | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ | ||||||
|  | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ | ||||||
|  | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ | ||||||
|  | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ | ||||||
|  | /*************************************************************************/ | ||||||
|  | 
 | ||||||
|  | #ifndef ANIMATION_TREE_PLAYER_EDITOR_PLUGIN_H | ||||||
|  | #define ANIMATION_TREE_PLAYER_EDITOR_PLUGIN_H | ||||||
|  | 
 | ||||||
|  | #include "editor/editor_node.h" | ||||||
|  | #include "editor/editor_plugin.h" | ||||||
|  | #include "editor/property_editor.h" | ||||||
|  | #include "scene/animation/animation_tree_player.h" | ||||||
|  | #include "scene/gui/button.h" | ||||||
|  | #include "scene/gui/popup.h" | ||||||
|  | #include "scene/gui/tree.h" | ||||||
|  | /**
 | ||||||
|  | 	@author Juan Linietsky <reduzio@gmail.com> | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | class AnimationTreePlayerEditor : public Control { | ||||||
|  | 
 | ||||||
|  | 	GDCLASS(AnimationTreePlayerEditor, Control); | ||||||
|  | 
 | ||||||
|  | 	static const char *_node_type_names[]; | ||||||
|  | 
 | ||||||
|  | 	enum ClickType { | ||||||
|  | 		CLICK_NONE, | ||||||
|  | 		CLICK_NAME, | ||||||
|  | 		CLICK_NODE, | ||||||
|  | 		CLICK_INPUT_SLOT, | ||||||
|  | 		CLICK_OUTPUT_SLOT, | ||||||
|  | 		CLICK_PARAMETER | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	enum { | ||||||
|  | 
 | ||||||
|  | 		MENU_GRAPH_CLEAR = 100, | ||||||
|  | 		MENU_IMPORT_ANIMATIONS = 101, | ||||||
|  | 		NODE_DISCONNECT, | ||||||
|  | 		NODE_RENAME, | ||||||
|  | 		NODE_ERASE, | ||||||
|  | 		NODE_ADD_INPUT, | ||||||
|  | 		NODE_DELETE_INPUT, | ||||||
|  | 		NODE_SET_AUTOADVANCE, | ||||||
|  | 		NODE_CLEAR_AUTOADVANCE | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	bool renaming_edit; | ||||||
|  | 	StringName edited_node; | ||||||
|  | 	bool updating_edit; | ||||||
|  | 	Popup *edit_dialog; | ||||||
|  | 	HSlider *edit_scroll[2]; | ||||||
|  | 	LineEdit *edit_line[4]; | ||||||
|  | 	OptionButton *edit_option; | ||||||
|  | 	Label *edit_label[4]; | ||||||
|  | 	Button *edit_button; | ||||||
|  | 	Button *filter_button; | ||||||
|  | 	CheckButton *edit_check; | ||||||
|  | 	EditorFileDialog *file_dialog; | ||||||
|  | 	int file_op; | ||||||
|  | 
 | ||||||
|  | 	void _popup_edit_dialog(); | ||||||
|  | 
 | ||||||
|  | 	void _setup_edit_dialog(const StringName &p_node); | ||||||
|  | 	PopupMenu *master_anim_popup; | ||||||
|  | 	PopupMenu *node_popup; | ||||||
|  | 	PopupMenu *add_popup; | ||||||
|  | 	HScrollBar *h_scroll; | ||||||
|  | 	VScrollBar *v_scroll; | ||||||
|  | 	MenuButton *add_menu; | ||||||
|  | 
 | ||||||
|  | 	CustomPropertyEditor *property_editor; | ||||||
|  | 
 | ||||||
|  | 	AnimationTreePlayer *anim_tree; | ||||||
|  | 	List<StringName> order; | ||||||
|  | 	Set<StringName> active_nodes; | ||||||
|  | 
 | ||||||
|  | 	int last_x, last_y; | ||||||
|  | 
 | ||||||
|  | 	Point2 offset; | ||||||
|  | 	ClickType click_type; | ||||||
|  | 	Point2 click_pos; | ||||||
|  | 	StringName click_node; | ||||||
|  | 	int click_slot; | ||||||
|  | 	Point2 click_motion; | ||||||
|  | 	ClickType rclick_type; | ||||||
|  | 	StringName rclick_node; | ||||||
|  | 	int rclick_slot; | ||||||
|  | 
 | ||||||
|  | 	Button *play_button; | ||||||
|  | 
 | ||||||
|  | 	Size2 _get_maximum_size(); | ||||||
|  | 	Size2 get_node_size(const StringName &p_node) const; | ||||||
|  | 	void _draw_node(const StringName &p_node); | ||||||
|  | 
 | ||||||
|  | 	AcceptDialog *filter_dialog; | ||||||
|  | 	Tree *filter; | ||||||
|  | 
 | ||||||
|  | 	void _draw_cos_line(const Vector2 &p_from, const Vector2 &p_to, const Color &p_color); | ||||||
|  | 	void _update_scrollbars(); | ||||||
|  | 	void _scroll_moved(float); | ||||||
|  | 	void _play_toggled(); | ||||||
|  | 	/*
 | ||||||
|  | 	void _node_param_changed(); | ||||||
|  | 	void _node_add_callback(); | ||||||
|  | 	void _node_add(VisualServer::AnimationTreeNodeType p_type); | ||||||
|  | 	void _node_edit_property(const StringName& p_node); | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | 	void _master_anim_menu_item(int p_item); | ||||||
|  | 	void _node_menu_item(int p_item); | ||||||
|  | 	void _add_menu_item(int p_item); | ||||||
|  | 
 | ||||||
|  | 	void _filter_edited(); | ||||||
|  | 	void _find_paths_for_filter(const StringName &p_node, Set<String> &paths); | ||||||
|  | 	void _edit_filters(); | ||||||
|  | 
 | ||||||
|  | 	void _edit_oneshot_start(); | ||||||
|  | 	void _edit_dialog_animation_changed(); | ||||||
|  | 	void _edit_dialog_edit_animation(); | ||||||
|  | 	void _edit_dialog_changeds(String); | ||||||
|  | 	void _edit_dialog_changede(String); | ||||||
|  | 	void _edit_dialog_changedf(float); | ||||||
|  | 	void _edit_dialog_changed(); | ||||||
|  | 	void _dialog_changed() const; | ||||||
|  | 	ClickType _locate_click(const Point2 &p_click, StringName *p_node_id, int *p_slot_index) const; | ||||||
|  | 	Point2 _get_slot_pos(const StringName &p_node_id, bool p_input, int p_slot); | ||||||
|  | 
 | ||||||
|  | 	StringName _add_node(int p_item); | ||||||
|  | 	void _file_dialog_selected(String p_path); | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  | 	void _notification(int p_what); | ||||||
|  | 	void _gui_input(Ref<InputEvent> p_event); | ||||||
|  | 	static void _bind_methods(); | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  | 	virtual Size2 get_minimum_size() const; | ||||||
|  | 	void edit(AnimationTreePlayer *p_anim_tree); | ||||||
|  | 	AnimationTreePlayerEditor(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class AnimationTreePlayerEditorPlugin : public EditorPlugin { | ||||||
|  | 
 | ||||||
|  | 	GDCLASS(AnimationTreePlayerEditorPlugin, EditorPlugin); | ||||||
|  | 
 | ||||||
|  | 	AnimationTreePlayerEditor *anim_tree_editor; | ||||||
|  | 	EditorNode *editor; | ||||||
|  | 	Button *button; | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  | 	virtual String get_name() const { return "AnimTree"; } | ||||||
|  | 	bool has_main_screen() const { return false; } | ||||||
|  | 	virtual void edit(Object *p_object); | ||||||
|  | 	virtual bool handles(Object *p_object) const; | ||||||
|  | 	virtual void make_visible(bool p_visible); | ||||||
|  | 
 | ||||||
|  | 	AnimationTreePlayerEditorPlugin(EditorNode *p_node); | ||||||
|  | 	~AnimationTreePlayerEditorPlugin(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif // ANIMATION_TREE_EDITOR_PLUGIN_H
 | ||||||
|  | @ -1394,13 +1394,9 @@ void KinematicBody::_bind_methods() { | ||||||
| 	ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody::get_slide_count); | 	ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody::get_slide_count); | ||||||
| 	ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody::_get_slide_collision); | 	ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody::_get_slide_collision); | ||||||
| 
 | 
 | ||||||
| 	ADD_GROUP("Axis Lock", "axis_lock_"); | 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_x", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_X); | ||||||
| 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_X); | 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_y", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Y); | ||||||
| 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Y); | 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_z", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Z); | ||||||
| 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Z); |  | ||||||
| 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_X); |  | ||||||
| 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_Y); |  | ||||||
| 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_Z); |  | ||||||
| 
 | 
 | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); | 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,12 +1,15 @@ | ||||||
| #include "animation_blend_space_1d.h" | #include "animation_blend_space_1d.h" | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendSpace1D::set_tree(AnimationTree *p_player) { |  | ||||||
| 
 | 
 | ||||||
| 	AnimationRootNode::set_tree(p_player); | void AnimationNodeBlendSpace1D::get_parameter_list(List<PropertyInfo> *r_list) const { | ||||||
|  | 	r_list->push_back(PropertyInfo(Variant::REAL,blend_position)); | ||||||
|  | } | ||||||
|  | Variant AnimationNodeBlendSpace1D::get_parameter_default_value(const StringName &p_parameter) const { | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 	for (int i = 0; i < blend_points_used; i++) { | Ref<AnimationNode> AnimationNodeBlendSpace1D::get_child_by_name(const StringName &p_name) { | ||||||
| 		blend_points[i].node->set_tree(p_player); | 	return get_blend_point_node(p_name.operator String().to_int()); | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &property) const { | void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &property) const { | ||||||
|  | @ -20,6 +23,10 @@ void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &property) const | ||||||
| 	AnimationRootNode::_validate_property(property); | 	AnimationRootNode::_validate_property(property); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void AnimationNodeBlendSpace1D::_tree_changed() { | ||||||
|  | 	emit_signal("tree_changed"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void AnimationNodeBlendSpace1D::_bind_methods() { | 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("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("set_blend_point_position", "point", "pos"), &AnimationNodeBlendSpace1D::set_blend_point_position); | ||||||
|  | @ -38,30 +45,37 @@ void AnimationNodeBlendSpace1D::_bind_methods() { | ||||||
| 	ClassDB::bind_method(D_METHOD("set_snap", "snap"), &AnimationNodeBlendSpace1D::set_snap); | 	ClassDB::bind_method(D_METHOD("set_snap", "snap"), &AnimationNodeBlendSpace1D::set_snap); | ||||||
| 	ClassDB::bind_method(D_METHOD("get_snap"), &AnimationNodeBlendSpace1D::get_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("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("get_value_label"), &AnimationNodeBlendSpace1D::get_value_label); | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("_add_blend_point", "index", "node"), &AnimationNodeBlendSpace1D::_add_blend_point); | 	ClassDB::bind_method(D_METHOD("_add_blend_point", "index", "node"), &AnimationNodeBlendSpace1D::_add_blend_point); | ||||||
| 
 | 
 | ||||||
|  | 	ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeBlendSpace1D::_tree_changed); | ||||||
|  | 
 | ||||||
| 	for (int i = 0; i < MAX_BLEND_POINTS; i++) { | 	for (int i = 0; i < MAX_BLEND_POINTS; i++) { | ||||||
| 		ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "_add_blend_point", "get_blend_point_node", i); | 		ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_add_blend_point", "get_blend_point_node", i); | ||||||
| 		ADD_PROPERTYI(PropertyInfo(Variant::REAL, "blend_point_" + itos(i) + "/pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_blend_point_position", "get_blend_point_position", i); | 		ADD_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, "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, "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, "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"); | 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "value_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_value_label", "get_value_label"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void AnimationNodeBlendSpace1D::get_child_nodes(List<ChildNode> *r_child_nodes) { | ||||||
|  | 	for(int i=0;i<blend_points_used;i++) { | ||||||
|  | 		ChildNode cn; | ||||||
|  | 		cn.name=itos(i); | ||||||
|  | 		cn.node=blend_points[i].node; | ||||||
|  | 		r_child_nodes->push_back(cn); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void AnimationNodeBlendSpace1D::add_blend_point(const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index) { | 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(blend_points_used >= MAX_BLEND_POINTS); | ||||||
| 	ERR_FAIL_COND(p_node.is_null()); | 	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); | 	ERR_FAIL_COND(p_at_index < -1 || p_at_index > blend_points_used); | ||||||
| 
 | 
 | ||||||
| 	if (p_at_index == -1 || p_at_index == blend_points_used) { | 	if (p_at_index == -1 || p_at_index == blend_points_used) { | ||||||
|  | @ -75,10 +89,12 @@ void AnimationNodeBlendSpace1D::add_blend_point(const Ref<AnimationRootNode> &p_ | ||||||
| 	blend_points[p_at_index].node = p_node; | 	blend_points[p_at_index].node = p_node; | ||||||
| 	blend_points[p_at_index].position = p_position; | 	blend_points[p_at_index].position = p_position; | ||||||
| 
 | 
 | ||||||
| 	blend_points[p_at_index].node->set_parent(this); | 	blend_points[p_at_index].node->connect("tree_changed",this,"_tree_changed",varray(),CONNECT_REFERENCE_COUNTED); | ||||||
| 	blend_points[p_at_index].node->set_tree(get_tree()); |  | ||||||
| 
 | 
 | ||||||
| 	blend_points_used++; | 	blend_points_used++; | ||||||
|  | 	emit_signal("tree_changed"); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendSpace1D::set_blend_point_position(int p_point, float p_position) { | void AnimationNodeBlendSpace1D::set_blend_point_position(int p_point, float p_position) { | ||||||
|  | @ -92,13 +108,14 @@ void AnimationNodeBlendSpace1D::set_blend_point_node(int p_point, const Ref<Anim | ||||||
| 	ERR_FAIL_COND(p_node.is_null()); | 	ERR_FAIL_COND(p_node.is_null()); | ||||||
| 
 | 
 | ||||||
| 	if (blend_points[p_point].node.is_valid()) { | 	if (blend_points[p_point].node.is_valid()) { | ||||||
| 		blend_points[p_point].node->set_parent(NULL); | 		blend_points[p_point].node->disconnect("tree_changed",this,"_tree_changed"); | ||||||
| 		blend_points[p_point].node->set_tree(NULL); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	blend_points[p_point].node = p_node; | 	blend_points[p_point].node = p_node; | ||||||
| 	blend_points[p_point].node->set_parent(this); | 	blend_points[p_point].node->connect("tree_changed",this,"_tree_changed",varray(),CONNECT_REFERENCE_COUNTED); | ||||||
| 	blend_points[p_point].node->set_tree(get_tree()); | 
 | ||||||
|  | 	emit_signal("tree_changed"); | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| float AnimationNodeBlendSpace1D::get_blend_point_position(int p_point) const { | float AnimationNodeBlendSpace1D::get_blend_point_position(int p_point) const { | ||||||
|  | @ -114,14 +131,16 @@ Ref<AnimationRootNode> AnimationNodeBlendSpace1D::get_blend_point_node(int p_poi | ||||||
| void AnimationNodeBlendSpace1D::remove_blend_point(int p_point) { | void AnimationNodeBlendSpace1D::remove_blend_point(int p_point) { | ||||||
| 	ERR_FAIL_INDEX(p_point, blend_points_used); | 	ERR_FAIL_INDEX(p_point, blend_points_used); | ||||||
| 
 | 
 | ||||||
| 	blend_points[p_point].node->set_parent(NULL); | 	blend_points[p_point].node->disconnect("tree_changed",this,"_tree_changed"); | ||||||
| 	blend_points[p_point].node->set_tree(NULL); |  | ||||||
| 
 | 
 | ||||||
| 	for (int i = p_point; i < blend_points_used - 1; i++) { | 	for (int i = p_point; i < blend_points_used - 1; i++) { | ||||||
| 		blend_points[i] = blend_points[i + 1]; | 		blend_points[i] = blend_points[i + 1]; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| 	blend_points_used--; | 	blend_points_used--; | ||||||
|  | 	emit_signal("tree_changed"); | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int AnimationNodeBlendSpace1D::get_blend_point_count() const { | int AnimationNodeBlendSpace1D::get_blend_point_count() const { | ||||||
|  | @ -161,13 +180,6 @@ float AnimationNodeBlendSpace1D::get_snap() const { | ||||||
| 	return snap; | 	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) { | void AnimationNodeBlendSpace1D::set_value_label(const String &p_label) { | ||||||
| 	value_label = p_label; | 	value_label = p_label; | ||||||
|  | @ -191,11 +203,14 @@ float AnimationNodeBlendSpace1D::process(float p_time, bool p_seek) { | ||||||
| 		return 0.0; | 		return 0.0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| 	if (blend_points_used == 1) { | 	if (blend_points_used == 1) { | ||||||
| 		// only one point available, just play that animation
 | 		// only one point available, just play that animation
 | ||||||
| 		return blend_node(blend_points[0].node, p_time, p_seek, 1.0, FILTER_IGNORE, false); | 		return blend_node(blend_points[0].name,blend_points[0].node, p_time, p_seek, 1.0, FILTER_IGNORE, false); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	float blend_pos = get_parameter(blend_position); | ||||||
|  | 
 | ||||||
| 	float weights[MAX_BLEND_POINTS] = {}; | 	float weights[MAX_BLEND_POINTS] = {}; | ||||||
| 
 | 
 | ||||||
| 	int point_lower = -1; | 	int point_lower = -1; | ||||||
|  | @ -262,7 +277,7 @@ float AnimationNodeBlendSpace1D::process(float p_time, bool p_seek) { | ||||||
| 	float max_time_remaining = 0.0; | 	float max_time_remaining = 0.0; | ||||||
| 
 | 
 | ||||||
| 	for (int i = 0; i < blend_points_used; i++) { | 	for (int i = 0; i < blend_points_used; i++) { | ||||||
| 		float remaining = blend_node(blend_points[i].node, p_time, p_seek, weights[i], FILTER_IGNORE, false); | 		float remaining = blend_node(blend_points[i].name,blend_points[i].node, p_time, p_seek, weights[i], FILTER_IGNORE, false); | ||||||
| 
 | 
 | ||||||
| 		max_time_remaining = MAX(max_time_remaining, remaining); | 		max_time_remaining = MAX(max_time_remaining, remaining); | ||||||
| 	} | 	} | ||||||
|  | @ -276,18 +291,19 @@ String AnimationNodeBlendSpace1D::get_caption() const { | ||||||
| 
 | 
 | ||||||
| AnimationNodeBlendSpace1D::AnimationNodeBlendSpace1D() { | AnimationNodeBlendSpace1D::AnimationNodeBlendSpace1D() { | ||||||
| 
 | 
 | ||||||
|  | 	for(int i=0;i<MAX_BLEND_POINTS;i++) { | ||||||
|  | 		blend_points[i].name=itos(i); | ||||||
|  | 	} | ||||||
| 	blend_points_used = 0; | 	blend_points_used = 0; | ||||||
| 	max_space = 1; | 	max_space = 1; | ||||||
| 	min_space = -1; | 	min_space = -1; | ||||||
| 
 | 
 | ||||||
| 	snap = 0.1; | 	snap = 0.1; | ||||||
| 	value_label = "value"; | 	value_label = "value"; | ||||||
|  | 
 | ||||||
|  | 	blend_position="blend_position"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AnimationNodeBlendSpace1D::~AnimationNodeBlendSpace1D() { | 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()); |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode { | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	struct BlendPoint { | 	struct BlendPoint { | ||||||
|  | 		StringName name; | ||||||
| 		Ref<AnimationRootNode> node; | 		Ref<AnimationRootNode> node; | ||||||
| 		float position; | 		float position; | ||||||
| 	}; | 	}; | ||||||
|  | @ -18,8 +19,6 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode { | ||||||
| 	BlendPoint blend_points[MAX_BLEND_POINTS]; | 	BlendPoint blend_points[MAX_BLEND_POINTS]; | ||||||
| 	int blend_points_used; | 	int blend_points_used; | ||||||
| 
 | 
 | ||||||
| 	float blend_pos; |  | ||||||
| 
 |  | ||||||
| 	float max_space; | 	float max_space; | ||||||
| 	float min_space; | 	float min_space; | ||||||
| 
 | 
 | ||||||
|  | @ -29,12 +28,21 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode { | ||||||
| 
 | 
 | ||||||
| 	void _add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node); | 	void _add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node); | ||||||
| 
 | 
 | ||||||
|  | 	void _tree_changed(); | ||||||
|  | 
 | ||||||
|  | 	StringName blend_position; | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
| 	virtual void _validate_property(PropertyInfo &property) const; | 	virtual void _validate_property(PropertyInfo &property) const; | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 	virtual void set_tree(AnimationTree *p_player); | 
 | ||||||
|  | 	virtual void get_parameter_list(List<PropertyInfo> *r_list) const; | ||||||
|  | 	virtual Variant get_parameter_default_value(const StringName &p_parameter) const; | ||||||
|  | 
 | ||||||
|  | 	virtual void get_child_nodes(List<ChildNode> *r_child_nodes); | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 	void add_blend_point(const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index = -1); | 	void 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_position(int p_point, float p_position); | ||||||
|  | @ -54,15 +62,14 @@ public: | ||||||
| 	void set_snap(float p_snap); | 	void set_snap(float p_snap); | ||||||
| 	float get_snap() const; | 	float get_snap() const; | ||||||
| 
 | 
 | ||||||
| 	void set_blend_pos(float p_pos); |  | ||||||
| 	float get_blend_pos() const; |  | ||||||
| 
 |  | ||||||
| 	void set_value_label(const String &p_label); | 	void set_value_label(const String &p_label); | ||||||
| 	String get_value_label() const; | 	String get_value_label() const; | ||||||
| 
 | 
 | ||||||
| 	float process(float p_time, bool p_seek); | 	float process(float p_time, bool p_seek); | ||||||
| 	String get_caption() const; | 	String get_caption() const; | ||||||
| 
 | 
 | ||||||
|  | 	Ref<AnimationNode> get_child_by_name(const StringName &p_name); | ||||||
|  | 
 | ||||||
| 	AnimationNodeBlendSpace1D(); | 	AnimationNodeBlendSpace1D(); | ||||||
| 	~AnimationNodeBlendSpace1D(); | 	~AnimationNodeBlendSpace1D(); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -1,18 +1,27 @@ | ||||||
| #include "animation_blend_space_2d.h" | #include "animation_blend_space_2d.h" | ||||||
| #include "math/delaunay.h" | #include "math/delaunay.h" | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendSpace2D::set_tree(AnimationTree *p_player) { |  | ||||||
| 	AnimationRootNode::set_tree(p_player); |  | ||||||
| 
 | 
 | ||||||
| 	for (int i = 0; i < blend_points_used; i++) { | void AnimationNodeBlendSpace2D::get_parameter_list(List<PropertyInfo> *r_list) const { | ||||||
| 		blend_points[i].node->set_tree(p_player); | 	r_list->push_back(PropertyInfo(Variant::VECTOR2,blend_position)); | ||||||
|  | } | ||||||
|  | Variant AnimationNodeBlendSpace2D::get_parameter_default_value(const StringName &p_parameter) const { | ||||||
|  | 	return Vector2(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void AnimationNodeBlendSpace2D::get_child_nodes(List<ChildNode> *r_child_nodes) { | ||||||
|  | 	for(int i=0;i<blend_points_used;i++) { | ||||||
|  | 		ChildNode cn; | ||||||
|  | 		cn.name=itos(i); | ||||||
|  | 		cn.node=blend_points[i].node; | ||||||
|  | 		r_child_nodes->push_back(cn); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendSpace2D::add_blend_point(const Ref<AnimationRootNode> &p_node, const Vector2 &p_position, int p_at_index) { | 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(blend_points_used >= MAX_BLEND_POINTS); | ||||||
| 	ERR_FAIL_COND(p_node.is_null()); | 	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); | 	ERR_FAIL_COND(p_at_index < -1 || p_at_index > blend_points_used); | ||||||
| 
 | 
 | ||||||
| 	if (p_at_index == -1 || p_at_index == blend_points_used) { | 	if (p_at_index == -1 || p_at_index == blend_points_used) { | ||||||
|  | @ -32,13 +41,15 @@ void AnimationNodeBlendSpace2D::add_blend_point(const Ref<AnimationRootNode> &p_ | ||||||
| 	blend_points[p_at_index].node = p_node; | 	blend_points[p_at_index].node = p_node; | ||||||
| 	blend_points[p_at_index].position = p_position; | 	blend_points[p_at_index].position = p_position; | ||||||
| 
 | 
 | ||||||
| 	blend_points[p_at_index].node->set_parent(this); | 	blend_points[p_at_index].node->connect("tree_changed",this,"_tree_changed",varray(),CONNECT_REFERENCE_COUNTED); | ||||||
| 	blend_points[p_at_index].node->set_tree(get_tree()); |  | ||||||
| 	blend_points_used++; | 	blend_points_used++; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| 	if (auto_triangles) { | 	if (auto_triangles) { | ||||||
| 		trianges_dirty = true; | 		trianges_dirty = true; | ||||||
| 	} | 	} | ||||||
|  | 	emit_signal("tree_changed"); | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendSpace2D::set_blend_point_position(int p_point, const Vector2 &p_position) { | void AnimationNodeBlendSpace2D::set_blend_point_position(int p_point, const Vector2 &p_position) { | ||||||
|  | @ -53,12 +64,13 @@ void AnimationNodeBlendSpace2D::set_blend_point_node(int p_point, const Ref<Anim | ||||||
| 	ERR_FAIL_COND(p_node.is_null()); | 	ERR_FAIL_COND(p_node.is_null()); | ||||||
| 
 | 
 | ||||||
| 	if (blend_points[p_point].node.is_valid()) { | 	if (blend_points[p_point].node.is_valid()) { | ||||||
| 		blend_points[p_point].node->set_parent(NULL); | 		blend_points[p_point].node->disconnect("tree_changed",this,"_tree_changed"); | ||||||
| 		blend_points[p_point].node->set_tree(NULL); |  | ||||||
| 	} | 	} | ||||||
| 	blend_points[p_point].node = p_node; | 	blend_points[p_point].node = p_node; | ||||||
| 	blend_points[p_point].node->set_parent(this); | 	blend_points[p_point].node->connect("tree_changed",this,"_tree_changed",varray(),CONNECT_REFERENCE_COUNTED); | ||||||
| 	blend_points[p_point].node->set_tree(get_tree()); | 
 | ||||||
|  | 	emit_signal("tree_changed"); | ||||||
|  | 
 | ||||||
| } | } | ||||||
| Vector2 AnimationNodeBlendSpace2D::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()); | 	ERR_FAIL_INDEX_V(p_point, blend_points_used, Vector2()); | ||||||
|  | @ -71,8 +83,7 @@ Ref<AnimationRootNode> AnimationNodeBlendSpace2D::get_blend_point_node(int p_poi | ||||||
| void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) { | void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) { | ||||||
| 	ERR_FAIL_INDEX(p_point, blend_points_used); | 	ERR_FAIL_INDEX(p_point, blend_points_used); | ||||||
| 
 | 
 | ||||||
| 	blend_points[p_point].node->set_parent(NULL); | 	blend_points[p_point].node->disconnect("tree_changed",this,"_tree_changed"); | ||||||
| 	blend_points[p_point].node->set_tree(NULL); |  | ||||||
| 
 | 
 | ||||||
| 	for (int i = 0; i < triangles.size(); i++) { | 	for (int i = 0; i < triangles.size(); i++) { | ||||||
| 		bool erase = false; | 		bool erase = false; | ||||||
|  | @ -95,6 +106,8 @@ void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) { | ||||||
| 		blend_points[i] = blend_points[i + 1]; | 		blend_points[i] = blend_points[i + 1]; | ||||||
| 	} | 	} | ||||||
| 	blend_points_used--; | 	blend_points_used--; | ||||||
|  | 	emit_signal("tree_changed"); | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int AnimationNodeBlendSpace2D::get_blend_point_count() const { | int AnimationNodeBlendSpace2D::get_blend_point_count() const { | ||||||
|  | @ -217,13 +230,6 @@ Vector2 AnimationNodeBlendSpace2D::get_snap() const { | ||||||
| 	return snap; | 	return snap; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendSpace2D::set_blend_position(const Vector2 &p_pos) { |  | ||||||
| 	blend_pos = p_pos; |  | ||||||
| } |  | ||||||
| Vector2 AnimationNodeBlendSpace2D::get_blend_position() const { |  | ||||||
| 	return blend_pos; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void AnimationNodeBlendSpace2D::set_x_label(const String &p_label) { | void AnimationNodeBlendSpace2D::set_x_label(const String &p_label) { | ||||||
| 	x_label = p_label; | 	x_label = p_label; | ||||||
| } | } | ||||||
|  | @ -381,6 +387,8 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) { | ||||||
| 
 | 
 | ||||||
| 	_update_triangles(); | 	_update_triangles(); | ||||||
| 
 | 
 | ||||||
|  | 	Vector2 blend_pos = get_parameter(blend_position); | ||||||
|  | 
 | ||||||
| 	if (triangles.size() == 0) | 	if (triangles.size() == 0) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
|  | @ -443,7 +451,7 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) { | ||||||
| 		for (int j = 0; j < 3; j++) { | 		for (int j = 0; j < 3; j++) { | ||||||
| 			if (i == triangle_points[j]) { | 			if (i == triangle_points[j]) { | ||||||
| 				//blend with the given weight
 | 				//blend with the given weight
 | ||||||
| 				float t = blend_node(blend_points[i].node, p_time, p_seek, blend_weights[j], FILTER_IGNORE, false); | 				float t = blend_node(blend_points[i].name,blend_points[i].node, p_time, p_seek, blend_weights[j], FILTER_IGNORE, false); | ||||||
| 				if (first || t < mind) { | 				if (first || t < mind) { | ||||||
| 					mind = t; | 					mind = t; | ||||||
| 					first = false; | 					first = false; | ||||||
|  | @ -455,7 +463,7 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) { | ||||||
| 
 | 
 | ||||||
| 		if (!found) { | 		if (!found) { | ||||||
| 			//ignore
 | 			//ignore
 | ||||||
| 			blend_node(blend_points[i].node, p_time, p_seek, 0, FILTER_IGNORE, false); | 			blend_node(blend_points[i].name,blend_points[i].node, p_time, p_seek, 0, FILTER_IGNORE, false); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return mind; | 	return mind; | ||||||
|  | @ -483,10 +491,19 @@ void AnimationNodeBlendSpace2D::set_auto_triangles(bool p_enable) { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| bool AnimationNodeBlendSpace2D::get_auto_triangles() const { | bool AnimationNodeBlendSpace2D::get_auto_triangles() const { | ||||||
| 	return auto_triangles; | 	return auto_triangles; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Ref<AnimationNode> AnimationNodeBlendSpace2D::get_child_by_name(const StringName &p_name) { | ||||||
|  | 	return get_blend_point_node(p_name.operator String().to_int()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AnimationNodeBlendSpace2D::_tree_changed() { | ||||||
|  | 	emit_signal("tree_changed"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void AnimationNodeBlendSpace2D::_bind_methods() { | void AnimationNodeBlendSpace2D::_bind_methods() { | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace2D::add_blend_point, DEFVAL(-1)); | 	ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace2D::add_blend_point, DEFVAL(-1)); | ||||||
|  | @ -511,9 +528,6 @@ void AnimationNodeBlendSpace2D::_bind_methods() { | ||||||
| 	ClassDB::bind_method(D_METHOD("set_snap", "snap"), &AnimationNodeBlendSpace2D::set_snap); | 	ClassDB::bind_method(D_METHOD("set_snap", "snap"), &AnimationNodeBlendSpace2D::set_snap); | ||||||
| 	ClassDB::bind_method(D_METHOD("get_snap"), &AnimationNodeBlendSpace2D::get_snap); | 	ClassDB::bind_method(D_METHOD("get_snap"), &AnimationNodeBlendSpace2D::get_snap); | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("set_blend_position", "pos"), &AnimationNodeBlendSpace2D::set_blend_position); |  | ||||||
| 	ClassDB::bind_method(D_METHOD("get_blend_position"), &AnimationNodeBlendSpace2D::get_blend_position); |  | ||||||
| 
 |  | ||||||
| 	ClassDB::bind_method(D_METHOD("set_x_label", "text"), &AnimationNodeBlendSpace2D::set_x_label); | 	ClassDB::bind_method(D_METHOD("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("get_x_label"), &AnimationNodeBlendSpace2D::get_x_label); | ||||||
| 
 | 
 | ||||||
|  | @ -528,10 +542,12 @@ void AnimationNodeBlendSpace2D::_bind_methods() { | ||||||
| 	ClassDB::bind_method(D_METHOD("set_auto_triangles", "enable"), &AnimationNodeBlendSpace2D::set_auto_triangles); | 	ClassDB::bind_method(D_METHOD("set_auto_triangles", "enable"), &AnimationNodeBlendSpace2D::set_auto_triangles); | ||||||
| 	ClassDB::bind_method(D_METHOD("get_auto_triangles"), &AnimationNodeBlendSpace2D::get_auto_triangles); | 	ClassDB::bind_method(D_METHOD("get_auto_triangles"), &AnimationNodeBlendSpace2D::get_auto_triangles); | ||||||
| 
 | 
 | ||||||
|  | 	ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeBlendSpace2D::_tree_changed); | ||||||
|  | 
 | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_auto_triangles", "get_auto_triangles"); | 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_auto_triangles", "get_auto_triangles"); | ||||||
| 
 | 
 | ||||||
| 	for (int i = 0; i < MAX_BLEND_POINTS; i++) { | 	for (int i = 0; i < MAX_BLEND_POINTS; i++) { | ||||||
| 		ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "_add_blend_point", "get_blend_point_node", i); | 		ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_add_blend_point", "get_blend_point_node", i); | ||||||
| 		ADD_PROPERTYI(PropertyInfo(Variant::VECTOR2, "blend_point_" + itos(i) + "/pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_blend_point_position", "get_blend_point_position", i); | 		ADD_PROPERTYI(PropertyInfo(Variant::VECTOR2, "blend_point_" + itos(i) + "/pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_blend_point_position", "get_blend_point_position", i); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -540,13 +556,15 @@ void AnimationNodeBlendSpace2D::_bind_methods() { | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "min_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_min_space", "get_min_space"); | 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "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, "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, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_snap", "get_snap"); | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "blend_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_blend_position", "get_blend_position"); |  | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "x_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_x_label", "get_x_label"); | 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "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"); | 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "y_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_y_label", "get_y_label"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() { | AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() { | ||||||
| 
 | 
 | ||||||
|  | 	for(int i=0;i<MAX_BLEND_POINTS;i++) { | ||||||
|  | 		blend_points[i].name=itos(i); | ||||||
|  | 	} | ||||||
| 	auto_triangles = true; | 	auto_triangles = true; | ||||||
| 	blend_points_used = 0; | 	blend_points_used = 0; | ||||||
| 	max_space = Vector2(1, 1); | 	max_space = Vector2(1, 1); | ||||||
|  | @ -555,12 +573,10 @@ AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() { | ||||||
| 	x_label = "x"; | 	x_label = "x"; | ||||||
| 	y_label = "y"; | 	y_label = "y"; | ||||||
| 	trianges_dirty = false; | 	trianges_dirty = false; | ||||||
|  | 	blend_position = "blend_position"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AnimationNodeBlendSpace2D::~AnimationNodeBlendSpace2D() { | AnimationNodeBlendSpace2D::~AnimationNodeBlendSpace2D() { | ||||||
| 
 | 
 | ||||||
| 	for (int i = 0; i < blend_points_used; i++) { | 
 | ||||||
| 		blend_points[i].node->set_parent(this); |  | ||||||
| 		blend_points[i].node->set_tree(get_tree()); |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ class AnimationNodeBlendSpace2D : public AnimationRootNode { | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	struct BlendPoint { | 	struct BlendPoint { | ||||||
|  | 		StringName name; | ||||||
| 		Ref<AnimationRootNode> node; | 		Ref<AnimationRootNode> node; | ||||||
| 		Vector2 position; | 		Vector2 position; | ||||||
| 	}; | 	}; | ||||||
|  | @ -24,7 +25,7 @@ class AnimationNodeBlendSpace2D : public AnimationRootNode { | ||||||
| 
 | 
 | ||||||
| 	Vector<BlendTriangle> triangles; | 	Vector<BlendTriangle> triangles; | ||||||
| 
 | 
 | ||||||
| 	Vector2 blend_pos; | 	StringName blend_position; | ||||||
| 	Vector2 max_space; | 	Vector2 max_space; | ||||||
| 	Vector2 min_space; | 	Vector2 min_space; | ||||||
| 	Vector2 snap; | 	Vector2 snap; | ||||||
|  | @ -42,12 +43,19 @@ class AnimationNodeBlendSpace2D : public AnimationRootNode { | ||||||
| 
 | 
 | ||||||
| 	void _update_triangles(); | 	void _update_triangles(); | ||||||
| 
 | 
 | ||||||
|  | 	void _tree_changed(); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
| 	virtual void _validate_property(PropertyInfo &property) const; | 	virtual void _validate_property(PropertyInfo &property) const; | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 	virtual void set_tree(AnimationTree *p_player); | 
 | ||||||
|  | 	virtual void get_parameter_list(List<PropertyInfo> *r_list) const; | ||||||
|  | 	virtual Variant get_parameter_default_value(const StringName &p_parameter) const; | ||||||
|  | 
 | ||||||
|  | 	virtual void get_child_nodes(List<ChildNode> *r_child_nodes); | ||||||
| 
 | 
 | ||||||
| 	void add_blend_point(const Ref<AnimationRootNode> &p_node, const Vector2 &p_position, int p_at_index = -1); | 	void 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_position(int p_point, const Vector2 &p_position); | ||||||
|  | @ -72,9 +80,6 @@ public: | ||||||
| 	void set_snap(const Vector2 &p_snap); | 	void set_snap(const Vector2 &p_snap); | ||||||
| 	Vector2 get_snap() const; | 	Vector2 get_snap() const; | ||||||
| 
 | 
 | ||||||
| 	void set_blend_position(const Vector2 &p_pos); |  | ||||||
| 	Vector2 get_blend_position() const; |  | ||||||
| 
 |  | ||||||
| 	void set_x_label(const String &p_label); | 	void set_x_label(const String &p_label); | ||||||
| 	String get_x_label() const; | 	String get_x_label() const; | ||||||
| 
 | 
 | ||||||
|  | @ -89,6 +94,8 @@ public: | ||||||
| 	void set_auto_triangles(bool p_enable); | 	void set_auto_triangles(bool p_enable); | ||||||
| 	bool get_auto_triangles() const; | 	bool get_auto_triangles() const; | ||||||
| 
 | 
 | ||||||
|  | 	virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name); | ||||||
|  | 
 | ||||||
| 	AnimationNodeBlendSpace2D(); | 	AnimationNodeBlendSpace2D(); | ||||||
| 	~AnimationNodeBlendSpace2D(); | 	~AnimationNodeBlendSpace2D(); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| 
 | 
 | ||||||
| void AnimationNodeAnimation::set_animation(const StringName &p_name) { | void AnimationNodeAnimation::set_animation(const StringName &p_name) { | ||||||
| 	animation = p_name; | 	animation = p_name; | ||||||
|  | 	_change_notify("animation"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| StringName AnimationNodeAnimation::get_animation() const { | StringName AnimationNodeAnimation::get_animation() const { | ||||||
|  | @ -13,43 +14,36 @@ float AnimationNodeAnimation::get_playback_time() const { | ||||||
| 	return time; | 	return time; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Vector<String> (*AnimationNodeAnimation::get_editable_animation_list)() = NULL; | ||||||
|  | 
 | ||||||
| void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const { | void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const { | ||||||
| 
 | 
 | ||||||
| 	if (property.name == "animation") { | 	if (property.name == "animation" && get_editable_animation_list) { | ||||||
| 		AnimationTree *gp = get_tree(); | 		Vector<String> names = get_editable_animation_list(); | ||||||
| 		if (gp && gp->has_node(gp->get_animation_player())) { |  | ||||||
| 			AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player())); |  | ||||||
| 			if (ap) { |  | ||||||
| 				List<StringName> names; |  | ||||||
| 				ap->get_animation_list(&names); |  | ||||||
| 		String anims; | 		String anims; | ||||||
| 				for (List<StringName>::Element *E = names.front(); E; E = E->next()) { | 		for (int i = 0; i < names.size(); i++) { | ||||||
| 					if (E != names.front()) { | 
 | ||||||
|  | 			if (i > 0) { | ||||||
| 				anims += ","; | 				anims += ","; | ||||||
| 			} | 			} | ||||||
| 					anims += String(E->get()); | 			anims += String(names[i]); | ||||||
| 		} | 		} | ||||||
| 		if (anims != String()) { | 		if (anims != String()) { | ||||||
| 			property.hint = PROPERTY_HINT_ENUM; | 			property.hint = PROPERTY_HINT_ENUM; | ||||||
| 			property.hint_string = anims; | 			property.hint_string = anims; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	AnimationRootNode::_validate_property(property); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| float AnimationNodeAnimation::process(float p_time, bool p_seek) { | float AnimationNodeAnimation::process(float p_time, bool p_seek) { | ||||||
| 
 | 
 | ||||||
| 	AnimationPlayer *ap = get_player(); | 	AnimationPlayer *ap = state->player; | ||||||
| 	ERR_FAIL_COND_V(!ap, 0); | 	ERR_FAIL_COND_V(!ap, 0); | ||||||
| 
 | 
 | ||||||
| 	Ref<Animation> anim = ap->get_animation(animation); | 	if (!ap->has_animation(animation)) { | ||||||
| 	if (!anim.is_valid()) { |  | ||||||
| 
 | 
 | ||||||
| 		Ref<AnimationNodeBlendTree> tree = get_parent(); | 		AnimationNodeBlendTree *tree = Object::cast_to<AnimationNodeBlendTree>(parent); | ||||||
| 		if (tree.is_valid()) { | 		if (tree) { | ||||||
| 			String name = tree->get_node_name(Ref<AnimationNodeAnimation>(this)); | 			String name = tree->get_node_name(Ref<AnimationNodeAnimation>(this)); | ||||||
| 			make_invalid(vformat(RTR("On BlendTree node '%s', animation not found: '%s'"), name, animation)); | 			make_invalid(vformat(RTR("On BlendTree node '%s', animation not found: '%s'"), name, animation)); | ||||||
| 
 | 
 | ||||||
|  | @ -60,6 +54,8 @@ float AnimationNodeAnimation::process(float p_time, bool p_seek) { | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	Ref<Animation> anim = ap->get_animation(animation); | ||||||
|  | 
 | ||||||
| 	if (p_seek) { | 	if (p_seek) { | ||||||
| 		time = p_time; | 		time = p_time; | ||||||
| 		step = 0; | 		step = 0; | ||||||
|  | @ -108,6 +104,20 @@ AnimationNodeAnimation::AnimationNodeAnimation() { | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////
 | ||||||
| 
 | 
 | ||||||
|  | void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const { | ||||||
|  | 	r_list->push_back(PropertyInfo(Variant::BOOL, active)); | ||||||
|  | 	r_list->push_back(PropertyInfo(Variant::BOOL, prev_active, PROPERTY_HINT_NONE, "", 0)); | ||||||
|  | 	r_list->push_back(PropertyInfo(Variant::REAL, time, PROPERTY_HINT_NONE, "", 0)); | ||||||
|  | 	r_list->push_back(PropertyInfo(Variant::REAL, remaining, PROPERTY_HINT_NONE, "", 0)); | ||||||
|  | } | ||||||
|  | Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_parameter) const { | ||||||
|  | 	if (p_parameter == active || p_parameter == prev_active) { | ||||||
|  | 		return false; | ||||||
|  | 	} else { | ||||||
|  | 		return 0.0; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void AnimationNodeOneShot::set_fadein_time(float p_time) { | void AnimationNodeOneShot::set_fadein_time(float p_time) { | ||||||
| 
 | 
 | ||||||
| 	fade_in = p_time; | 	fade_in = p_time; | ||||||
|  | @ -162,18 +172,6 @@ AnimationNodeOneShot::MixMode AnimationNodeOneShot::get_mix_mode() const { | ||||||
| 	return mix; | 	return mix; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeOneShot::start() { |  | ||||||
| 	active = true; |  | ||||||
| 	do_start = true; |  | ||||||
| } |  | ||||||
| void AnimationNodeOneShot::stop() { |  | ||||||
| 	active = false; |  | ||||||
| } |  | ||||||
| bool AnimationNodeOneShot::is_active() const { |  | ||||||
| 
 |  | ||||||
| 	return active; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| String AnimationNodeOneShot::get_caption() const { | String AnimationNodeOneShot::get_caption() const { | ||||||
| 	return "OneShot"; | 	return "OneShot"; | ||||||
| } | } | ||||||
|  | @ -184,8 +182,16 @@ bool AnimationNodeOneShot::has_filter() const { | ||||||
| 
 | 
 | ||||||
| float AnimationNodeOneShot::process(float p_time, bool p_seek) { | float AnimationNodeOneShot::process(float p_time, bool p_seek) { | ||||||
| 
 | 
 | ||||||
|  | 	bool active = get_parameter(this->active); | ||||||
|  | 	bool prev_active = get_parameter(this->prev_active); | ||||||
|  | 	float time = get_parameter(this->time); | ||||||
|  | 	float remaining = get_parameter(this->remaining); | ||||||
|  | 
 | ||||||
| 	if (!active) { | 	if (!active) { | ||||||
| 		//make it as if this node doesn't exist, pass input 0 by.
 | 		//make it as if this node doesn't exist, pass input 0 by.
 | ||||||
|  | 		if (prev_active) { | ||||||
|  | 			set_parameter(this->prev_active, false); | ||||||
|  | 		} | ||||||
| 		return blend_input(0, p_time, p_seek, 1.0, FILTER_IGNORE, !sync); | 		return blend_input(0, p_time, p_seek, 1.0, FILTER_IGNORE, !sync); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -193,9 +199,12 @@ float AnimationNodeOneShot::process(float p_time, bool p_seek) { | ||||||
| 
 | 
 | ||||||
| 	if (p_seek) | 	if (p_seek) | ||||||
| 		time = p_time; | 		time = p_time; | ||||||
|  | 	bool do_start = !prev_active; | ||||||
|  | 
 | ||||||
| 	if (do_start) { | 	if (do_start) { | ||||||
| 		time = 0; | 		time = 0; | ||||||
| 		os_seek = true; | 		os_seek = true; | ||||||
|  | 		set_parameter(this->prev_active, true); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	float blend; | 	float blend; | ||||||
|  | @ -233,9 +242,14 @@ float AnimationNodeOneShot::process(float p_time, bool p_seek) { | ||||||
| 	if (!p_seek) { | 	if (!p_seek) { | ||||||
| 		time += p_time; | 		time += p_time; | ||||||
| 		remaining = os_rem; | 		remaining = os_rem; | ||||||
| 		if (remaining <= 0) | 		if (remaining <= 0) { | ||||||
| 			active = false; | 			set_parameter(this->active, false); | ||||||
|  | 			set_parameter(this->prev_active, false); | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	set_parameter(this->time, time); | ||||||
|  | 	set_parameter(this->remaining, remaining); | ||||||
| 
 | 
 | ||||||
| 	return MAX(main_rem, remaining); | 	return MAX(main_rem, remaining); | ||||||
| } | } | ||||||
|  | @ -269,10 +283,6 @@ void AnimationNodeOneShot::_bind_methods() { | ||||||
| 	ClassDB::bind_method(D_METHOD("set_mix_mode", "mode"), &AnimationNodeOneShot::set_mix_mode); | 	ClassDB::bind_method(D_METHOD("set_mix_mode", "mode"), &AnimationNodeOneShot::set_mix_mode); | ||||||
| 	ClassDB::bind_method(D_METHOD("get_mix_mode"), &AnimationNodeOneShot::get_mix_mode); | 	ClassDB::bind_method(D_METHOD("get_mix_mode"), &AnimationNodeOneShot::get_mix_mode); | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("start"), &AnimationNodeOneShot::start); |  | ||||||
| 	ClassDB::bind_method(D_METHOD("stop"), &AnimationNodeOneShot::stop); |  | ||||||
| 	ClassDB::bind_method(D_METHOD("is_active"), &AnimationNodeOneShot::is_active); |  | ||||||
| 
 |  | ||||||
| 	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeOneShot::set_use_sync); | 	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeOneShot::set_use_sync); | ||||||
| 	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeOneShot::is_using_sync); | 	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeOneShot::is_using_sync); | ||||||
| 
 | 
 | ||||||
|  | @ -297,26 +307,22 @@ AnimationNodeOneShot::AnimationNodeOneShot() { | ||||||
| 	add_input("in"); | 	add_input("in"); | ||||||
| 	add_input("shot"); | 	add_input("shot"); | ||||||
| 
 | 
 | ||||||
| 	time = 0; |  | ||||||
| 	fade_in = 0.1; | 	fade_in = 0.1; | ||||||
| 	fade_out = 0.1; | 	fade_out = 0.1; | ||||||
| 	autorestart = false; | 	autorestart = false; | ||||||
| 	autorestart_delay = 1; | 	autorestart_delay = 1; | ||||||
| 	autorestart_remaining = 0; | 
 | ||||||
| 	mix = MIX_MODE_BLEND; | 	mix = MIX_MODE_BLEND; | ||||||
| 	active = false; |  | ||||||
| 	do_start = false; |  | ||||||
| 	sync = false; | 	sync = false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////
 | ////////////////////////////////////////////////
 | ||||||
| 
 | 
 | ||||||
| void AnimationNodeAdd2::set_amount(float p_amount) { | void AnimationNodeAdd2::get_parameter_list(List<PropertyInfo> *r_list) const { | ||||||
| 	amount = p_amount; | 	r_list->push_back(PropertyInfo(Variant::REAL, add_amount, PROPERTY_HINT_RANGE, "0,1,0.01")); | ||||||
| } | } | ||||||
| 
 | Variant AnimationNodeAdd2::get_parameter_default_value(const StringName &p_parameter) const { | ||||||
| float AnimationNodeAdd2::get_amount() const { | 	return 0; | ||||||
| 	return amount; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| String AnimationNodeAdd2::get_caption() const { | String AnimationNodeAdd2::get_caption() const { | ||||||
|  | @ -339,6 +345,7 @@ bool AnimationNodeAdd2::has_filter() const { | ||||||
| 
 | 
 | ||||||
| float AnimationNodeAdd2::process(float p_time, bool p_seek) { | float AnimationNodeAdd2::process(float p_time, bool p_seek) { | ||||||
| 
 | 
 | ||||||
|  | 	float amount = get_parameter(add_amount); | ||||||
| 	float rem0 = blend_input(0, p_time, p_seek, 1.0, FILTER_IGNORE, !sync); | 	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); | 	blend_input(1, p_time, p_seek, amount, FILTER_PASS, !sync); | ||||||
| 
 | 
 | ||||||
|  | @ -347,32 +354,27 @@ float AnimationNodeAdd2::process(float p_time, bool p_seek) { | ||||||
| 
 | 
 | ||||||
| void AnimationNodeAdd2::_bind_methods() { | void AnimationNodeAdd2::_bind_methods() { | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("set_amount", "amount"), &AnimationNodeAdd2::set_amount); |  | ||||||
| 	ClassDB::bind_method(D_METHOD("get_amount"), &AnimationNodeAdd2::get_amount); |  | ||||||
| 
 |  | ||||||
| 	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeAdd2::set_use_sync); | 	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeAdd2::set_use_sync); | ||||||
| 	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeAdd2::is_using_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"); | 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AnimationNodeAdd2::AnimationNodeAdd2() { | AnimationNodeAdd2::AnimationNodeAdd2() { | ||||||
| 
 | 
 | ||||||
|  | 	add_amount = "add_amount"; | ||||||
| 	add_input("in"); | 	add_input("in"); | ||||||
| 	add_input("add"); | 	add_input("add"); | ||||||
| 	amount = 0; |  | ||||||
| 	sync = false; | 	sync = false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////
 | ////////////////////////////////////////////////
 | ||||||
| 
 | 
 | ||||||
| void AnimationNodeAdd3::set_amount(float p_amount) { | void AnimationNodeAdd3::get_parameter_list(List<PropertyInfo> *r_list) const { | ||||||
| 	amount = p_amount; | 	r_list->push_back(PropertyInfo(Variant::REAL, add_amount, PROPERTY_HINT_RANGE, "-1,1,0.01")); | ||||||
| } | } | ||||||
| 
 | Variant AnimationNodeAdd3::get_parameter_default_value(const StringName &p_parameter) const { | ||||||
| float AnimationNodeAdd3::get_amount() const { | 	return 0; | ||||||
| 	return amount; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| String AnimationNodeAdd3::get_caption() const { | String AnimationNodeAdd3::get_caption() const { | ||||||
|  | @ -395,6 +397,7 @@ bool AnimationNodeAdd3::has_filter() const { | ||||||
| 
 | 
 | ||||||
| float AnimationNodeAdd3::process(float p_time, bool p_seek) { | float AnimationNodeAdd3::process(float p_time, bool p_seek) { | ||||||
| 
 | 
 | ||||||
|  | 	float amount = get_parameter(add_amount); | ||||||
| 	blend_input(0, p_time, p_seek, MAX(0, -amount), FILTER_PASS, !sync); | 	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); | 	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); | 	blend_input(2, p_time, p_seek, MAX(0, amount), FILTER_PASS, !sync); | ||||||
|  | @ -404,39 +407,37 @@ float AnimationNodeAdd3::process(float p_time, bool p_seek) { | ||||||
| 
 | 
 | ||||||
| void AnimationNodeAdd3::_bind_methods() { | 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("set_use_sync", "enable"), &AnimationNodeAdd3::set_use_sync); | ||||||
| 	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeAdd3::is_using_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"); | 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AnimationNodeAdd3::AnimationNodeAdd3() { | AnimationNodeAdd3::AnimationNodeAdd3() { | ||||||
| 
 | 
 | ||||||
|  | 	add_amount = "add_amount"; | ||||||
| 	add_input("-add"); | 	add_input("-add"); | ||||||
| 	add_input("in"); | 	add_input("in"); | ||||||
| 	add_input("+add"); | 	add_input("+add"); | ||||||
| 	amount = 0; |  | ||||||
| 	sync = false; | 	sync = false; | ||||||
| } | } | ||||||
| /////////////////////////////////////////////
 | /////////////////////////////////////////////
 | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlend2::set_amount(float p_amount) { | void AnimationNodeBlend2::get_parameter_list(List<PropertyInfo> *r_list) const { | ||||||
| 	amount = p_amount; | 	r_list->push_back(PropertyInfo(Variant::REAL, blend_amount, PROPERTY_HINT_RANGE, "0,1,0.01")); | ||||||
|  | } | ||||||
|  | Variant AnimationNodeBlend2::get_parameter_default_value(const StringName &p_parameter) const { | ||||||
|  | 	return 0; //for blend amount
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| float AnimationNodeBlend2::get_amount() const { |  | ||||||
| 	return amount; |  | ||||||
| } |  | ||||||
| String AnimationNodeBlend2::get_caption() const { | String AnimationNodeBlend2::get_caption() const { | ||||||
| 	return "Blend2"; | 	return "Blend2"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| float AnimationNodeBlend2::process(float p_time, bool p_seek) { | float AnimationNodeBlend2::process(float p_time, bool p_seek) { | ||||||
| 
 | 
 | ||||||
|  | 	float amount = get_parameter(blend_amount); | ||||||
|  | 
 | ||||||
| 	float rem0 = blend_input(0, p_time, p_seek, 1.0 - amount, FILTER_BLEND, !sync); | 	float rem0 = blend_input(0, p_time, p_seek, 1.0 - amount, FILTER_BLEND, !sync); | ||||||
| 	float rem1 = blend_input(1, p_time, p_seek, amount, FILTER_PASS, !sync); | 	float rem1 = blend_input(1, p_time, p_seek, amount, FILTER_PASS, !sync); | ||||||
| 
 | 
 | ||||||
|  | @ -459,31 +460,25 @@ bool AnimationNodeBlend2::has_filter() const { | ||||||
| } | } | ||||||
| void AnimationNodeBlend2::_bind_methods() { | void AnimationNodeBlend2::_bind_methods() { | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("set_amount", "amount"), &AnimationNodeBlend2::set_amount); |  | ||||||
| 	ClassDB::bind_method(D_METHOD("get_amount"), &AnimationNodeBlend2::get_amount); |  | ||||||
| 
 |  | ||||||
| 	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlend2::set_use_sync); | 	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlend2::set_use_sync); | ||||||
| 	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlend2::is_using_sync); | 	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlend2::is_using_sync); | ||||||
| 
 | 
 | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_amount", "get_amount"); |  | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync"); | 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync"); | ||||||
| } | } | ||||||
| AnimationNodeBlend2::AnimationNodeBlend2() { | AnimationNodeBlend2::AnimationNodeBlend2() { | ||||||
|  | 	blend_amount = "blend_amount"; | ||||||
| 	add_input("in"); | 	add_input("in"); | ||||||
| 	add_input("blend"); | 	add_input("blend"); | ||||||
| 	sync = false; | 	sync = false; | ||||||
| 
 |  | ||||||
| 	amount = 0; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| //////////////////////////////////////
 | //////////////////////////////////////
 | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlend3::set_amount(float p_amount) { | void AnimationNodeBlend3::get_parameter_list(List<PropertyInfo> *r_list) const { | ||||||
| 	amount = p_amount; | 	r_list->push_back(PropertyInfo(Variant::REAL, blend_amount, PROPERTY_HINT_RANGE, "-1,1,0.01")); | ||||||
| } | } | ||||||
| 
 | Variant AnimationNodeBlend3::get_parameter_default_value(const StringName &p_parameter) const { | ||||||
| float AnimationNodeBlend3::get_amount() const { | 	return 0; //for blend amount
 | ||||||
| 	return amount; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| String AnimationNodeBlend3::get_caption() const { | String AnimationNodeBlend3::get_caption() const { | ||||||
|  | @ -502,6 +497,7 @@ bool AnimationNodeBlend3::is_using_sync() const { | ||||||
| 
 | 
 | ||||||
| float AnimationNodeBlend3::process(float p_time, bool p_seek) { | float AnimationNodeBlend3::process(float p_time, bool p_seek) { | ||||||
| 
 | 
 | ||||||
|  | 	float amount = get_parameter(blend_amount); | ||||||
| 	float rem0 = blend_input(0, p_time, p_seek, MAX(0, -amount), FILTER_IGNORE, !sync); | 	float rem0 = blend_input(0, p_time, p_seek, MAX(0, -amount), FILTER_IGNORE, !sync); | ||||||
| 	float rem1 = blend_input(1, p_time, p_seek, 1.0 - ABS(amount), FILTER_IGNORE, !sync); | 	float rem1 = blend_input(1, p_time, p_seek, 1.0 - ABS(amount), FILTER_IGNORE, !sync); | ||||||
| 	float rem2 = blend_input(2, p_time, p_seek, MAX(0, amount), FILTER_IGNORE, !sync); | 	float rem2 = blend_input(2, p_time, p_seek, MAX(0, amount), FILTER_IGNORE, !sync); | ||||||
|  | @ -511,31 +507,26 @@ float AnimationNodeBlend3::process(float p_time, bool p_seek) { | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlend3::_bind_methods() { | void AnimationNodeBlend3::_bind_methods() { | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("set_amount", "amount"), &AnimationNodeBlend3::set_amount); |  | ||||||
| 	ClassDB::bind_method(D_METHOD("get_amount"), &AnimationNodeBlend3::get_amount); |  | ||||||
| 
 |  | ||||||
| 	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlend3::set_use_sync); | 	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlend3::set_use_sync); | ||||||
| 	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlend3::is_using_sync); | 	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlend3::is_using_sync); | ||||||
| 
 | 
 | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "amount", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_amount", "get_amount"); |  | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync"); | 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync"); | ||||||
| } | } | ||||||
| AnimationNodeBlend3::AnimationNodeBlend3() { | AnimationNodeBlend3::AnimationNodeBlend3() { | ||||||
|  | 	blend_amount = "blend_amount"; | ||||||
| 	add_input("-blend"); | 	add_input("-blend"); | ||||||
| 	add_input("in"); | 	add_input("in"); | ||||||
| 	add_input("+blend"); | 	add_input("+blend"); | ||||||
| 	sync = false; | 	sync = false; | ||||||
| 	amount = 0; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /////////////////////////////////
 | /////////////////////////////////
 | ||||||
| 
 | 
 | ||||||
| void AnimationNodeTimeScale::set_scale(float p_scale) { | void AnimationNodeTimeScale::get_parameter_list(List<PropertyInfo> *r_list) const { | ||||||
| 	scale = p_scale; | 	r_list->push_back(PropertyInfo(Variant::REAL, scale, PROPERTY_HINT_RANGE, "0,32,0.01,or_greater")); | ||||||
| } | } | ||||||
| 
 | Variant AnimationNodeTimeScale::get_parameter_default_value(const StringName &p_parameter) const { | ||||||
| float AnimationNodeTimeScale::get_scale() const { | 	return 1.0; //initial timescale
 | ||||||
| 	return scale; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| String AnimationNodeTimeScale::get_caption() const { | String AnimationNodeTimeScale::get_caption() const { | ||||||
|  | @ -544,6 +535,7 @@ String AnimationNodeTimeScale::get_caption() const { | ||||||
| 
 | 
 | ||||||
| float AnimationNodeTimeScale::process(float p_time, bool p_seek) { | float AnimationNodeTimeScale::process(float p_time, bool p_seek) { | ||||||
| 
 | 
 | ||||||
|  | 	float scale = get_parameter(this->scale); | ||||||
| 	if (p_seek) { | 	if (p_seek) { | ||||||
| 		return blend_input(0, p_time, true, 1.0, FILTER_IGNORE, false); | 		return blend_input(0, p_time, true, 1.0, FILTER_IGNORE, false); | ||||||
| 	} else { | 	} else { | ||||||
|  | @ -552,25 +544,19 @@ float AnimationNodeTimeScale::process(float p_time, bool p_seek) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeTimeScale::_bind_methods() { | void AnimationNodeTimeScale::_bind_methods() { | ||||||
| 
 |  | ||||||
| 	ClassDB::bind_method(D_METHOD("set_scale", "scale"), &AnimationNodeTimeScale::set_scale); |  | ||||||
| 	ClassDB::bind_method(D_METHOD("get_scale"), &AnimationNodeTimeScale::get_scale); |  | ||||||
| 
 |  | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "scale", PROPERTY_HINT_RANGE, "0,32,0.01,or_greater"), "set_scale", "get_scale"); |  | ||||||
| } | } | ||||||
| AnimationNodeTimeScale::AnimationNodeTimeScale() { | AnimationNodeTimeScale::AnimationNodeTimeScale() { | ||||||
|  | 	scale = "scale"; | ||||||
| 	add_input("in"); | 	add_input("in"); | ||||||
| 	scale = 1.0; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////
 | ////////////////////////////////////
 | ||||||
| 
 | 
 | ||||||
| void AnimationNodeTimeSeek::set_seek_pos(float p_seek_pos) { | void AnimationNodeTimeSeek::get_parameter_list(List<PropertyInfo> *r_list) const { | ||||||
| 	seek_pos = p_seek_pos; | 	r_list->push_back(PropertyInfo(Variant::REAL, seek_pos, PROPERTY_HINT_RANGE, "-1,3600,0.01,or_greater")); | ||||||
| } | } | ||||||
| 
 | Variant AnimationNodeTimeSeek::get_parameter_default_value(const StringName &p_parameter) const { | ||||||
| float AnimationNodeTimeSeek::get_seek_pos() const { | 	return 1.0; //initial timescale
 | ||||||
| 	return seek_pos; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| String AnimationNodeTimeSeek::get_caption() const { | String AnimationNodeTimeSeek::get_caption() const { | ||||||
|  | @ -579,11 +565,12 @@ String AnimationNodeTimeSeek::get_caption() const { | ||||||
| 
 | 
 | ||||||
| float AnimationNodeTimeSeek::process(float p_time, bool p_seek) { | float AnimationNodeTimeSeek::process(float p_time, bool p_seek) { | ||||||
| 
 | 
 | ||||||
|  | 	float seek_pos = get_parameter(this->seek_pos); | ||||||
| 	if (p_seek) { | 	if (p_seek) { | ||||||
| 		return blend_input(0, p_time, true, 1.0, FILTER_IGNORE, false); | 		return blend_input(0, p_time, true, 1.0, FILTER_IGNORE, false); | ||||||
| 	} else if (seek_pos >= 0) { | 	} else if (seek_pos >= 0) { | ||||||
| 		float ret = blend_input(0, seek_pos, true, 1.0, FILTER_IGNORE, false); | 		float ret = blend_input(0, seek_pos, true, 1.0, FILTER_IGNORE, false); | ||||||
| 		seek_pos = -1; | 		set_parameter(this->seek_pos, -1.0); //reset
 | ||||||
| 		_change_notify("seek_pos"); | 		_change_notify("seek_pos"); | ||||||
| 		return ret; | 		return ret; | ||||||
| 	} else { | 	} else { | ||||||
|  | @ -592,19 +579,41 @@ float AnimationNodeTimeSeek::process(float p_time, bool p_seek) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeTimeSeek::_bind_methods() { | void AnimationNodeTimeSeek::_bind_methods() { | ||||||
| 
 |  | ||||||
| 	ClassDB::bind_method(D_METHOD("set_seek_pos", "seek_pos"), &AnimationNodeTimeSeek::set_seek_pos); |  | ||||||
| 	ClassDB::bind_method(D_METHOD("get_seek_pos"), &AnimationNodeTimeSeek::get_seek_pos); |  | ||||||
| 
 |  | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "seek_pos", PROPERTY_HINT_RANGE, "-1,3600,0.01,or_greater"), "set_seek_pos", "get_seek_pos"); |  | ||||||
| } | } | ||||||
|  | 
 | ||||||
| AnimationNodeTimeSeek::AnimationNodeTimeSeek() { | AnimationNodeTimeSeek::AnimationNodeTimeSeek() { | ||||||
| 	add_input("in"); | 	add_input("in"); | ||||||
| 	seek_pos = -1; | 	seek_pos = "seek_position"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /////////////////////////////////////////////////
 | /////////////////////////////////////////////////
 | ||||||
| 
 | 
 | ||||||
|  | void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) const { | ||||||
|  | 
 | ||||||
|  | 	String anims; | ||||||
|  | 	for (int i = 0; i < enabled_inputs; i++) { | ||||||
|  | 		if (i > 0) { | ||||||
|  | 			anims += ","; | ||||||
|  | 		} | ||||||
|  | 		anims += inputs[i].name; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	r_list->push_back(PropertyInfo(Variant::INT, current, PROPERTY_HINT_ENUM, anims)); | ||||||
|  | 	r_list->push_back(PropertyInfo(Variant::INT, prev_current, PROPERTY_HINT_NONE, "", 0)); | ||||||
|  | 	r_list->push_back(PropertyInfo(Variant::INT, prev, PROPERTY_HINT_NONE, "", 0)); | ||||||
|  | 	r_list->push_back(PropertyInfo(Variant::REAL, time, PROPERTY_HINT_NONE, "", 0)); | ||||||
|  | 	r_list->push_back(PropertyInfo(Variant::REAL, prev_xfading, PROPERTY_HINT_NONE, "", 0)); | ||||||
|  | } | ||||||
|  | Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p_parameter) const { | ||||||
|  | 	if (p_parameter == time || p_parameter == prev_xfading) { | ||||||
|  | 		return 0.0; | ||||||
|  | 	} else if (p_parameter == prev || p_parameter == prev_current) { | ||||||
|  | 		return -1; | ||||||
|  | 	} else { | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| String AnimationNodeTransition::get_caption() const { | String AnimationNodeTransition::get_caption() const { | ||||||
| 	return "Transition"; | 	return "Transition"; | ||||||
| } | } | ||||||
|  | @ -650,18 +659,12 @@ String AnimationNodeTransition::get_input_caption(int p_input) const { | ||||||
| 	return inputs[p_input].name; | 	return inputs[p_input].name; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeTransition::set_current(int p_current) { | #if 0 | ||||||
| 
 |  | ||||||
| 	if (current == p_current) |  | ||||||
| 		return; |  | ||||||
| 	ERR_FAIL_INDEX(p_current, enabled_inputs); |  | ||||||
| 
 |  | ||||||
| 	Ref<AnimationNodeBlendTree> tree = get_parent(); | 	Ref<AnimationNodeBlendTree> tree = get_parent(); | ||||||
| 
 | 
 | ||||||
| 	if (tree.is_valid() && current >= 0) { | 	if (tree.is_valid() && current >= 0) { | ||||||
| 		prev = current; | 		prev = current; | ||||||
| 		prev_xfading = xfade;		 | 		prev_xfading = xfade;		 | ||||||
| 		prev_time = time; |  | ||||||
| 		time = 0; | 		time = 0; | ||||||
| 		current = p_current; | 		current = p_current; | ||||||
| 		switched = true; | 		switched = true; | ||||||
|  | @ -669,11 +672,8 @@ void AnimationNodeTransition::set_current(int p_current) { | ||||||
| 	} else { | 	} else { | ||||||
| 		current = p_current; | 		current = p_current; | ||||||
| 	} | 	} | ||||||
| } | #endif | ||||||
| 
 | 
 | ||||||
| int AnimationNodeTransition::get_current() const { |  | ||||||
| 	return current; |  | ||||||
| } |  | ||||||
| void AnimationNodeTransition::set_cross_fade_time(float p_fade) { | void AnimationNodeTransition::set_cross_fade_time(float p_fade) { | ||||||
| 	xfade = p_fade; | 	xfade = p_fade; | ||||||
| } | } | ||||||
|  | @ -684,9 +684,34 @@ float AnimationNodeTransition::get_cross_fade_time() const { | ||||||
| 
 | 
 | ||||||
| float AnimationNodeTransition::process(float p_time, bool p_seek) { | float AnimationNodeTransition::process(float p_time, bool p_seek) { | ||||||
| 
 | 
 | ||||||
|  | 	int current = get_parameter(this->current); | ||||||
|  | 	int prev = get_parameter(this->prev); | ||||||
|  | 	int prev_current = get_parameter(this->prev_current); | ||||||
|  | 
 | ||||||
|  | 	float time = get_parameter(this->time); | ||||||
|  | 	float prev_xfading = get_parameter(this->prev_xfading); | ||||||
|  | 
 | ||||||
|  | 	bool switched = current != prev_current; | ||||||
|  | 
 | ||||||
|  | 	if (switched) { | ||||||
|  | 		set_parameter(this->prev_current, current); | ||||||
|  | 		set_parameter(this->prev, prev_current); | ||||||
|  | 
 | ||||||
|  | 		prev = prev_current; | ||||||
|  | 		prev_xfading = xfade; | ||||||
|  | 		time = 0; | ||||||
|  | 		switched = true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (current < 0 || current >= enabled_inputs || prev >= enabled_inputs) { | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	float rem = 0; | ||||||
|  | 
 | ||||||
| 	if (prev < 0) { // process current animation, check for transition
 | 	if (prev < 0) { // process current animation, check for transition
 | ||||||
| 
 | 
 | ||||||
| 		float rem = blend_input(current, p_time, p_seek, 1.0, FILTER_IGNORE, false); | 		rem = blend_input(current, p_time, p_seek, 1.0, FILTER_IGNORE, false); | ||||||
| 
 | 
 | ||||||
| 		if (p_seek) | 		if (p_seek) | ||||||
| 			time = p_time; | 			time = p_time; | ||||||
|  | @ -695,16 +720,13 @@ float AnimationNodeTransition::process(float p_time, bool p_seek) { | ||||||
| 
 | 
 | ||||||
| 		if (inputs[current].auto_advance && rem <= xfade) { | 		if (inputs[current].auto_advance && rem <= xfade) { | ||||||
| 
 | 
 | ||||||
| 			set_current((current + 1) % enabled_inputs); | 			set_parameter(this->current, (current + 1) % enabled_inputs); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		return rem; |  | ||||||
| 	} else { // cross-fading from prev to current
 | 	} else { // cross-fading from prev to current
 | ||||||
| 
 | 
 | ||||||
| 		float blend = xfade ? (prev_xfading / xfade) : 1; | 		float blend = xfade ? (prev_xfading / xfade) : 1; | ||||||
| 
 | 
 | ||||||
| 		float rem; |  | ||||||
| 
 |  | ||||||
| 		if (!p_seek && switched) { //just switched, seek to start of current
 | 		if (!p_seek && switched) { //just switched, seek to start of current
 | ||||||
| 
 | 
 | ||||||
| 			rem = blend_input(current, 0, true, 1.0 - blend, FILTER_IGNORE, false); | 			rem = blend_input(current, 0, true, 1.0 - blend, FILTER_IGNORE, false); | ||||||
|  | @ -723,28 +745,19 @@ float AnimationNodeTransition::process(float p_time, bool p_seek) { | ||||||
| 			time += p_time; | 			time += p_time; | ||||||
| 			prev_xfading -= p_time; | 			prev_xfading -= p_time; | ||||||
| 			if (prev_xfading < 0) { | 			if (prev_xfading < 0) { | ||||||
| 				prev = -1; | 				set_parameter(this->prev, -1); | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	set_parameter(this->time, time); | ||||||
|  | 	set_parameter(this->prev_xfading, prev_xfading); | ||||||
|  | 
 | ||||||
| 	return rem; | 	return rem; | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeTransition::_validate_property(PropertyInfo &property) const { | void AnimationNodeTransition::_validate_property(PropertyInfo &property) const { | ||||||
| 
 | 
 | ||||||
| 	if (property.name == "current" && enabled_inputs > 0) { |  | ||||||
| 		property.hint = PROPERTY_HINT_ENUM; |  | ||||||
| 		String anims; |  | ||||||
| 		for (int i = 0; i < enabled_inputs; i++) { |  | ||||||
| 			if (i > 0) { |  | ||||||
| 				anims += ","; |  | ||||||
| 			} |  | ||||||
| 			anims += inputs[i].name; |  | ||||||
| 		} |  | ||||||
| 		property.hint_string = anims; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (property.name.begins_with("input_")) { | 	if (property.name.begins_with("input_")) { | ||||||
| 		String n = property.name.get_slicec('/', 0).get_slicec('_', 1); | 		String n = property.name.get_slicec('/', 0).get_slicec('_', 1); | ||||||
| 		if (n != "count") { | 		if (n != "count") { | ||||||
|  | @ -769,14 +782,10 @@ void AnimationNodeTransition::_bind_methods() { | ||||||
| 	ClassDB::bind_method(D_METHOD("set_input_caption", "input", "caption"), &AnimationNodeTransition::set_input_caption); | 	ClassDB::bind_method(D_METHOD("set_input_caption", "input", "caption"), &AnimationNodeTransition::set_input_caption); | ||||||
| 	ClassDB::bind_method(D_METHOD("get_input_caption", "input"), &AnimationNodeTransition::get_input_caption); | 	ClassDB::bind_method(D_METHOD("get_input_caption", "input"), &AnimationNodeTransition::get_input_caption); | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("set_current", "index"), &AnimationNodeTransition::set_current); |  | ||||||
| 	ClassDB::bind_method(D_METHOD("get_current"), &AnimationNodeTransition::get_current); |  | ||||||
| 
 |  | ||||||
| 	ClassDB::bind_method(D_METHOD("set_cross_fade_time", "time"), &AnimationNodeTransition::set_cross_fade_time); | 	ClassDB::bind_method(D_METHOD("set_cross_fade_time", "time"), &AnimationNodeTransition::set_cross_fade_time); | ||||||
| 	ClassDB::bind_method(D_METHOD("get_cross_fade_time"), &AnimationNodeTransition::get_cross_fade_time); | 	ClassDB::bind_method(D_METHOD("get_cross_fade_time"), &AnimationNodeTransition::get_cross_fade_time); | ||||||
| 
 | 
 | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs"); | 	ADD_PROPERTY(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs"); | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::INT, "current", PROPERTY_HINT_RANGE, "0,64,1"), "set_current", "get_current"); |  | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01"), "set_cross_fade_time", "get_cross_fade_time"); | 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01"), "set_cross_fade_time", "get_cross_fade_time"); | ||||||
| 
 | 
 | ||||||
| 	for (int i = 0; i < MAX_INPUTS; i++) { | 	for (int i = 0; i < MAX_INPUTS; i++) { | ||||||
|  | @ -786,13 +795,15 @@ void AnimationNodeTransition::_bind_methods() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AnimationNodeTransition::AnimationNodeTransition() { | AnimationNodeTransition::AnimationNodeTransition() { | ||||||
|  | 
 | ||||||
|  | 	prev_xfading = "prev_xfading"; | ||||||
|  | 	prev = "prev"; | ||||||
|  | 	time = "time"; | ||||||
|  | 	current = "current"; | ||||||
|  | 	prev_current = "prev_current"; | ||||||
|  | 	; | ||||||
|  | 
 | ||||||
| 	enabled_inputs = 0; | 	enabled_inputs = 0; | ||||||
| 	xfade = 0; |  | ||||||
| 	current = -1; |  | ||||||
| 	prev = -1; |  | ||||||
| 	prev_time = 0; |  | ||||||
| 	prev_xfading = 0; |  | ||||||
| 	switched = false; |  | ||||||
| 	for (int i = 0; i < MAX_INPUTS; i++) { | 	for (int i = 0; i < MAX_INPUTS; i++) { | ||||||
| 		inputs[i].auto_advance = false; | 		inputs[i].auto_advance = false; | ||||||
| 		inputs[i].name = itos(i + 1); | 		inputs[i].name = itos(i + 1); | ||||||
|  | @ -814,69 +825,102 @@ AnimationNodeOutput::AnimationNodeOutput() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ///////////////////////////////////////////////////////
 | ///////////////////////////////////////////////////////
 | ||||||
| void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref<AnimationNode> p_node) { | void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position) { | ||||||
| 
 | 
 | ||||||
| 	ERR_FAIL_COND(nodes.has(p_name)); | 	ERR_FAIL_COND(nodes.has(p_name)); | ||||||
| 	ERR_FAIL_COND(p_node.is_null()); | 	ERR_FAIL_COND(p_node.is_null()); | ||||||
| 	ERR_FAIL_COND(p_node->get_parent().is_valid()); |  | ||||||
| 	ERR_FAIL_COND(p_node->get_tree() != NULL); |  | ||||||
| 	ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output); | 	ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output); | ||||||
| 	ERR_FAIL_COND(String(p_name).find("/") != -1); | 	ERR_FAIL_COND(String(p_name).find("/") != -1); | ||||||
| 	nodes[p_name] = p_node; |  | ||||||
| 
 | 
 | ||||||
| 	p_node->set_parent(this); | 	Node n; | ||||||
| 	p_node->set_tree(get_tree()); | 	n.node = p_node; | ||||||
|  | 	n.position = p_position; | ||||||
|  | 	n.connections.resize(n.node->get_input_count()); | ||||||
|  | 	nodes[p_name] = n; | ||||||
| 
 | 
 | ||||||
| 	emit_changed(); | 	emit_changed(); | ||||||
|  | 	emit_signal("tree_changed"); | ||||||
|  | 
 | ||||||
|  | 	p_node->connect("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED); | ||||||
|  | 	p_node->connect("changed", this, "_node_changed", varray(p_name), CONNECT_REFERENCE_COUNTED); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Ref<AnimationNode> AnimationNodeBlendTree::get_node(const StringName &p_name) const { | Ref<AnimationNode> AnimationNodeBlendTree::get_node(const StringName &p_name) const { | ||||||
| 
 | 
 | ||||||
| 	ERR_FAIL_COND_V(!nodes.has(p_name), Ref<AnimationNode>()); | 	ERR_FAIL_COND_V(!nodes.has(p_name), Ref<AnimationNode>()); | ||||||
| 
 | 
 | ||||||
| 	return nodes[p_name]; | 	return nodes[p_name].node; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| StringName AnimationNodeBlendTree::get_node_name(const Ref<AnimationNode> &p_node) const { | StringName AnimationNodeBlendTree::get_node_name(const Ref<AnimationNode> &p_node) const { | ||||||
| 	for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) { | 	for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) { | ||||||
| 		if (E->get() == p_node) { | 		if (E->get().node == p_node) { | ||||||
| 			return E->key(); | 			return E->key(); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ERR_FAIL_V(StringName()); | 	ERR_FAIL_V(StringName()); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void AnimationNodeBlendTree::set_node_position(const StringName &p_node, const Vector2 &p_position) { | ||||||
|  | 	ERR_FAIL_COND(!nodes.has(p_node)); | ||||||
|  | 	nodes[p_node].position = p_position; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Vector2 AnimationNodeBlendTree::get_node_position(const StringName &p_node) const { | ||||||
|  | 	ERR_FAIL_COND_V(!nodes.has(p_node), Vector2()); | ||||||
|  | 	return nodes[p_node].position; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AnimationNodeBlendTree::get_child_nodes(List<ChildNode> *r_child_nodes) { | ||||||
|  | 	Vector<StringName> ns; | ||||||
|  | 
 | ||||||
|  | 	for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) { | ||||||
|  | 		ns.push_back(E->key()); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	ns.sort_custom<StringName::AlphCompare>(); | ||||||
|  | 
 | ||||||
|  | 	for (int i = 0; i < ns.size(); i++) { | ||||||
|  | 		ChildNode cn; | ||||||
|  | 		cn.name = ns[i]; | ||||||
|  | 		cn.node = nodes[cn.name].node; | ||||||
|  | 		r_child_nodes->push_back(cn); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool AnimationNodeBlendTree::has_node(const StringName &p_name) const { | bool AnimationNodeBlendTree::has_node(const StringName &p_name) const { | ||||||
| 	return nodes.has(p_name); | 	return nodes.has(p_name); | ||||||
| } | } | ||||||
|  | Vector<StringName> AnimationNodeBlendTree::get_node_connection_array(const StringName &p_name) const { | ||||||
|  | 
 | ||||||
|  | 	ERR_FAIL_COND_V(!nodes.has(p_name), Vector<StringName>()); | ||||||
|  | 	return nodes[p_name].connections; | ||||||
|  | } | ||||||
| void AnimationNodeBlendTree::remove_node(const StringName &p_name) { | void AnimationNodeBlendTree::remove_node(const StringName &p_name) { | ||||||
| 
 | 
 | ||||||
| 	ERR_FAIL_COND(!nodes.has(p_name)); | 	ERR_FAIL_COND(!nodes.has(p_name)); | ||||||
| 	ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output); //can't delete output
 | 	ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output); //can't delete output
 | ||||||
| 
 | 
 | ||||||
| 	{ | 	{ | ||||||
| 		//erase node connections
 | 		Ref<AnimationNode> node = nodes[p_name].node; | ||||||
| 		Ref<AnimationNode> node = nodes[p_name]; | 		node->disconnect("tree_changed", this, "_tree_changed"); | ||||||
| 		for (int i = 0; i < node->get_input_count(); i++) { | 		node->disconnect("changed", this, "_node_changed"); | ||||||
| 			node->set_input_connection(i, StringName()); |  | ||||||
| 		} |  | ||||||
| 		node->set_parent(NULL); |  | ||||||
| 		node->set_tree(NULL); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	nodes.erase(p_name); | 	nodes.erase(p_name); | ||||||
| 
 | 
 | ||||||
| 	//erase connections to name
 | 	//erase connections to name
 | ||||||
| 	for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) { | 	for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) { | ||||||
| 		Ref<AnimationNode> node = E->get(); | 		for (int i = 0; i < E->get().connections.size(); i++) { | ||||||
| 		for (int i = 0; i < node->get_input_count(); i++) { | 			if (E->get().connections[i] == p_name) { | ||||||
| 			if (node->get_input_connection(i) == p_name) { | 				E->get().connections.write[i] = StringName(); | ||||||
| 				node->set_input_connection(i, StringName()); |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	emit_changed(); | 	emit_changed(); | ||||||
|  | 	emit_signal("tree_changed"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringName &p_new_name) { | void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringName &p_new_name) { | ||||||
|  | @ -886,18 +930,24 @@ void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringN | ||||||
| 	ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output); | 	ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output); | ||||||
| 	ERR_FAIL_COND(p_new_name == SceneStringNames::get_singleton()->output); | 	ERR_FAIL_COND(p_new_name == SceneStringNames::get_singleton()->output); | ||||||
| 
 | 
 | ||||||
|  | 	nodes[p_name].node->disconnect("changed", this, "_node_changed"); | ||||||
|  | 
 | ||||||
| 	nodes[p_new_name] = nodes[p_name]; | 	nodes[p_new_name] = nodes[p_name]; | ||||||
| 	nodes.erase(p_name); | 	nodes.erase(p_name); | ||||||
| 
 | 
 | ||||||
| 	//rename connections
 | 	//rename connections
 | ||||||
| 	for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) { | 	for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) { | ||||||
| 		Ref<AnimationNode> node = E->get(); | 
 | ||||||
| 		for (int i = 0; i < node->get_input_count(); i++) { | 		for (int i = 0; i < E->get().connections.size(); i++) { | ||||||
| 			if (node->get_input_connection(i) == p_name) { | 			if (E->get().connections[i] == p_name) { | ||||||
| 				node->set_input_connection(i, p_new_name); | 				E->get().connections.write[i] = p_new_name; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	//connection must be done with new name
 | ||||||
|  | 	nodes[p_new_name].node->connect("changed", this, "_node_changed", varray(p_new_name), CONNECT_REFERENCE_COUNTED); | ||||||
|  | 
 | ||||||
|  | 	emit_signal("tree_changed"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendTree::connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node) { | void AnimationNodeBlendTree::connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node) { | ||||||
|  | @ -907,18 +957,18 @@ void AnimationNodeBlendTree::connect_node(const StringName &p_input_node, int p_ | ||||||
| 	ERR_FAIL_COND(p_output_node == SceneStringNames::get_singleton()->output); | 	ERR_FAIL_COND(p_output_node == SceneStringNames::get_singleton()->output); | ||||||
| 	ERR_FAIL_COND(p_input_node == p_output_node); | 	ERR_FAIL_COND(p_input_node == p_output_node); | ||||||
| 
 | 
 | ||||||
| 	Ref<AnimationNode> input = nodes[p_input_node]; | 	Ref<AnimationNode> input = nodes[p_input_node].node; | ||||||
| 	ERR_FAIL_INDEX(p_input_index, input->get_input_count()); | 	ERR_FAIL_INDEX(p_input_index, nodes[p_input_node].connections.size()); | ||||||
| 
 | 
 | ||||||
| 	for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) { | 	for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) { | ||||||
| 		Ref<AnimationNode> node = E->get(); | 		for (int i = 0; i < E->get().connections.size(); i++) { | ||||||
| 		for (int i = 0; i < node->get_input_count(); i++) { | 			StringName output = E->get().connections[i]; | ||||||
| 			StringName output = node->get_input_connection(i); |  | ||||||
| 			ERR_FAIL_COND(output == p_output_node); | 			ERR_FAIL_COND(output == p_output_node); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	input->set_input_connection(p_input_index, p_output_node); | 	nodes[p_input_node].connections.write[p_input_index] = p_output_node; | ||||||
|  | 
 | ||||||
| 	emit_changed(); | 	emit_changed(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -926,20 +976,21 @@ void AnimationNodeBlendTree::disconnect_node(const StringName &p_node, int p_inp | ||||||
| 
 | 
 | ||||||
| 	ERR_FAIL_COND(!nodes.has(p_node)); | 	ERR_FAIL_COND(!nodes.has(p_node)); | ||||||
| 
 | 
 | ||||||
| 	Ref<AnimationNode> input = nodes[p_node]; | 	Ref<AnimationNode> input = nodes[p_node].node; | ||||||
| 	ERR_FAIL_INDEX(p_input_index, input->get_input_count()); | 	ERR_FAIL_INDEX(p_input_index, nodes[p_node].connections.size()); | ||||||
| 
 | 
 | ||||||
| 	input->set_input_connection(p_input_index, StringName()); | 	nodes[p_node].connections.write[p_input_index] = StringName(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| float AnimationNodeBlendTree::get_connection_activity(const StringName &p_input_node, int p_input_index) const { | float AnimationNodeBlendTree::get_connection_activity(const StringName &p_input_node, int p_input_index) const { | ||||||
| 
 | 
 | ||||||
| 	ERR_FAIL_COND_V(!nodes.has(p_input_node), 0); | 	ERR_FAIL_COND_V(!nodes.has(p_input_node), 0); | ||||||
| 
 | 
 | ||||||
| 	Ref<AnimationNode> input = nodes[p_input_node]; | 	Ref<AnimationNode> input = nodes[p_input_node].node; | ||||||
| 	ERR_FAIL_INDEX_V(p_input_index, input->get_input_count(), 0); | 	ERR_FAIL_INDEX_V(p_input_index, nodes[p_input_node].connections.size(), 0); | ||||||
| 
 | 
 | ||||||
| 	return input->get_input_activity(p_input_index); | 	//return input->get_input_activity(p_input_index);
 | ||||||
|  | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node) const { | AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node) const { | ||||||
|  | @ -956,20 +1007,19 @@ AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node | ||||||
| 		return CONNECTION_ERROR_SAME_NODE; | 		return CONNECTION_ERROR_SAME_NODE; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Ref<AnimationNode> input = nodes[p_input_node]; | 	Ref<AnimationNode> input = nodes[p_input_node].node; | ||||||
| 
 | 
 | ||||||
| 	if (p_input_index < 0 || p_input_index >= input->get_input_count()) { | 	if (p_input_index < 0 || p_input_index >= nodes[p_input_node].connections.size()) { | ||||||
| 		return CONNECTION_ERROR_NO_INPUT_INDEX; | 		return CONNECTION_ERROR_NO_INPUT_INDEX; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (input->get_input_connection(p_input_index) != StringName()) { | 	if (nodes[p_input_node].connections[p_input_index] != StringName()) { | ||||||
| 		return CONNECTION_ERROR_CONNECTION_EXISTS; | 		return CONNECTION_ERROR_CONNECTION_EXISTS; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) { | 	for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) { | ||||||
| 		Ref<AnimationNode> node = E->get(); | 		for (int i = 0; i < E->get().connections.size(); i++) { | ||||||
| 		for (int i = 0; i < node->get_input_count(); i++) { | 			StringName output = E->get().connections[i]; | ||||||
| 			StringName output = node->get_input_connection(i); |  | ||||||
| 			if (output == p_output_node) { | 			if (output == p_output_node) { | ||||||
| 				return CONNECTION_ERROR_CONNECTION_EXISTS; | 				return CONNECTION_ERROR_CONNECTION_EXISTS; | ||||||
| 			} | 			} | ||||||
|  | @ -980,10 +1030,9 @@ AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendTree::get_node_connections(List<NodeConnection> *r_connections) const { | void AnimationNodeBlendTree::get_node_connections(List<NodeConnection> *r_connections) const { | ||||||
| 
 | 
 | ||||||
| 	for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) { | 	for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) { | ||||||
| 		Ref<AnimationNode> node = E->get(); | 		for (int i = 0; i < E->get().connections.size(); i++) { | ||||||
| 		for (int i = 0; i < node->get_input_count(); i++) { | 			StringName output = E->get().connections[i]; | ||||||
| 			StringName output = node->get_input_connection(i); |  | ||||||
| 			if (output != StringName()) { | 			if (output != StringName()) { | ||||||
| 				NodeConnection nc; | 				NodeConnection nc; | ||||||
| 				nc.input_node = E->key(); | 				nc.input_node = E->key(); | ||||||
|  | @ -1001,13 +1050,13 @@ String AnimationNodeBlendTree::get_caption() const { | ||||||
| 
 | 
 | ||||||
| float AnimationNodeBlendTree::process(float p_time, bool p_seek) { | float AnimationNodeBlendTree::process(float p_time, bool p_seek) { | ||||||
| 
 | 
 | ||||||
| 	Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output]; | 	Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output].node; | ||||||
| 	return blend_node(output, p_time, p_seek, 1.0); | 	return _blend_node("output", nodes[SceneStringNames::get_singleton()->output].connections, this, output, p_time, p_seek, 1.0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendTree::get_node_list(List<StringName> *r_list) { | void AnimationNodeBlendTree::get_node_list(List<StringName> *r_list) { | ||||||
| 
 | 
 | ||||||
| 	for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) { | 	for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) { | ||||||
| 		r_list->push_back(E->key()); | 		r_list->push_back(E->key()); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -1022,14 +1071,8 @@ Vector2 AnimationNodeBlendTree::get_graph_offset() const { | ||||||
| 	return graph_offset; | 	return graph_offset; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNodeBlendTree::set_tree(AnimationTree *p_player) { | Ref<AnimationNode> AnimationNodeBlendTree::get_child_by_name(const StringName &p_name) { | ||||||
| 
 | 	return get_node(p_name); | ||||||
| 	AnimationNode::set_tree(p_player); |  | ||||||
| 
 |  | ||||||
| 	for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) { |  | ||||||
| 		Ref<AnimationNode> node = E->get(); |  | ||||||
| 		node->set_tree(p_player); |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool AnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_value) { | bool AnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_value) { | ||||||
|  | @ -1051,7 +1094,7 @@ bool AnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_val | ||||||
| 		if (what == "position") { | 		if (what == "position") { | ||||||
| 
 | 
 | ||||||
| 			if (nodes.has(node_name)) { | 			if (nodes.has(node_name)) { | ||||||
| 				nodes[node_name]->set_position(p_value); | 				nodes[node_name].position = p_value; | ||||||
| 			} | 			} | ||||||
| 			return true; | 			return true; | ||||||
| 		} | 		} | ||||||
|  | @ -1078,7 +1121,7 @@ bool AnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_ret) cons | ||||||
| 
 | 
 | ||||||
| 		if (what == "node") { | 		if (what == "node") { | ||||||
| 			if (nodes.has(node_name)) { | 			if (nodes.has(node_name)) { | ||||||
| 				r_ret = nodes[node_name]; | 				r_ret = nodes[node_name].node; | ||||||
| 				return true; | 				return true; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | @ -1086,7 +1129,7 @@ bool AnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_ret) cons | ||||||
| 		if (what == "position") { | 		if (what == "position") { | ||||||
| 
 | 
 | ||||||
| 			if (nodes.has(node_name)) { | 			if (nodes.has(node_name)) { | ||||||
| 				r_ret = nodes[node_name]->get_position(); | 				r_ret = nodes[node_name].position; | ||||||
| 				return true; | 				return true; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | @ -1113,7 +1156,7 @@ bool AnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_ret) cons | ||||||
| void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) const { | void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) const { | ||||||
| 
 | 
 | ||||||
| 	List<StringName> names; | 	List<StringName> names; | ||||||
| 	for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) { | 	for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) { | ||||||
| 		names.push_back(E->key()); | 		names.push_back(E->key()); | ||||||
| 	} | 	} | ||||||
| 	names.sort_custom<StringName::AlphCompare>(); | 	names.sort_custom<StringName::AlphCompare>(); | ||||||
|  | @ -1121,7 +1164,7 @@ void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) cons | ||||||
| 	for (List<StringName>::Element *E = names.front(); E; E = E->next()) { | 	for (List<StringName>::Element *E = names.front(); E; E = E->next()) { | ||||||
| 		String name = E->get(); | 		String name = E->get(); | ||||||
| 		if (name != "output") { | 		if (name != "output") { | ||||||
| 			p_list->push_back(PropertyInfo(Variant::OBJECT, "nodes/" + name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE)); | 			p_list->push_back(PropertyInfo(Variant::OBJECT, "nodes/" + name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NOEDITOR)); | ||||||
| 		} | 		} | ||||||
| 		p_list->push_back(PropertyInfo(Variant::VECTOR2, "nodes/" + name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); | 		p_list->push_back(PropertyInfo(Variant::VECTOR2, "nodes/" + name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); | ||||||
| 	} | 	} | ||||||
|  | @ -1129,9 +1172,19 @@ void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) cons | ||||||
| 	p_list->push_back(PropertyInfo(Variant::ARRAY, "node_connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); | 	p_list->push_back(PropertyInfo(Variant::ARRAY, "node_connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void AnimationNodeBlendTree::_tree_changed() { | ||||||
|  | 	emit_signal("tree_changed"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AnimationNodeBlendTree::_node_changed(const StringName &p_node) { | ||||||
|  | 
 | ||||||
|  | 	ERR_FAIL_COND(!nodes.has(p_node)); | ||||||
|  | 	nodes[p_node].connections.resize(nodes[p_node].node->get_input_count()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void AnimationNodeBlendTree::_bind_methods() { | void AnimationNodeBlendTree::_bind_methods() { | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("add_node", "name", "node"), &AnimationNodeBlendTree::add_node); | 	ClassDB::bind_method(D_METHOD("add_node", "name", "node", "position"), &AnimationNodeBlendTree::add_node, DEFVAL(Vector2())); | ||||||
| 	ClassDB::bind_method(D_METHOD("get_node", "name"), &AnimationNodeBlendTree::get_node); | 	ClassDB::bind_method(D_METHOD("get_node", "name"), &AnimationNodeBlendTree::get_node); | ||||||
| 	ClassDB::bind_method(D_METHOD("remove_node", "name"), &AnimationNodeBlendTree::remove_node); | 	ClassDB::bind_method(D_METHOD("remove_node", "name"), &AnimationNodeBlendTree::remove_node); | ||||||
| 	ClassDB::bind_method(D_METHOD("rename_node", "name", "new_name"), &AnimationNodeBlendTree::rename_node); | 	ClassDB::bind_method(D_METHOD("rename_node", "name", "new_name"), &AnimationNodeBlendTree::rename_node); | ||||||
|  | @ -1139,9 +1192,15 @@ void AnimationNodeBlendTree::_bind_methods() { | ||||||
| 	ClassDB::bind_method(D_METHOD("connect_node", "input_node", "input_index", "output_node"), &AnimationNodeBlendTree::connect_node); | 	ClassDB::bind_method(D_METHOD("connect_node", "input_node", "input_index", "output_node"), &AnimationNodeBlendTree::connect_node); | ||||||
| 	ClassDB::bind_method(D_METHOD("disconnect_node", "input_node", "input_index"), &AnimationNodeBlendTree::disconnect_node); | 	ClassDB::bind_method(D_METHOD("disconnect_node", "input_node", "input_index"), &AnimationNodeBlendTree::disconnect_node); | ||||||
| 
 | 
 | ||||||
|  | 	ClassDB::bind_method(D_METHOD("set_node_position", "name", "position"), &AnimationNodeBlendTree::set_node_position); | ||||||
|  | 	ClassDB::bind_method(D_METHOD("get_node_position", "name"), &AnimationNodeBlendTree::get_node_position); | ||||||
|  | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &AnimationNodeBlendTree::set_graph_offset); | 	ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &AnimationNodeBlendTree::set_graph_offset); | ||||||
| 	ClassDB::bind_method(D_METHOD("get_graph_offset"), &AnimationNodeBlendTree::get_graph_offset); | 	ClassDB::bind_method(D_METHOD("get_graph_offset"), &AnimationNodeBlendTree::get_graph_offset); | ||||||
| 
 | 
 | ||||||
|  | 	ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeBlendTree::_tree_changed); | ||||||
|  | 	ClassDB::bind_method(D_METHOD("_node_changed", "node"), &AnimationNodeBlendTree::_node_changed); | ||||||
|  | 
 | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_graph_offset", "get_graph_offset"); | 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_graph_offset", "get_graph_offset"); | ||||||
| 
 | 
 | ||||||
| 	BIND_CONSTANT(CONNECTION_OK); | 	BIND_CONSTANT(CONNECTION_OK); | ||||||
|  | @ -1156,15 +1215,12 @@ AnimationNodeBlendTree::AnimationNodeBlendTree() { | ||||||
| 
 | 
 | ||||||
| 	Ref<AnimationNodeOutput> output; | 	Ref<AnimationNodeOutput> output; | ||||||
| 	output.instance(); | 	output.instance(); | ||||||
| 	output->set_position(Vector2(300, 150)); | 	Node n; | ||||||
| 	output->set_parent(this); | 	n.node = output; | ||||||
| 	nodes["output"] = output; | 	n.position = Vector2(300, 150); | ||||||
|  | 	n.connections.resize(1); | ||||||
|  | 	nodes["output"] = n; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AnimationNodeBlendTree::~AnimationNodeBlendTree() { | AnimationNodeBlendTree::~AnimationNodeBlendTree() { | ||||||
| 
 |  | ||||||
| 	for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) { |  | ||||||
| 		E->get()->set_parent(NULL); |  | ||||||
| 		E->get()->set_tree(NULL); |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -20,6 +20,8 @@ protected: | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|  | 	static Vector<String> (*get_editable_animation_list)(); | ||||||
|  | 
 | ||||||
| 	virtual String get_caption() const; | 	virtual String get_caption() const; | ||||||
| 	virtual float process(float p_time, bool p_seek); | 	virtual float process(float p_time, bool p_seek); | ||||||
| 
 | 
 | ||||||
|  | @ -41,8 +43,6 @@ public: | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 	bool active; |  | ||||||
| 	bool do_start; |  | ||||||
| 	float fade_in; | 	float fade_in; | ||||||
| 	float fade_out; | 	float fade_out; | ||||||
| 
 | 
 | ||||||
|  | @ -51,15 +51,25 @@ private: | ||||||
| 	float autorestart_random_delay; | 	float autorestart_random_delay; | ||||||
| 	MixMode mix; | 	MixMode mix; | ||||||
| 
 | 
 | ||||||
| 	float time; |  | ||||||
| 	float remaining; |  | ||||||
| 	float autorestart_remaining; |  | ||||||
| 	bool sync; | 	bool sync; | ||||||
| 
 | 
 | ||||||
|  | 	/*	bool active;
 | ||||||
|  | 	bool do_start; | ||||||
|  | 	float time; | ||||||
|  | 	float remaining;*/ | ||||||
|  | 
 | ||||||
|  | 	StringName active; | ||||||
|  | 	StringName prev_active; | ||||||
|  | 	StringName time; | ||||||
|  | 	StringName remaining; | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|  | 	virtual void get_parameter_list(List<PropertyInfo> *r_list) const; | ||||||
|  | 	virtual Variant get_parameter_default_value(const StringName &p_parameter) const; | ||||||
|  | 
 | ||||||
| 	virtual String get_caption() const; | 	virtual String get_caption() const; | ||||||
| 
 | 
 | ||||||
| 	void set_fadein_time(float p_time); | 	void set_fadein_time(float p_time); | ||||||
|  | @ -79,10 +89,6 @@ public: | ||||||
| 	void set_mix_mode(MixMode p_mix); | 	void set_mix_mode(MixMode p_mix); | ||||||
| 	MixMode get_mix_mode() const; | 	MixMode get_mix_mode() const; | ||||||
| 
 | 
 | ||||||
| 	void start(); |  | ||||||
| 	void stop(); |  | ||||||
| 	bool is_active() const; |  | ||||||
| 
 |  | ||||||
| 	void set_use_sync(bool p_sync); | 	void set_use_sync(bool p_sync); | ||||||
| 	bool is_using_sync() const; | 	bool is_using_sync() const; | ||||||
| 
 | 
 | ||||||
|  | @ -97,17 +103,17 @@ VARIANT_ENUM_CAST(AnimationNodeOneShot::MixMode) | ||||||
| class AnimationNodeAdd2 : public AnimationNode { | class AnimationNodeAdd2 : public AnimationNode { | ||||||
| 	GDCLASS(AnimationNodeAdd2, AnimationNode); | 	GDCLASS(AnimationNodeAdd2, AnimationNode); | ||||||
| 
 | 
 | ||||||
| 	float amount; | 	StringName add_amount; | ||||||
| 	bool sync; | 	bool sync; | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 	virtual String get_caption() const; | 	void get_parameter_list(List<PropertyInfo> *r_list) const; | ||||||
|  | 	virtual Variant get_parameter_default_value(const StringName &p_parameter) const; | ||||||
| 
 | 
 | ||||||
| 	void set_amount(float p_amount); | 	virtual String get_caption() const; | ||||||
| 	float get_amount() const; |  | ||||||
| 
 | 
 | ||||||
| 	void set_use_sync(bool p_sync); | 	void set_use_sync(bool p_sync); | ||||||
| 	bool is_using_sync() const; | 	bool is_using_sync() const; | ||||||
|  | @ -121,17 +127,17 @@ public: | ||||||
| class AnimationNodeAdd3 : public AnimationNode { | class AnimationNodeAdd3 : public AnimationNode { | ||||||
| 	GDCLASS(AnimationNodeAdd3, AnimationNode); | 	GDCLASS(AnimationNodeAdd3, AnimationNode); | ||||||
| 
 | 
 | ||||||
| 	float amount; | 	StringName add_amount; | ||||||
| 	bool sync; | 	bool sync; | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 	virtual String get_caption() const; | 	void get_parameter_list(List<PropertyInfo> *r_list) const; | ||||||
|  | 	virtual Variant get_parameter_default_value(const StringName &p_parameter) const; | ||||||
| 
 | 
 | ||||||
| 	void set_amount(float p_amount); | 	virtual String get_caption() const; | ||||||
| 	float get_amount() const; |  | ||||||
| 
 | 
 | ||||||
| 	void set_use_sync(bool p_sync); | 	void set_use_sync(bool p_sync); | ||||||
| 	bool is_using_sync() const; | 	bool is_using_sync() const; | ||||||
|  | @ -145,19 +151,19 @@ public: | ||||||
| class AnimationNodeBlend2 : public AnimationNode { | class AnimationNodeBlend2 : public AnimationNode { | ||||||
| 	GDCLASS(AnimationNodeBlend2, AnimationNode); | 	GDCLASS(AnimationNodeBlend2, AnimationNode); | ||||||
| 
 | 
 | ||||||
| 	float amount; | 	StringName blend_amount; | ||||||
| 	bool sync; | 	bool sync; | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|  | 	virtual void get_parameter_list(List<PropertyInfo> *r_list) const; | ||||||
|  | 	virtual Variant get_parameter_default_value(const StringName &p_parameter) const; | ||||||
|  | 
 | ||||||
| 	virtual String get_caption() const; | 	virtual String get_caption() const; | ||||||
| 	virtual float process(float p_time, bool p_seek); | 	virtual float process(float p_time, bool p_seek); | ||||||
| 
 | 
 | ||||||
| 	void set_amount(float p_amount); |  | ||||||
| 	float get_amount() const; |  | ||||||
| 
 |  | ||||||
| 	void set_use_sync(bool p_sync); | 	void set_use_sync(bool p_sync); | ||||||
| 	bool is_using_sync() const; | 	bool is_using_sync() const; | ||||||
| 
 | 
 | ||||||
|  | @ -168,17 +174,17 @@ public: | ||||||
| class AnimationNodeBlend3 : public AnimationNode { | class AnimationNodeBlend3 : public AnimationNode { | ||||||
| 	GDCLASS(AnimationNodeBlend3, AnimationNode); | 	GDCLASS(AnimationNodeBlend3, AnimationNode); | ||||||
| 
 | 
 | ||||||
| 	float amount; | 	StringName blend_amount; | ||||||
| 	bool sync; | 	bool sync; | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 	virtual String get_caption() const; | 	virtual void get_parameter_list(List<PropertyInfo> *r_list) const; | ||||||
|  | 	virtual Variant get_parameter_default_value(const StringName &p_parameter) const; | ||||||
| 
 | 
 | ||||||
| 	void set_amount(float p_amount); | 	virtual String get_caption() const; | ||||||
| 	float get_amount() const; |  | ||||||
| 
 | 
 | ||||||
| 	void set_use_sync(bool p_sync); | 	void set_use_sync(bool p_sync); | ||||||
| 	bool is_using_sync() const; | 	bool is_using_sync() const; | ||||||
|  | @ -190,16 +196,16 @@ public: | ||||||
| class AnimationNodeTimeScale : public AnimationNode { | class AnimationNodeTimeScale : public AnimationNode { | ||||||
| 	GDCLASS(AnimationNodeTimeScale, AnimationNode); | 	GDCLASS(AnimationNodeTimeScale, AnimationNode); | ||||||
| 
 | 
 | ||||||
| 	float scale; | 	StringName scale; | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 	virtual String get_caption() const; | 	virtual void get_parameter_list(List<PropertyInfo> *r_list) const; | ||||||
|  | 	virtual Variant get_parameter_default_value(const StringName &p_parameter) const; | ||||||
| 
 | 
 | ||||||
| 	void set_scale(float p_scale); | 	virtual String get_caption() const; | ||||||
| 	float get_scale() const; |  | ||||||
| 
 | 
 | ||||||
| 	float process(float p_time, bool p_seek); | 	float process(float p_time, bool p_seek); | ||||||
| 
 | 
 | ||||||
|  | @ -209,16 +215,16 @@ public: | ||||||
| class AnimationNodeTimeSeek : public AnimationNode { | class AnimationNodeTimeSeek : public AnimationNode { | ||||||
| 	GDCLASS(AnimationNodeTimeSeek, AnimationNode); | 	GDCLASS(AnimationNodeTimeSeek, AnimationNode); | ||||||
| 
 | 
 | ||||||
| 	float seek_pos; | 	StringName seek_pos; | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 	virtual String get_caption() const; | 	virtual void get_parameter_list(List<PropertyInfo> *r_list) const; | ||||||
|  | 	virtual Variant get_parameter_default_value(const StringName &p_parameter) const; | ||||||
| 
 | 
 | ||||||
| 	void set_seek_pos(float p_sec); | 	virtual String get_caption() const; | ||||||
| 	float get_seek_pos() const; |  | ||||||
| 
 | 
 | ||||||
| 	float process(float p_time, bool p_seek); | 	float process(float p_time, bool p_seek); | ||||||
| 
 | 
 | ||||||
|  | @ -241,13 +247,18 @@ class AnimationNodeTransition : public AnimationNode { | ||||||
| 	InputData inputs[MAX_INPUTS]; | 	InputData inputs[MAX_INPUTS]; | ||||||
| 	int enabled_inputs; | 	int enabled_inputs; | ||||||
| 
 | 
 | ||||||
| 	float prev_time; | 	/*
 | ||||||
| 	float prev_xfading; | 	float prev_xfading; | ||||||
| 	int prev; | 	int prev; | ||||||
| 	bool switched; |  | ||||||
| 
 |  | ||||||
| 	float time; | 	float time; | ||||||
| 	int current; | 	int current; | ||||||
|  | 	int prev_current; */ | ||||||
|  | 
 | ||||||
|  | 	StringName prev_xfading; | ||||||
|  | 	StringName prev; | ||||||
|  | 	StringName time; | ||||||
|  | 	StringName current; | ||||||
|  | 	StringName prev_current; | ||||||
| 
 | 
 | ||||||
| 	float xfade; | 	float xfade; | ||||||
| 
 | 
 | ||||||
|  | @ -258,6 +269,9 @@ protected: | ||||||
| 	void _validate_property(PropertyInfo &property) const; | 	void _validate_property(PropertyInfo &property) const; | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|  | 	virtual void get_parameter_list(List<PropertyInfo> *r_list) const; | ||||||
|  | 	virtual Variant get_parameter_default_value(const StringName &p_parameter) const; | ||||||
|  | 
 | ||||||
| 	virtual String get_caption() const; | 	virtual String get_caption() const; | ||||||
| 
 | 
 | ||||||
| 	void set_enabled_inputs(int p_inputs); | 	void set_enabled_inputs(int p_inputs); | ||||||
|  | @ -269,9 +283,6 @@ public: | ||||||
| 	void set_input_caption(int p_input, const String &p_name); | 	void set_input_caption(int p_input, const String &p_name); | ||||||
| 	String get_input_caption(int p_input) const; | 	String get_input_caption(int p_input) const; | ||||||
| 
 | 
 | ||||||
| 	void set_current(int p_current); |  | ||||||
| 	int get_current() const; |  | ||||||
| 
 |  | ||||||
| 	void set_cross_fade_time(float p_fade); | 	void set_cross_fade_time(float p_fade); | ||||||
| 	float get_cross_fade_time() const; | 	float get_cross_fade_time() const; | ||||||
| 
 | 
 | ||||||
|  | @ -293,10 +304,19 @@ public: | ||||||
| class AnimationNodeBlendTree : public AnimationRootNode { | class AnimationNodeBlendTree : public AnimationRootNode { | ||||||
| 	GDCLASS(AnimationNodeBlendTree, AnimationRootNode) | 	GDCLASS(AnimationNodeBlendTree, AnimationRootNode) | ||||||
| 
 | 
 | ||||||
| 	Map<StringName, Ref<AnimationNode> > nodes; | 	struct Node { | ||||||
|  | 		Ref<AnimationNode> node; | ||||||
|  | 		Vector2 position; | ||||||
|  | 		Vector<StringName> connections; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	Map<StringName, Node> nodes; | ||||||
| 
 | 
 | ||||||
| 	Vector2 graph_offset; | 	Vector2 graph_offset; | ||||||
| 
 | 
 | ||||||
|  | 	void _tree_changed(); | ||||||
|  | 	void _node_changed(const StringName &p_node); | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
| 	bool _set(const StringName &p_name, const Variant &p_value); | 	bool _set(const StringName &p_name, const Variant &p_value); | ||||||
|  | @ -314,12 +334,18 @@ public: | ||||||
| 		//no need to check for cycles due to tree topology
 | 		//no need to check for cycles due to tree topology
 | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	void add_node(const StringName &p_name, Ref<AnimationNode> p_node); | 	void add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position = Vector2()); | ||||||
| 	Ref<AnimationNode> get_node(const StringName &p_name) const; | 	Ref<AnimationNode> get_node(const StringName &p_name) const; | ||||||
| 	void remove_node(const StringName &p_name); | 	void remove_node(const StringName &p_name); | ||||||
| 	void rename_node(const StringName &p_name, const StringName &p_new_name); | 	void rename_node(const StringName &p_name, const StringName &p_new_name); | ||||||
| 	bool has_node(const StringName &p_name) const; | 	bool has_node(const StringName &p_name) const; | ||||||
| 	StringName get_node_name(const Ref<AnimationNode> &p_node) const; | 	StringName get_node_name(const Ref<AnimationNode> &p_node) const; | ||||||
|  | 	Vector<StringName> get_node_connection_array(const StringName &p_name) const; | ||||||
|  | 
 | ||||||
|  | 	void set_node_position(const StringName &p_node, const Vector2 &p_position); | ||||||
|  | 	Vector2 get_node_position(const StringName &p_node) const; | ||||||
|  | 
 | ||||||
|  | 	virtual void get_child_nodes(List<ChildNode> *r_child_nodes); | ||||||
| 
 | 
 | ||||||
| 	void connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node); | 	void connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node); | ||||||
| 	void disconnect_node(const StringName &p_node, int p_input_index); | 	void disconnect_node(const StringName &p_node, int p_input_index); | ||||||
|  | @ -342,7 +368,8 @@ public: | ||||||
| 	void set_graph_offset(const Vector2 &p_graph_offset); | 	void set_graph_offset(const Vector2 &p_graph_offset); | ||||||
| 	Vector2 get_graph_offset() const; | 	Vector2 get_graph_offset() const; | ||||||
| 
 | 
 | ||||||
| 	virtual void set_tree(AnimationTree *p_player); | 	virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name); | ||||||
|  | 
 | ||||||
| 	AnimationNodeBlendTree(); | 	AnimationNodeBlendTree(); | ||||||
| 	~AnimationNodeBlendTree(); | 	~AnimationNodeBlendTree(); | ||||||
| }; | }; | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -15,6 +15,8 @@ public: | ||||||
| private: | private: | ||||||
| 	SwitchMode switch_mode; | 	SwitchMode switch_mode; | ||||||
| 	bool auto_advance; | 	bool auto_advance; | ||||||
|  | 	StringName advance_condition; | ||||||
|  | 	StringName advance_condition_name; | ||||||
| 	float xfade; | 	float xfade; | ||||||
| 	bool disabled; | 	bool disabled; | ||||||
| 	int priority; | 	int priority; | ||||||
|  | @ -29,6 +31,11 @@ public: | ||||||
| 	void set_auto_advance(bool p_enable); | 	void set_auto_advance(bool p_enable); | ||||||
| 	bool has_auto_advance() const; | 	bool has_auto_advance() const; | ||||||
| 
 | 
 | ||||||
|  | 	void set_advance_condition(const StringName &p_condition); | ||||||
|  | 	StringName get_advance_condition() const; | ||||||
|  | 
 | ||||||
|  | 	StringName get_advance_condition_name() const; | ||||||
|  | 
 | ||||||
| 	void set_xfade_time(float p_xfade); | 	void set_xfade_time(float p_xfade); | ||||||
| 	float get_xfade_time() const; | 	float get_xfade_time() const; | ||||||
| 
 | 
 | ||||||
|  | @ -43,39 +50,24 @@ public: | ||||||
| 
 | 
 | ||||||
| VARIANT_ENUM_CAST(AnimationNodeStateMachineTransition::SwitchMode) | VARIANT_ENUM_CAST(AnimationNodeStateMachineTransition::SwitchMode) | ||||||
| 
 | 
 | ||||||
| class AnimationNodeStateMachine : public AnimationRootNode { | class AnimationNodeStateMachine; | ||||||
| 
 | 
 | ||||||
| 	GDCLASS(AnimationNodeStateMachine, AnimationRootNode); | class AnimationNodeStateMachinePlayback : public Resource { | ||||||
|  | 	GDCLASS(AnimationNodeStateMachinePlayback, Resource); | ||||||
| 
 | 
 | ||||||
| private: | 	friend class AnimationNodeStateMachine; | ||||||
| 	Map<StringName, Ref<AnimationRootNode> > states; |  | ||||||
| 
 |  | ||||||
| 	struct Transition { |  | ||||||
| 
 |  | ||||||
| 		StringName from; |  | ||||||
| 		StringName to; |  | ||||||
| 		Ref<AnimationNodeStateMachineTransition> transition; |  | ||||||
| 	}; |  | ||||||
| 
 | 
 | ||||||
| 	struct AStarCost { | 	struct AStarCost { | ||||||
| 		float distance; | 		float distance; | ||||||
| 		StringName prev; | 		StringName prev; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	Vector<Transition> transitions; |  | ||||||
| 
 |  | ||||||
| 	float len_total; | 	float len_total; | ||||||
| 
 | 
 | ||||||
| 	float len_current; | 	float len_current; | ||||||
| 	float pos_current; | 	float pos_current; | ||||||
| 	int loops_current; | 	int loops_current; | ||||||
| 
 | 
 | ||||||
| 	bool play_start; |  | ||||||
| 	StringName start_node; |  | ||||||
| 	StringName end_node; |  | ||||||
| 
 |  | ||||||
| 	Vector2 graph_offset; |  | ||||||
| 
 |  | ||||||
| 	StringName current; | 	StringName current; | ||||||
| 
 | 
 | ||||||
| 	StringName fading_from; | 	StringName fading_from; | ||||||
|  | @ -85,6 +77,63 @@ private: | ||||||
| 	Vector<StringName> path; | 	Vector<StringName> path; | ||||||
| 	bool playing; | 	bool playing; | ||||||
| 
 | 
 | ||||||
|  | 	StringName start_request; | ||||||
|  | 	bool start_request_travel; | ||||||
|  | 	bool stop_request; | ||||||
|  | 
 | ||||||
|  | 	bool _travel(AnimationNodeStateMachine *p_state_machine, const StringName &p_travel); | ||||||
|  | 
 | ||||||
|  | 	float process(AnimationNodeStateMachine *p_state_machine, float p_time, bool p_seek); | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  | 	static void _bind_methods(); | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  | 	void travel(const StringName &p_state); | ||||||
|  | 	void start(const StringName &p_state); | ||||||
|  | 	void stop(); | ||||||
|  | 	bool is_playing() const; | ||||||
|  | 	StringName get_current_node() const; | ||||||
|  | 	StringName get_blend_from_node() const; | ||||||
|  | 	Vector<StringName> get_travel_path() const; | ||||||
|  | 	float get_current_play_pos() const; | ||||||
|  | 	float get_current_length() const; | ||||||
|  | 
 | ||||||
|  | 	AnimationNodeStateMachinePlayback(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class AnimationNodeStateMachine : public AnimationRootNode { | ||||||
|  | 
 | ||||||
|  | 	GDCLASS(AnimationNodeStateMachine, AnimationRootNode); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  | 	friend class AnimationNodeStateMachinePlayback; | ||||||
|  | 
 | ||||||
|  | 	struct State { | ||||||
|  | 		Ref<AnimationRootNode> node; | ||||||
|  | 		Vector2 position; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	Map<StringName, State> states; | ||||||
|  | 
 | ||||||
|  | 	struct Transition { | ||||||
|  | 
 | ||||||
|  | 		StringName from; | ||||||
|  | 		StringName to; | ||||||
|  | 		Ref<AnimationNodeStateMachineTransition> transition; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	Vector<Transition> transitions; | ||||||
|  | 
 | ||||||
|  | 	StringName playback; | ||||||
|  | 
 | ||||||
|  | 	StringName start_node; | ||||||
|  | 	StringName end_node; | ||||||
|  | 
 | ||||||
|  | 	Vector2 graph_offset; | ||||||
|  | 
 | ||||||
|  | 	void _tree_changed(); | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
| 	void _notification(int p_what); | 	void _notification(int p_what); | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
|  | @ -94,7 +143,10 @@ protected: | ||||||
| 	void _get_property_list(List<PropertyInfo> *p_list) const; | 	void _get_property_list(List<PropertyInfo> *p_list) const; | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 	void add_node(const StringName &p_name, Ref<AnimationNode> p_node); | 	virtual void get_parameter_list(List<PropertyInfo> *r_list) const; | ||||||
|  | 	virtual Variant get_parameter_default_value(const StringName &p_parameter) const; | ||||||
|  | 
 | ||||||
|  | 	void add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position = Vector2()); | ||||||
| 	Ref<AnimationNode> get_node(const StringName &p_name) const; | 	Ref<AnimationNode> get_node(const StringName &p_name) const; | ||||||
| 	void remove_node(const StringName &p_name); | 	void remove_node(const StringName &p_name); | ||||||
| 	void rename_node(const StringName &p_name, const StringName &p_new_name); | 	void rename_node(const StringName &p_name, const StringName &p_new_name); | ||||||
|  | @ -102,6 +154,11 @@ public: | ||||||
| 	StringName get_node_name(const Ref<AnimationNode> &p_node) const; | 	StringName get_node_name(const Ref<AnimationNode> &p_node) const; | ||||||
| 	void get_node_list(List<StringName> *r_nodes) const; | 	void get_node_list(List<StringName> *r_nodes) const; | ||||||
| 
 | 
 | ||||||
|  | 	void set_node_position(const StringName &p_name, const Vector2 &p_position); | ||||||
|  | 	Vector2 get_node_position(const StringName &p_name) const; | ||||||
|  | 
 | ||||||
|  | 	virtual void get_child_nodes(List<ChildNode> *r_child_nodes); | ||||||
|  | 
 | ||||||
| 	bool has_transition(const StringName &p_from, const StringName &p_to) const; | 	bool has_transition(const StringName &p_from, const StringName &p_to) const; | ||||||
| 	int find_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); | 	void add_transition(const StringName &p_from, const StringName &p_to, const Ref<AnimationNodeStateMachineTransition> &p_transition); | ||||||
|  | @ -124,17 +181,7 @@ public: | ||||||
| 	virtual float process(float p_time, bool p_seek); | 	virtual float process(float p_time, bool p_seek); | ||||||
| 	virtual String get_caption() const; | 	virtual String get_caption() const; | ||||||
| 
 | 
 | ||||||
| 	bool travel(const StringName &p_state); | 	virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name); | ||||||
| 	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(); | 	AnimationNodeStateMachine(); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -5,6 +5,38 @@ | ||||||
| #include "scene/scene_string_names.h" | #include "scene/scene_string_names.h" | ||||||
| #include "servers/audio/audio_stream.h" | #include "servers/audio/audio_stream.h" | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const { | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter) const { | ||||||
|  | 	return Variant(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AnimationNode::set_parameter(const StringName& p_name, const Variant& p_value) { | ||||||
|  | 	ERR_FAIL_COND(!state); | ||||||
|  | 	ERR_FAIL_COND(!state->tree->property_parent_map.has(base_path)); | ||||||
|  | 	ERR_FAIL_COND(!state->tree->property_parent_map[base_path].has(p_name)); | ||||||
|  | 	StringName path = state->tree->property_parent_map[base_path][p_name]; | ||||||
|  | 
 | ||||||
|  | 	state->tree->property_map[path]=p_value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Variant AnimationNode::get_parameter(const StringName& p_name) const { | ||||||
|  | 	ERR_FAIL_COND_V(!state,Variant()); | ||||||
|  | 	ERR_FAIL_COND_V(!state->tree->property_parent_map.has(base_path),Variant()); | ||||||
|  | 	ERR_FAIL_COND_V(!state->tree->property_parent_map[base_path].has(p_name),Variant()); | ||||||
|  | 
 | ||||||
|  | 	StringName path = state->tree->property_parent_map[base_path][p_name]; | ||||||
|  | 	return state->tree->property_map[path]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) { | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void AnimationNode::blend_animation(const StringName &p_animation, float p_time, float p_delta, bool p_seeked, float p_blend) { | void AnimationNode::blend_animation(const StringName &p_animation, float p_time, float p_delta, bool p_seeked, float p_blend) { | ||||||
| 
 | 
 | ||||||
| 	ERR_FAIL_COND(!state); | 	ERR_FAIL_COND(!state); | ||||||
|  | @ -14,8 +46,8 @@ void AnimationNode::blend_animation(const StringName &p_animation, float p_time, | ||||||
| 
 | 
 | ||||||
| 	if (animation.is_null()) { | 	if (animation.is_null()) { | ||||||
| 
 | 
 | ||||||
| 		Ref<AnimationNodeBlendTree> btree = get_parent(); | 		AnimationNodeBlendTree* btree = Object::cast_to<AnimationNodeBlendTree>(parent); | ||||||
| 		if (btree.is_valid()) { | 		if (btree) { | ||||||
| 			String name = btree->get_node_name(Ref<AnimationNodeAnimation>(this)); | 			String name = btree->get_node_name(Ref<AnimationNodeAnimation>(this)); | ||||||
| 			make_invalid(vformat(RTR("In node '%s', invalid animation: '%s'."), name, p_animation)); | 			make_invalid(vformat(RTR("In node '%s', invalid animation: '%s'."), name, p_animation)); | ||||||
| 		} else { | 		} else { | ||||||
|  | @ -37,10 +69,20 @@ void AnimationNode::blend_animation(const StringName &p_animation, float p_time, | ||||||
| 	state->animation_states.push_back(anim_state); | 	state->animation_states.push_back(anim_state); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| float AnimationNode::_pre_process(State *p_state, float p_time, bool p_seek) { | float AnimationNode::_pre_process(const StringName& p_base_path, AnimationNode *p_parent, State *p_state, float p_time, bool p_seek, const Vector<StringName>& p_connections) { | ||||||
|  | 
 | ||||||
|  | 	base_path = p_base_path; | ||||||
|  | 	parent = p_parent; | ||||||
|  | 	connections=p_connections; | ||||||
| 	state = p_state; | 	state = p_state; | ||||||
|  | 
 | ||||||
| 	float t = process(p_time, p_seek); | 	float t = process(p_time, p_seek); | ||||||
|  | 
 | ||||||
| 	state = NULL; | 	state = NULL; | ||||||
|  | 	parent = NULL; | ||||||
|  | 	base_path = StringName(); | ||||||
|  | 	connections.clear(); | ||||||
|  | 
 | ||||||
| 	return t; | 	return t; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -56,39 +98,31 @@ void AnimationNode::make_invalid(const String &p_reason) { | ||||||
| float AnimationNode::blend_input(int p_input, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) { | 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_INDEX_V(p_input, inputs.size(), 0); | ||||||
| 	ERR_FAIL_COND_V(!state, 0); | 	ERR_FAIL_COND_V(!state, 0); | ||||||
| 	ERR_FAIL_COND_V(!get_tree(), 0); //should not happen, but used to catch bugs
 |  | ||||||
| 
 | 
 | ||||||
| 	Ref<AnimationNodeBlendTree> tree = get_parent(); | 	AnimationNodeBlendTree* blend_tree = Object::cast_to<AnimationNodeBlendTree>(parent); | ||||||
|  | 	ERR_FAIL_COND_V(!blend_tree,0); | ||||||
| 
 | 
 | ||||||
| 	if (!tree.is_valid() && get_tree()->get_tree_root().ptr() != this) { | 	StringName node_name = connections[p_input]; | ||||||
| 		make_invalid(RTR("Can't blend input because node is not in a tree")); |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	ERR_FAIL_COND_V(!tree.is_valid(), 0); //should not happen
 | 	if (!blend_tree->has_node(node_name)) { | ||||||
| 
 | 		String name = blend_tree->get_node_name(Ref<AnimationNode>(this)); | ||||||
| 	StringName anim_name = inputs[p_input].connected_to; |  | ||||||
| 
 |  | ||||||
| 	Ref<AnimationNode> node = tree->get_node(anim_name); |  | ||||||
| 
 |  | ||||||
| 	if (node.is_null()) { |  | ||||||
| 
 |  | ||||||
| 		String name = tree->get_node_name(Ref<AnimationNodeAnimation>(this)); |  | ||||||
| 		make_invalid(vformat(RTR("Nothing connected to input '%s' of node '%s'."), get_input_name(p_input), name)); | 		make_invalid(vformat(RTR("Nothing connected to input '%s' of node '%s'."), get_input_name(p_input), name)); | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	inputs.write[p_input].last_pass = state->last_pass; | 	Ref<AnimationNode> node = blend_tree->get_node(node_name); | ||||||
| 
 | 
 | ||||||
| 	return _blend_node(node, p_time, p_seek, p_blend, p_filter, p_optimize, &inputs.write[p_input].activity); | 	//inputs.write[p_input].last_pass = state->last_pass;
 | ||||||
|  | 	float activity; | ||||||
|  | 	return _blend_node(node_name,blend_tree->get_node_connection_array(node_name),NULL,node, p_time, p_seek, p_blend, p_filter, p_optimize, &activity); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| float AnimationNode::blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) { | float AnimationNode::blend_node(const StringName& p_sub_path,Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) { | ||||||
| 
 | 
 | ||||||
| 	return _blend_node(p_node, p_time, p_seek, p_blend, p_filter, p_optimize); | 	return _blend_node(p_sub_path,Vector<StringName>(),this,p_node, p_time, p_seek, p_blend, p_filter, p_optimize); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| float AnimationNode::_blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize, float *r_max) { | float AnimationNode::_blend_node(const StringName &p_subpath, const Vector<StringName>& p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize, float *r_max) { | ||||||
| 
 | 
 | ||||||
| 	ERR_FAIL_COND_V(!p_node.is_valid(), 0); | 	ERR_FAIL_COND_V(!p_node.is_valid(), 0); | ||||||
| 	ERR_FAIL_COND_V(!state, 0); | 	ERR_FAIL_COND_V(!state, 0); | ||||||
|  | @ -189,7 +223,19 @@ float AnimationNode::_blend_node(Ref<AnimationNode> p_node, float p_time, bool p | ||||||
| 	if (!p_seek && p_optimize && !any_valid) //pointless to go on, all are zero
 | 	if (!p_seek && p_optimize && !any_valid) //pointless to go on, all are zero
 | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	return p_node->_pre_process(state, p_time, p_seek); | 	String new_path; | ||||||
|  | 	AnimationNode *new_parent; | ||||||
|  | 
 | ||||||
|  | 	//this is the slowest part of processing, but as strings process in powers of 2, and the paths always exist, it will not result in that many allocations
 | ||||||
|  | 	if (p_new_parent) { | ||||||
|  | 		new_parent = p_new_parent; | ||||||
|  | 		new_path = String(base_path)+String(p_subpath)+"/"; | ||||||
|  | 	} else { | ||||||
|  | 		ERR_FAIL_COND_V(!parent,0); | ||||||
|  | 		new_parent = parent; | ||||||
|  | 		new_path = String(parent->base_path) + String(p_subpath)+"/"; | ||||||
|  | 	} | ||||||
|  | 	return p_node->_pre_process(new_path,new_parent,state, p_time, p_seek, p_connections); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int AnimationNode::get_input_count() const { | int AnimationNode::get_input_count() const { | ||||||
|  | @ -201,28 +247,6 @@ String AnimationNode::get_input_name(int p_input) { | ||||||
| 	return inputs[p_input].name; | 	return inputs[p_input].name; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| float AnimationNode::get_input_activity(int p_input) const { |  | ||||||
| 
 |  | ||||||
| 	ERR_FAIL_INDEX_V(p_input, inputs.size(), 0); |  | ||||||
| 	if (!get_tree()) |  | ||||||
| 		return 0; |  | ||||||
| 
 |  | ||||||
| 	if (get_tree()->get_last_process_pass() != inputs[p_input].last_pass) { |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
| 	return inputs[p_input].activity; |  | ||||||
| } |  | ||||||
| StringName AnimationNode::get_input_connection(int p_input) { |  | ||||||
| 
 |  | ||||||
| 	ERR_FAIL_INDEX_V(p_input, inputs.size(), StringName()); |  | ||||||
| 	return inputs[p_input].connected_to; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void AnimationNode::set_input_connection(int p_input, const StringName &p_connection) { |  | ||||||
| 
 |  | ||||||
| 	ERR_FAIL_INDEX(p_input, inputs.size()); |  | ||||||
| 	inputs.write[p_input].connected_to = p_connection; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| String AnimationNode::get_caption() const { | String AnimationNode::get_caption() const { | ||||||
| 
 | 
 | ||||||
|  | @ -239,8 +263,6 @@ void AnimationNode::add_input(const String &p_name) { | ||||||
| 	Input input; | 	Input input; | ||||||
| 	ERR_FAIL_COND(p_name.find(".") != -1 || p_name.find("/") != -1); | 	ERR_FAIL_COND(p_name.find(".") != -1 || p_name.find("/") != -1); | ||||||
| 	input.name = p_name; | 	input.name = p_name; | ||||||
| 	input.activity = 0; |  | ||||||
| 	input.last_pass = 0; |  | ||||||
| 	inputs.push_back(input); | 	inputs.push_back(input); | ||||||
| 	emit_changed(); | 	emit_changed(); | ||||||
| } | } | ||||||
|  | @ -258,35 +280,6 @@ void AnimationNode::remove_input(int p_index) { | ||||||
| 	emit_changed(); | 	emit_changed(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNode::_set_parent(Object *p_parent) { |  | ||||||
| 	set_parent(Object::cast_to<AnimationNode>(p_parent)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void AnimationNode::set_parent(AnimationNode *p_parent) { |  | ||||||
| 	parent = p_parent; //do not use ref because parent contains children
 |  | ||||||
| 	if (get_script_instance()) { |  | ||||||
| 		get_script_instance()->call("_parent_set", p_parent); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Ref<AnimationNode> AnimationNode::get_parent() const { |  | ||||||
| 	if (parent) { |  | ||||||
| 		return Ref<AnimationNode>(parent); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return Ref<AnimationNode>(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| AnimationTree *AnimationNode::get_tree() const { |  | ||||||
| 
 |  | ||||||
| 	return player; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| AnimationPlayer *AnimationNode::get_player() const { |  | ||||||
| 	ERR_FAIL_COND_V(!state, NULL); |  | ||||||
| 	return state->player; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| float AnimationNode::process(float p_time, bool p_seek) { | float AnimationNode::process(float p_time, bool p_seek) { | ||||||
| 
 | 
 | ||||||
| 	if (get_script_instance()) { | 	if (get_script_instance()) { | ||||||
|  | @ -320,21 +313,7 @@ bool AnimationNode::has_filter() const { | ||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationNode::set_position(const Vector2 &p_position) { |  | ||||||
| 	position = p_position; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| Vector2 AnimationNode::get_position() const { |  | ||||||
| 	return position; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void AnimationNode::set_tree(AnimationTree *p_player) { |  | ||||||
| 
 |  | ||||||
| 	if (player != NULL && p_player == NULL) { |  | ||||||
| 		emit_signal("removed_from_graph"); |  | ||||||
| 	} |  | ||||||
| 	player = p_player; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| Array AnimationNode::_get_filters() const { | Array AnimationNode::_get_filters() const { | ||||||
| 
 | 
 | ||||||
|  | @ -361,12 +340,14 @@ void AnimationNode::_validate_property(PropertyInfo &property) const { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Ref<AnimationNode> AnimationNode::get_child_by_name(const StringName &p_name) { | ||||||
|  | 	return Ref<AnimationNode>(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void AnimationNode::_bind_methods() { | void AnimationNode::_bind_methods() { | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("get_input_count"), &AnimationNode::get_input_count); | 	ClassDB::bind_method(D_METHOD("get_input_count"), &AnimationNode::get_input_count); | ||||||
| 	ClassDB::bind_method(D_METHOD("get_input_name", "input"), &AnimationNode::get_input_name); | 	ClassDB::bind_method(D_METHOD("get_input_name", "input"), &AnimationNode::get_input_name); | ||||||
| 	ClassDB::bind_method(D_METHOD("get_input_connection", "input"), &AnimationNode::get_input_connection); |  | ||||||
| 	ClassDB::bind_method(D_METHOD("get_input_activity", "input"), &AnimationNode::get_input_activity); |  | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("add_input", "name"), &AnimationNode::add_input); | 	ClassDB::bind_method(D_METHOD("add_input", "name"), &AnimationNode::add_input); | ||||||
| 	ClassDB::bind_method(D_METHOD("remove_input", "index"), &AnimationNode::remove_input); | 	ClassDB::bind_method(D_METHOD("remove_input", "index"), &AnimationNode::remove_input); | ||||||
|  | @ -377,19 +358,16 @@ void AnimationNode::_bind_methods() { | ||||||
| 	ClassDB::bind_method(D_METHOD("set_filter_enabled", "enable"), &AnimationNode::set_filter_enabled); | 	ClassDB::bind_method(D_METHOD("set_filter_enabled", "enable"), &AnimationNode::set_filter_enabled); | ||||||
| 	ClassDB::bind_method(D_METHOD("is_filter_enabled"), &AnimationNode::is_filter_enabled); | 	ClassDB::bind_method(D_METHOD("is_filter_enabled"), &AnimationNode::is_filter_enabled); | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("set_position", "position"), &AnimationNode::set_position); |  | ||||||
| 	ClassDB::bind_method(D_METHOD("get_position"), &AnimationNode::get_position); |  | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("_set_filters", "filters"), &AnimationNode::_set_filters); | 	ClassDB::bind_method(D_METHOD("_set_filters", "filters"), &AnimationNode::_set_filters); | ||||||
| 	ClassDB::bind_method(D_METHOD("_get_filters"), &AnimationNode::_get_filters); | 	ClassDB::bind_method(D_METHOD("_get_filters"), &AnimationNode::_get_filters); | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "blend"), &AnimationNode::blend_animation); | 	ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "blend"), &AnimationNode::blend_animation); | ||||||
| 	ClassDB::bind_method(D_METHOD("blend_node", "node", "time", "seek", "blend", "filter", "optimize"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true)); | 	ClassDB::bind_method(D_METHOD("blend_node", "name","node", "time", "seek", "blend", "filter", "optimize"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true)); | ||||||
| 	ClassDB::bind_method(D_METHOD("blend_input", "input_index", "time", "seek", "blend", "filter", "optimize"), &AnimationNode::blend_input, DEFVAL(FILTER_IGNORE), DEFVAL(true)); | 	ClassDB::bind_method(D_METHOD("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("set_parameter","name","value"), &AnimationNode::set_parameter); | ||||||
| 	ClassDB::bind_method(D_METHOD("get_parent"), &AnimationNode::get_parent); | 	ClassDB::bind_method(D_METHOD("get_parameter","name"), &AnimationNode::get_parameter); | ||||||
| 	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::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"); | 	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "filters", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_filters", "_get_filters"); | ||||||
|  | @ -397,9 +375,11 @@ void AnimationNode::_bind_methods() { | ||||||
| 	BIND_VMETHOD(MethodInfo("process", PropertyInfo(Variant::REAL, "time"), PropertyInfo(Variant::BOOL, "seek"))); | 	BIND_VMETHOD(MethodInfo("process", PropertyInfo(Variant::REAL, "time"), PropertyInfo(Variant::BOOL, "seek"))); | ||||||
| 	BIND_VMETHOD(MethodInfo(Variant::STRING, "get_caption")); | 	BIND_VMETHOD(MethodInfo(Variant::STRING, "get_caption")); | ||||||
| 	BIND_VMETHOD(MethodInfo(Variant::STRING, "has_filter")); | 	BIND_VMETHOD(MethodInfo(Variant::STRING, "has_filter")); | ||||||
| 	BIND_VMETHOD(MethodInfo("_parent_set", PropertyInfo(Variant::OBJECT, "parent"))); |  | ||||||
| 
 | 
 | ||||||
| 	ADD_SIGNAL(MethodInfo("removed_from_graph")); | 	ADD_SIGNAL(MethodInfo("removed_from_graph")); | ||||||
|  | 
 | ||||||
|  | 	ADD_SIGNAL(MethodInfo("tree_changed")); | ||||||
|  | 
 | ||||||
| 	BIND_ENUM_CONSTANT(FILTER_IGNORE); | 	BIND_ENUM_CONSTANT(FILTER_IGNORE); | ||||||
| 	BIND_ENUM_CONSTANT(FILTER_PASS); | 	BIND_ENUM_CONSTANT(FILTER_PASS); | ||||||
| 	BIND_ENUM_CONSTANT(FILTER_STOP); | 	BIND_ENUM_CONSTANT(FILTER_STOP); | ||||||
|  | @ -410,8 +390,6 @@ AnimationNode::AnimationNode() { | ||||||
| 
 | 
 | ||||||
| 	state = NULL; | 	state = NULL; | ||||||
| 	parent = NULL; | 	parent = NULL; | ||||||
| 	player = NULL; |  | ||||||
| 	set_local_to_scene(true); |  | ||||||
| 	filter_enabled = false; | 	filter_enabled = false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -420,18 +398,17 @@ AnimationNode::AnimationNode() { | ||||||
| void AnimationTree::set_tree_root(const Ref<AnimationNode> &p_root) { | void AnimationTree::set_tree_root(const Ref<AnimationNode> &p_root) { | ||||||
| 
 | 
 | ||||||
| 	if (root.is_valid()) { | 	if (root.is_valid()) { | ||||||
| 		root->set_tree(NULL); | 		root->disconnect("tree_changed",this,"_tree_changed"); | ||||||
| 	} |  | ||||||
| 	if (p_root.is_valid()) { |  | ||||||
| 		ERR_EXPLAIN("root node already set to another player"); |  | ||||||
| 		ERR_FAIL_COND(p_root->player); |  | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
| 	root = p_root; | 	root = p_root; | ||||||
| 
 | 
 | ||||||
| 	if (root.is_valid()) { | 	if (root.is_valid()) { | ||||||
| 		root->set_tree(this); | 		root->connect("tree_changed",this,"_tree_changed"); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	properties_dirty=true; | ||||||
|  | 
 | ||||||
| 	update_configuration_warning(); | 	update_configuration_warning(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -699,7 +676,10 @@ void AnimationTree::_clear_caches() { | ||||||
| 
 | 
 | ||||||
| void AnimationTree::_process_graph(float p_delta) { | void AnimationTree::_process_graph(float p_delta) { | ||||||
| 
 | 
 | ||||||
|  | 	_update_properties(); //if properties need updating, update them
 | ||||||
|  | 
 | ||||||
| 	//check all tracks, see if they need modification
 | 	//check all tracks, see if they need modification
 | ||||||
|  | 
 | ||||||
| 	root_motion_transform = Transform(); | 	root_motion_transform = Transform(); | ||||||
| 
 | 
 | ||||||
| 	if (!root.is_valid()) { | 	if (!root.is_valid()) { | ||||||
|  | @ -741,6 +721,7 @@ void AnimationTree::_process_graph(float p_delta) { | ||||||
| 		state.valid = true; | 		state.valid = true; | ||||||
| 		state.player = player; | 		state.player = player; | ||||||
| 		state.last_pass = process_pass; | 		state.last_pass = process_pass; | ||||||
|  | 		state.tree = this; | ||||||
| 
 | 
 | ||||||
| 		// root source blends
 | 		// root source blends
 | ||||||
| 
 | 
 | ||||||
|  | @ -757,11 +738,11 @@ void AnimationTree::_process_graph(float p_delta) { | ||||||
| 
 | 
 | ||||||
| 		if (started) { | 		if (started) { | ||||||
| 			//if started, seek
 | 			//if started, seek
 | ||||||
| 			root->_pre_process(&state, 0, true); | 			root->_pre_process(SceneStringNames::get_singleton()->parameters_base_path,NULL,&state, 0, true,Vector<StringName>()); | ||||||
| 			started = false; | 			started = false; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		root->_pre_process(&state, p_delta, false); | 		root->_pre_process(SceneStringNames::get_singleton()->parameters_base_path,NULL,&state, p_delta, false,Vector<StringName>()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (!state.valid) { | 	if (!state.valid) { | ||||||
|  | @ -1297,6 +1278,117 @@ Transform AnimationTree::get_root_motion_transform() const { | ||||||
| 	return root_motion_transform; | 	return root_motion_transform; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void AnimationTree::_tree_changed() { | ||||||
|  | 	if (properties_dirty) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	call_deferred("_update_properties"); | ||||||
|  | 	properties_dirty=true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AnimationTree::_update_properties_for_node(const String& p_base_path,Ref<AnimationNode> node) { | ||||||
|  | 
 | ||||||
|  | 	if (!property_parent_map.has(p_base_path)) { | ||||||
|  | 		property_parent_map[p_base_path]=HashMap<StringName, StringName>(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	List<PropertyInfo> plist; | ||||||
|  | 	node->get_parameter_list(&plist); | ||||||
|  | 	for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) { | ||||||
|  | 		PropertyInfo pinfo = E->get(); | ||||||
|  | 
 | ||||||
|  | 		StringName key = pinfo.name; | ||||||
|  | 
 | ||||||
|  | 		if (!property_map.has(p_base_path +key)) { | ||||||
|  | 			property_map[p_base_path + key] = node->get_parameter_default_value(key); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		property_parent_map[p_base_path][key]=p_base_path+key; | ||||||
|  | 
 | ||||||
|  | 		pinfo.name = p_base_path + key; | ||||||
|  | 		properties.push_back(pinfo); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	List<AnimationNode::ChildNode> children; | ||||||
|  | 	node->get_child_nodes(&children); | ||||||
|  | 
 | ||||||
|  | 	for (List<AnimationNode::ChildNode>::Element *E=children.front();E;E=E->next()) { | ||||||
|  | 		_update_properties_for_node(p_base_path+E->get().name+"/",E->get().node); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AnimationTree::_update_properties() { | ||||||
|  | 	if (!properties_dirty) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	properties.clear(); | ||||||
|  | 	property_parent_map.clear(); | ||||||
|  | 
 | ||||||
|  | 	if (root.is_valid()) { | ||||||
|  | 		_update_properties_for_node(SceneStringNames::get_singleton()->parameters_base_path,root); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	properties_dirty = false; | ||||||
|  | 
 | ||||||
|  | 	_change_notify(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool AnimationTree::_set(const StringName &p_name, const Variant &p_value) { | ||||||
|  | 	if (properties_dirty) { | ||||||
|  | 		_update_properties(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (property_map.has(p_name)) { | ||||||
|  | 		property_map[p_name]=p_value; | ||||||
|  | #ifdef TOOLS_ENABLED | ||||||
|  | 		_change_notify(p_name.operator String().utf8().get_data()); | ||||||
|  | #endif | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool AnimationTree::_get(const StringName &p_name, Variant &r_ret) const { | ||||||
|  | 	if (properties_dirty) { | ||||||
|  | 		const_cast<AnimationTree*>(this)->_update_properties(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (property_map.has(p_name)) { | ||||||
|  | 		r_ret=property_map[p_name]; | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | void AnimationTree::_get_property_list(List<PropertyInfo> *p_list) const { | ||||||
|  | 	if (properties_dirty) { | ||||||
|  | 		const_cast<AnimationTree*>(this)->_update_properties(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for (const List<PropertyInfo>::Element *E=properties.front();E;E=E->next()) { | ||||||
|  | 		p_list->push_back(E->get()); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AnimationTree::rename_parameter(const String& p_base,const String& p_new_base) { | ||||||
|  | 
 | ||||||
|  | 	//rename values first
 | ||||||
|  | 	for (const List<PropertyInfo>::Element *E=properties.front();E;E=E->next()) { | ||||||
|  | 		if (E->get().name.begins_with(p_base)) { | ||||||
|  | 			String new_name = E->get().name.replace_first(p_base,p_new_base); | ||||||
|  | 			property_map[new_name]=property_map[E->get().name]; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	//update tree second
 | ||||||
|  | 	properties_dirty=true; | ||||||
|  | 	_update_properties(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void AnimationTree::_bind_methods() { | void AnimationTree::_bind_methods() { | ||||||
| 	ClassDB::bind_method(D_METHOD("set_active", "active"), &AnimationTree::set_active); | 	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("is_active"), &AnimationTree::is_active); | ||||||
|  | @ -1315,11 +1407,17 @@ void AnimationTree::_bind_methods() { | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("get_root_motion_transform"), &AnimationTree::get_root_motion_transform); | 	ClassDB::bind_method(D_METHOD("get_root_motion_transform"), &AnimationTree::get_root_motion_transform); | ||||||
| 
 | 
 | ||||||
|  | 	ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationTree::_tree_changed); | ||||||
|  | 	ClassDB::bind_method(D_METHOD("_update_properties"), &AnimationTree::_update_properties); | ||||||
|  | 
 | ||||||
|  | 	ClassDB::bind_method(D_METHOD("rename_parameter","old_name","new_name"), &AnimationTree::rename_parameter); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationTree::advance); | 	ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationTree::advance); | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("_node_removed"), &AnimationTree::_node_removed); | 	ClassDB::bind_method(D_METHOD("_node_removed"), &AnimationTree::_node_removed); | ||||||
| 
 | 
 | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_tree_root", "get_tree_root"); | 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode"), "set_tree_root", "get_tree_root"); | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationPlayer"), "set_animation_player", "get_animation_player"); | 	ADD_PROPERTY(PropertyInfo(Variant::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::BOOL, "active"), "set_active", "is_active"); | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_process_mode", "get_process_mode"); | 	ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_process_mode", "get_process_mode"); | ||||||
|  | @ -1338,10 +1436,9 @@ AnimationTree::AnimationTree() { | ||||||
| 	cache_valid = false; | 	cache_valid = false; | ||||||
| 	setup_pass = 1; | 	setup_pass = 1; | ||||||
| 	started = true; | 	started = true; | ||||||
|  | 	properties_dirty = true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AnimationTree::~AnimationTree() { | AnimationTree::~AnimationTree() { | ||||||
| 	if (root.is_valid()) { | 
 | ||||||
| 		root->player = NULL; |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -23,9 +23,6 @@ public: | ||||||
| 	struct Input { | 	struct Input { | ||||||
| 
 | 
 | ||||||
| 		String name; | 		String name; | ||||||
| 		StringName connected_to; |  | ||||||
| 		float activity; |  | ||||||
| 		uint64_t last_pass; |  | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	Vector<Input> inputs; | 	Vector<Input> inputs; | ||||||
|  | @ -51,30 +48,33 @@ public: | ||||||
| 		List<AnimationState> animation_states; | 		List<AnimationState> animation_states; | ||||||
| 		bool valid; | 		bool valid; | ||||||
| 		AnimationPlayer *player; | 		AnimationPlayer *player; | ||||||
|  | 		AnimationTree *tree; | ||||||
| 		String invalid_reasons; | 		String invalid_reasons; | ||||||
| 		uint64_t last_pass; | 		uint64_t last_pass; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	Vector<float> blends; | 	Vector<float> blends; | ||||||
| 	State *state; | 	State *state; | ||||||
| 	float _pre_process(State *p_state, float p_time, bool p_seek); | 	String path; | ||||||
|  | 	float _pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, float p_time, bool p_seek, const Vector<StringName> &p_connections); | ||||||
| 	void _pre_update_animations(HashMap<NodePath, int> *track_map); | 	void _pre_update_animations(HashMap<NodePath, int> *track_map); | ||||||
| 	Vector2 position; |  | ||||||
| 
 | 
 | ||||||
|  | 	//all this is temporary
 | ||||||
|  | 	StringName base_path; | ||||||
|  | 	Vector<StringName> connections; | ||||||
| 	AnimationNode *parent; | 	AnimationNode *parent; | ||||||
| 	AnimationTree *player; |  | ||||||
| 
 |  | ||||||
| 	float _blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true, float *r_max = NULL); |  | ||||||
| 
 | 
 | ||||||
| 	HashMap<NodePath, bool> filter; | 	HashMap<NodePath, bool> filter; | ||||||
| 	bool filter_enabled; | 	bool filter_enabled; | ||||||
| 
 | 
 | ||||||
| 	Array _get_filters() const; | 	Array _get_filters() const; | ||||||
| 	void _set_filters(const Array &p_filters); | 	void _set_filters(const Array &p_filters); | ||||||
|  | 	friend class AnimationNodeBlendTree; | ||||||
|  | 	float _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true, float *r_max = NULL); | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
| 	void blend_animation(const StringName &p_animation, float p_time, float p_delta, bool p_seeked, float p_blend); | 	void blend_animation(const StringName &p_animation, float p_time, float p_delta, bool p_seeked, float p_blend); | ||||||
| 	float blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true); | 	float blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true); | ||||||
| 	float blend_input(int p_input, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true); | 	float blend_input(int p_input, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true); | ||||||
| 	void make_invalid(const String &p_reason); | 	void make_invalid(const String &p_reason); | ||||||
| 
 | 
 | ||||||
|  | @ -85,20 +85,24 @@ protected: | ||||||
| 	void _set_parent(Object *p_parent); | 	void _set_parent(Object *p_parent); | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 	void set_parent(AnimationNode *p_parent); | 	virtual void get_parameter_list(List<PropertyInfo> *r_list) const; | ||||||
| 	Ref<AnimationNode> get_parent() const; | 	virtual Variant get_parameter_default_value(const StringName &p_parameter) const; | ||||||
| 	virtual void set_tree(AnimationTree *p_player); | 
 | ||||||
| 	AnimationTree *get_tree() const; | 	void set_parameter(const StringName &p_name, const Variant &p_value); | ||||||
| 	AnimationPlayer *get_player() const; | 	Variant get_parameter(const StringName &p_name) const; | ||||||
|  | 
 | ||||||
|  | 	struct ChildNode { | ||||||
|  | 		StringName name; | ||||||
|  | 		Ref<AnimationNode> node; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	virtual void get_child_nodes(List<ChildNode> *r_child_nodes); | ||||||
| 
 | 
 | ||||||
| 	virtual float process(float p_time, bool p_seek); | 	virtual float process(float p_time, bool p_seek); | ||||||
| 	virtual String get_caption() const; | 	virtual String get_caption() const; | ||||||
| 
 | 
 | ||||||
| 	int get_input_count() const; | 	int get_input_count() const; | ||||||
| 	String get_input_name(int p_input); | 	String get_input_name(int p_input); | ||||||
| 	StringName get_input_connection(int p_input); |  | ||||||
| 	void set_input_connection(int p_input, const StringName &p_connection); |  | ||||||
| 	float get_input_activity(int p_input) const; |  | ||||||
| 
 | 
 | ||||||
| 	void add_input(const String &p_name); | 	void add_input(const String &p_name); | ||||||
| 	void set_input_name(int p_input, const String &p_name); | 	void set_input_name(int p_input, const String &p_name); | ||||||
|  | @ -112,8 +116,7 @@ public: | ||||||
| 
 | 
 | ||||||
| 	virtual bool has_filter() const; | 	virtual bool has_filter() const; | ||||||
| 
 | 
 | ||||||
| 	void set_position(const Vector2 &p_position); | 	virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name); | ||||||
| 	Vector2 get_position() const; |  | ||||||
| 
 | 
 | ||||||
| 	AnimationNode(); | 	AnimationNode(); | ||||||
| }; | }; | ||||||
|  | @ -245,7 +248,21 @@ private: | ||||||
| 	NodePath root_motion_track; | 	NodePath root_motion_track; | ||||||
| 	Transform root_motion_transform; | 	Transform root_motion_transform; | ||||||
| 
 | 
 | ||||||
|  | 	friend class AnimationNode; | ||||||
|  | 	bool properties_dirty; | ||||||
|  | 	void _tree_changed(); | ||||||
|  | 	void _update_properties(); | ||||||
|  | 	List<PropertyInfo> properties; | ||||||
|  | 	HashMap<StringName, HashMap<StringName, StringName> > property_parent_map; | ||||||
|  | 	HashMap<StringName, Variant> property_map; | ||||||
|  | 
 | ||||||
|  | 	void _update_properties_for_node(const String &p_base_path, Ref<AnimationNode> node); | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
|  | 	bool _set(const StringName &p_name, const Variant &p_value); | ||||||
|  | 	bool _get(const StringName &p_name, Variant &r_ret) const; | ||||||
|  | 	void _get_property_list(List<PropertyInfo> *p_list) const; | ||||||
|  | 
 | ||||||
| 	void _notification(int p_what); | 	void _notification(int p_what); | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
| 
 | 
 | ||||||
|  | @ -274,6 +291,8 @@ public: | ||||||
| 
 | 
 | ||||||
| 	void advance(float p_time); | 	void advance(float p_time); | ||||||
| 
 | 
 | ||||||
|  | 	void rename_parameter(const String &p_base, const String &p_new_base); | ||||||
|  | 
 | ||||||
| 	uint64_t get_last_process_pass() const; | 	uint64_t get_last_process_pass() const; | ||||||
| 	AnimationTree(); | 	AnimationTree(); | ||||||
| 	~AnimationTree(); | 	~AnimationTree(); | ||||||
|  |  | ||||||
|  | @ -356,14 +356,14 @@ bool GraphEdit::_filter_input(const Point2 &p_point) { | ||||||
| 		for (int j = 0; j < gn->get_connection_output_count(); j++) { | 		for (int j = 0; j < gn->get_connection_output_count(); j++) { | ||||||
| 
 | 
 | ||||||
| 			Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); | 			Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); | ||||||
| 			if (create_hot_zone(pos).has_point(p_point)) | 			if (is_in_hot_zone(pos, p_point)) | ||||||
| 				return true; | 				return true; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		for (int j = 0; j < gn->get_connection_input_count(); j++) { | 		for (int j = 0; j < gn->get_connection_input_count(); j++) { | ||||||
| 
 | 
 | ||||||
| 			Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); | 			Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); | ||||||
| 			if (create_hot_zone(pos).has_point(p_point)) { | 			if (is_in_hot_zone(pos, p_point)) { | ||||||
| 				return true; | 				return true; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | @ -388,7 +388,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { | ||||||
| 			for (int j = 0; j < gn->get_connection_output_count(); j++) { | 			for (int j = 0; j < gn->get_connection_output_count(); j++) { | ||||||
| 
 | 
 | ||||||
| 				Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); | 				Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); | ||||||
| 				if (create_hot_zone(pos).has_point(mpos)) { | 				if (is_in_hot_zone(pos, mpos)) { | ||||||
| 
 | 
 | ||||||
| 					if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) { | 					if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) { | ||||||
| 						//check disconnect
 | 						//check disconnect
 | ||||||
|  | @ -435,7 +435,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { | ||||||
| 			for (int j = 0; j < gn->get_connection_input_count(); j++) { | 			for (int j = 0; j < gn->get_connection_input_count(); j++) { | ||||||
| 
 | 
 | ||||||
| 				Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); | 				Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); | ||||||
| 				if (create_hot_zone(pos).has_point(mpos)) { | 				if (is_in_hot_zone(pos, mpos)) { | ||||||
| 
 | 
 | ||||||
| 					if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) { | 					if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) { | ||||||
| 						//check disconnect
 | 						//check disconnect
 | ||||||
|  | @ -502,7 +502,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { | ||||||
| 
 | 
 | ||||||
| 					Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); | 					Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); | ||||||
| 					int type = gn->get_connection_output_type(j); | 					int type = gn->get_connection_output_type(j); | ||||||
| 					if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && create_hot_zone(pos).has_point(mpos)) { | 					if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos, mpos)) { | ||||||
| 
 | 
 | ||||||
| 						connecting_target = true; | 						connecting_target = true; | ||||||
| 						connecting_to = pos; | 						connecting_to = pos; | ||||||
|  | @ -517,7 +517,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { | ||||||
| 
 | 
 | ||||||
| 					Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); | 					Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); | ||||||
| 					int type = gn->get_connection_input_type(j); | 					int type = gn->get_connection_input_type(j); | ||||||
| 					if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && create_hot_zone(pos).has_point(mpos)) { | 					if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos, mpos)) { | ||||||
| 						connecting_target = true; | 						connecting_target = true; | ||||||
| 						connecting_to = pos; | 						connecting_to = pos; | ||||||
| 						connecting_target_to = gn->get_name(); | 						connecting_target_to = gn->get_name(); | ||||||
|  | @ -557,8 +557,55 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Rect2 GraphEdit::create_hot_zone(const Vector2 &pos) { | bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &pos) { | ||||||
| 	return Rect2(pos.x - port_grab_distance_horizontal, pos.y - port_grab_distance_vertical, port_grab_distance_horizontal * 2, port_grab_distance_vertical * 2); | 
 | ||||||
|  | 	if (p_control->is_set_as_toplevel() || !p_control->is_visible()) | ||||||
|  | 		return false; | ||||||
|  | 
 | ||||||
|  | 	if (!p_control->has_point(pos) || p_control->get_mouse_filter() == MOUSE_FILTER_IGNORE) { | ||||||
|  | 		//test children
 | ||||||
|  | 		for (int i = 0; i < p_control->get_child_count(); i++) { | ||||||
|  | 			Control *subchild = Object::cast_to<Control>(p_control->get_child(i)); | ||||||
|  | 			if (!subchild) | ||||||
|  | 				continue; | ||||||
|  | 			if (_check_clickable_control(subchild, pos - subchild->get_position())) { | ||||||
|  | 				return true; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return false; | ||||||
|  | 	} else { | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool GraphEdit::is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos) { | ||||||
|  | 	if (!Rect2(pos.x - port_grab_distance_horizontal, pos.y - port_grab_distance_vertical, port_grab_distance_horizontal * 2, port_grab_distance_vertical * 2).has_point(p_mouse_pos)) | ||||||
|  | 		return false; | ||||||
|  | 
 | ||||||
|  | 	for (int i = 0; i < get_child_count(); i++) { | ||||||
|  | 		Control *child = Object::cast_to<Control>(get_child(i)); | ||||||
|  | 		if (!child) | ||||||
|  | 			continue; | ||||||
|  | 		Rect2 rect = child->get_rect(); | ||||||
|  | 		if (rect.has_point(p_mouse_pos)) { | ||||||
|  | 
 | ||||||
|  | 			//check sub-controls
 | ||||||
|  | 			Vector2 subpos = p_mouse_pos - rect.position; | ||||||
|  | 
 | ||||||
|  | 			for (int j = 0; j < child->get_child_count(); j++) { | ||||||
|  | 				Control *subchild = Object::cast_to<Control>(child->get_child(j)); | ||||||
|  | 				if (!subchild) | ||||||
|  | 					continue; | ||||||
|  | 
 | ||||||
|  | 				if (_check_clickable_control(subchild, subpos - subchild->get_position())) { | ||||||
|  | 					return false; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template <class Vector2> | template <class Vector2> | ||||||
|  |  | ||||||
|  | @ -131,7 +131,7 @@ private: | ||||||
| 	GraphEditFilter *top_layer; | 	GraphEditFilter *top_layer; | ||||||
| 	void _top_layer_input(const Ref<InputEvent> &p_ev); | 	void _top_layer_input(const Ref<InputEvent> &p_ev); | ||||||
| 
 | 
 | ||||||
| 	Rect2 create_hot_zone(const Vector2 &pos); | 	bool is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos); | ||||||
| 
 | 
 | ||||||
| 	void _top_layer_draw(); | 	void _top_layer_draw(); | ||||||
| 	void _connections_layer_draw(); | 	void _connections_layer_draw(); | ||||||
|  | @ -172,6 +172,8 @@ private: | ||||||
| 	void _snap_toggled(); | 	void _snap_toggled(); | ||||||
| 	void _snap_value_changed(double); | 	void _snap_value_changed(double); | ||||||
| 
 | 
 | ||||||
|  | 	bool _check_clickable_control(Control *p_control, const Vector2 &pos); | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
| 	virtual void add_child_notify(Node *p_child); | 	virtual void add_child_notify(Node *p_child); | ||||||
|  |  | ||||||
|  | @ -412,6 +412,8 @@ void register_scene_types() { | ||||||
| 	ClassDB::register_class<AnimationNodeBlendSpace1D>(); | 	ClassDB::register_class<AnimationNodeBlendSpace1D>(); | ||||||
| 	ClassDB::register_class<AnimationNodeBlendSpace2D>(); | 	ClassDB::register_class<AnimationNodeBlendSpace2D>(); | ||||||
| 	ClassDB::register_class<AnimationNodeStateMachine>(); | 	ClassDB::register_class<AnimationNodeStateMachine>(); | ||||||
|  | 	ClassDB::register_class<AnimationNodeStateMachinePlayback>(); | ||||||
|  | 
 | ||||||
| 	ClassDB::register_class<AnimationNodeStateMachineTransition>(); | 	ClassDB::register_class<AnimationNodeStateMachineTransition>(); | ||||||
| 	ClassDB::register_class<AnimationNodeOutput>(); | 	ClassDB::register_class<AnimationNodeOutput>(); | ||||||
| 	ClassDB::register_class<AnimationNodeOneShot>(); | 	ClassDB::register_class<AnimationNodeOneShot>(); | ||||||
|  |  | ||||||
|  | @ -201,4 +201,6 @@ SceneStringNames::SceneStringNames() { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	_mesh_changed = StaticCString::create("_mesh_changed"); | 	_mesh_changed = StaticCString::create("_mesh_changed"); | ||||||
|  | 
 | ||||||
|  | 	parameters_base_path = "parameters/"; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -203,6 +203,8 @@ public: | ||||||
| 
 | 
 | ||||||
| 	StringName output; | 	StringName output; | ||||||
| 
 | 
 | ||||||
|  | 	StringName parameters_base_path; | ||||||
|  | 
 | ||||||
| 	enum { | 	enum { | ||||||
| 		MAX_MATERIALS = 32 | 		MAX_MATERIALS = 32 | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Juan Linietsky
						Juan Linietsky