Vector<String> AnimationTreeEditor::get_animation_list() { if (!singleton->is_visible()) { return Vector<String>(); } AnimationTree *tree = singleton->tree; if (!tree || !tree->has_node(tree->get_animation_player())) return Vector<String>(); AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(tree->get_node(tree->get_animation_player())); if (!ap) return Vector<String>(); List<StringName> anims; ap->get_animation_list(&anims); Vector<String> ret; for (List<StringName>::Element *E = anims.front(); E; E = E->next()) { ret.push_back(E->get()); } return ret; }
Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>,Ref<Shape> > &collision_map,uint32_t p_flags,Set<Ref<ImageTexture> >& image_map) { // children first.. for(int i=0;i<p_node->get_child_count();i++) { Node *r = _fix_node(p_node->get_child(i),p_root,collision_map,p_flags,image_map); if (!r) { print_line("was erased.."); i--; //was erased } } String name = p_node->get_name(); bool isroot = p_node==p_root; if (!isroot && p_flags&SCENE_FLAG_REMOVE_NOIMP && _teststr(name,"noimp")) { memdelete(p_node); return NULL; } { List<PropertyInfo> pl; p_node->get_property_list(&pl); for(List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) { if (E->get().type==Variant::OBJECT || E->get().type==Variant::ARRAY || E->get().type==Variant::DICTIONARY) { _find_resources(p_node->get(E->get().name),image_map); } } } if (p_flags&SCENE_FLAG_CREATE_BILLBOARDS && p_node->cast_to<MeshInstance>()) { MeshInstance *mi = p_node->cast_to<MeshInstance>(); bool bb=false; if ((_teststr(name,"bb"))) { bb=true; } else if (mi->get_mesh().is_valid() && (_teststr(mi->get_mesh()->get_name(),"bb"))) { bb=true; } if (bb) { mi->set_flag(GeometryInstance::FLAG_BILLBOARD,true); if (mi->get_mesh().is_valid()) { Ref<Mesh> m = mi->get_mesh(); for(int i=0;i<m->get_surface_count();i++) { Ref<FixedMaterial> fm = m->surface_get_material(i); if (fm.is_valid()) { fm->set_flag(Material::FLAG_UNSHADED,true); fm->set_flag(Material::FLAG_DOUBLE_SIDED,true); fm->set_hint(Material::HINT_NO_DEPTH_DRAW,true); fm->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true); } } } } } if (p_flags&SCENE_FLAG_REMOVE_NOIMP && p_node->cast_to<AnimationPlayer>()) { //remove animations referencing non-importable nodes AnimationPlayer *ap = p_node->cast_to<AnimationPlayer>(); List<StringName> anims; ap->get_animation_list(&anims); for(List<StringName>::Element *E=anims.front();E;E=E->next()) { Ref<Animation> anim=ap->get_animation(E->get()); ERR_CONTINUE(anim.is_null()); for(int i=0;i<anim->get_track_count();i++) { NodePath path = anim->track_get_path(i); for(int j=0;j<path.get_name_count();j++) { String node = path.get_name(j); if (_teststr(node,"noimp")) { anim->remove_track(i); i--; break; } } } } } if (p_flags&SCENE_FLAG_CREATE_IMPOSTORS && p_node->cast_to<MeshInstance>()) { MeshInstance *mi = p_node->cast_to<MeshInstance>(); String str; if ((_teststr(name,"imp"))) { str=name; } else if (mi->get_mesh().is_valid() && (_teststr(mi->get_mesh()->get_name(),"imp"))) { str=mi->get_mesh()->get_name(); } if (p_node->get_parent() && p_node->get_parent()->cast_to<MeshInstance>()) { MeshInstance *mi = p_node->cast_to<MeshInstance>(); MeshInstance *mip = p_node->get_parent()->cast_to<MeshInstance>(); String d=str.substr(str.find("imp")+3,str.length()); if (d!="") { if ((d[0]<'0' || d[0]>'9')) d=d.substr(1,d.length()); if (d.length() && d[0]>='0' && d[0]<='9') { float dist = d.to_double(); mi->set_flag(GeometryInstance::FLAG_BILLBOARD,true); mi->set_flag(GeometryInstance::FLAG_BILLBOARD_FIX_Y,true); mi->set_draw_range_begin(dist); mi->set_draw_range_end(100000); mip->set_draw_range_begin(0); mip->set_draw_range_end(dist); if (mi->get_mesh().is_valid()) { Ref<Mesh> m = mi->get_mesh(); for(int i=0;i<m->get_surface_count();i++) { Ref<FixedMaterial> fm = m->surface_get_material(i); if (fm.is_valid()) { fm->set_flag(Material::FLAG_UNSHADED,true); fm->set_flag(Material::FLAG_DOUBLE_SIDED,true); fm->set_hint(Material::HINT_NO_DEPTH_DRAW,true); fm->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true); } } } } } } } if (p_flags&SCENE_FLAG_CREATE_LODS && p_node->cast_to<MeshInstance>()) { MeshInstance *mi = p_node->cast_to<MeshInstance>(); String str; if ((_teststr(name,"lod"))) { str=name; } else if (mi->get_mesh().is_valid() && (_teststr(mi->get_mesh()->get_name(),"lod"))) { str=mi->get_mesh()->get_name(); } if (p_node->get_parent() && p_node->get_parent()->cast_to<MeshInstance>()) { MeshInstance *mi = p_node->cast_to<MeshInstance>(); MeshInstance *mip = p_node->get_parent()->cast_to<MeshInstance>(); String d=str.substr(str.find("lod")+3,str.length()); if (d!="") { if ((d[0]<'0' || d[0]>'9')) d=d.substr(1,d.length()); if (d.length() && d[0]>='0' && d[0]<='9') { float dist = d.to_double(); mi->set_draw_range_begin(dist); mi->set_draw_range_end(100000); mip->set_draw_range_begin(0); mip->set_draw_range_end(dist); /*if (mi->get_mesh().is_valid()) { Ref<Mesh> m = mi->get_mesh(); for(int i=0;i<m->get_surface_count();i++) { Ref<FixedMaterial> fm = m->surface_get_material(i); if (fm.is_valid()) { fm->set_flag(Material::FLAG_UNSHADED,true); fm->set_flag(Material::FLAG_DOUBLE_SIDED,true); fm->set_hint(Material::HINT_NO_DEPTH_DRAW,true); fm->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true); } } }*/ } } } } if (p_flags&SCENE_FLAG_CREATE_COLLISIONS && _teststr(name,"colonly") && p_node->cast_to<MeshInstance>()) { if (isroot) return p_node; MeshInstance *mi = p_node->cast_to<MeshInstance>(); Node * col = mi->create_trimesh_collision_node(); ERR_FAIL_COND_V(!col,NULL); col->set_name(_fixstr(name,"colonly")); col->cast_to<Spatial>()->set_transform(mi->get_transform()); p_node->replace_by(col); memdelete(p_node); p_node=col; } else if (p_flags&SCENE_FLAG_CREATE_COLLISIONS &&_teststr(name,"col") && p_node->cast_to<MeshInstance>()) { MeshInstance *mi = p_node->cast_to<MeshInstance>(); mi->set_name(_fixstr(name,"col")); mi->create_trimesh_collision(); } else if (p_flags&SCENE_FLAG_CREATE_ROOMS && _teststr(name,"room") && p_node->cast_to<MeshInstance>()) { if (isroot) return p_node; MeshInstance *mi = p_node->cast_to<MeshInstance>(); DVector<Face3> faces = mi->get_faces(VisualInstance::FACES_SOLID); BSP_Tree bsptree(faces); Ref<RoomBounds> area = memnew( RoomBounds ); area->set_bounds(faces); area->set_geometry_hint(faces); Room * room = memnew( Room ); room->set_name(_fixstr(name,"room")); room->set_transform(mi->get_transform()); room->set_room(area); p_node->replace_by(room); memdelete(p_node); p_node=room; } else if (p_flags&SCENE_FLAG_CREATE_ROOMS &&_teststr(name,"room")) { if (isroot) return p_node; Spatial *dummy = p_node->cast_to<Spatial>(); ERR_FAIL_COND_V(!dummy,NULL); Room * room = memnew( Room ); room->set_name(_fixstr(name,"room")); room->set_transform(dummy->get_transform()); p_node->replace_by(room); memdelete(p_node); p_node=room; room->compute_room_from_subtree(); } else if (p_flags&SCENE_FLAG_CREATE_PORTALS &&_teststr(name,"portal") && p_node->cast_to<MeshInstance>()) { if (isroot) return p_node; MeshInstance *mi = p_node->cast_to<MeshInstance>(); DVector<Face3> faces = mi->get_faces(VisualInstance::FACES_SOLID); ERR_FAIL_COND_V(faces.size()==0,NULL); //step 1 compute the plane Set<Vector3> points; Plane plane; Vector3 center; for(int i=0;i<faces.size();i++) { Face3 f = faces.get(i); Plane p = f.get_plane(); plane.normal+=p.normal; plane.d+=p.d; for(int i=0;i<3;i++) { Vector3 v = f.vertex[i].snapped(0.01); if (!points.has(v)) { points.insert(v); center+=v; } } } plane.normal.normalize(); plane.d/=faces.size(); center/=points.size(); //step 2, create points Transform t; t.basis.from_z(plane.normal); t.basis.transpose(); t.origin=center; Vector<Point2> portal_points; for(Set<Vector3>::Element *E=points.front();E;E=E->next()) { Vector3 local = t.xform_inv(E->get()); portal_points.push_back(Point2(local.x,local.y)); } // step 3 bubbly sort points int swaps=0; do { swaps=0; for(int i=0;i<portal_points.size()-1;i++) { float a = portal_points[i].atan2(); float b = portal_points[i+1].atan2(); if (a>b) { SWAP( portal_points[i], portal_points[i+1] ); swaps++; } } } while(swaps); Portal *portal = memnew( Portal ); portal->set_shape(portal_points); portal->set_transform( mi->get_transform() * t); p_node->replace_by(portal); memdelete(p_node); p_node=portal; } else if (p_node->cast_to<MeshInstance>()) { //last attempt, maybe collision insde the mesh data MeshInstance *mi = p_node->cast_to<MeshInstance>(); Ref<Mesh> mesh = mi->get_mesh(); if (!mesh.is_null()) { if (p_flags&SCENE_FLAG_CREATE_COLLISIONS && _teststr(mesh->get_name(),"col")) { mesh->set_name( _fixstr(mesh->get_name(),"col") ); Ref<Shape> shape; if (collision_map.has(mesh)) { shape = collision_map[mesh]; } else { shape = mesh->create_trimesh_shape(); if (!shape.is_null()) collision_map[mesh]=shape; } if (!shape.is_null()) { #if 0 StaticBody* static_body = memnew( StaticBody ); ERR_FAIL_COND_V(!static_body,NULL); static_body->set_name( String(mesh->get_name()) + "_col" ); shape->set_name(static_body->get_name()); static_body->add_shape(shape); mi->add_child(static_body); if (mi->get_owner()) static_body->set_owner( mi->get_owner() ); #endif } } for(int i=0;i<mesh->get_surface_count();i++) { Ref<FixedMaterial> fm = mesh->surface_get_material(i); if (fm.is_valid()) { String name = fm->get_name(); if (_teststr(name,"alpha")) { fm->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true); name=_fixstr(name,"alpha"); } if (_teststr(name,"vcol")) { fm->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY,true); name=_fixstr(name,"vcol"); } fm->set_name(name); } } } } return p_node; }
void AnimationTreeEditor::_popup_edit_dialog() { updating_edit=true; for(int i=0;i<2;i++) edit_scroll[i]->hide(); for(int i=0;i<4;i++) { edit_line[i]->hide(); edit_label[i]->hide(); } edit_option->hide(); edit_button->hide();; filter_button->hide(); edit_check->hide();; Point2 pos = anim_tree->node_get_pos(edited_node)-Point2(h_scroll->get_val(),v_scroll->get_val()); Ref<StyleBox> style = get_stylebox("panel","PopupMenu"); Size2 size = get_node_size(edited_node); Point2 popup_pos( pos.x+style->get_margin(MARGIN_LEFT), pos.y+size.y-style->get_margin(MARGIN_BOTTOM)); popup_pos+=get_global_pos(); if (renaming_edit) { edit_label[0]->set_text("New name:"); edit_label[0]->set_pos(Point2(5,5)); edit_label[0]->show(); edit_line[0]->set_begin(Point2(15,25)); edit_line[0]->set_text(edited_node); edit_line[0]->show(); edit_dialog->set_size(Size2(150,50)); } else { AnimationTreePlayer::NodeType type=anim_tree->node_get_type(edited_node); switch(type) { case AnimationTreePlayer::NODE_ANIMATION: if (anim_tree->get_master_player()!=NodePath() && anim_tree->has_node(anim_tree->get_master_player()) && anim_tree->get_node(anim_tree->get_master_player())->cast_to<AnimationPlayer>()) { AnimationPlayer *ap = anim_tree->get_node(anim_tree->get_master_player())->cast_to<AnimationPlayer>(); master_anim_popup->clear(); List<StringName> sn; ap->get_animation_list(&sn); sn.sort_custom<StringName::AlphCompare>(); for (List<StringName>::Element *E=sn.front();E;E=E->next()) { master_anim_popup->add_item(E->get()); } master_anim_popup->set_pos(popup_pos); master_anim_popup->popup(); } else { property_editor->edit(this,"",Variant::OBJECT,anim_tree->animation_node_get_animation(edited_node),PROPERTY_HINT_RESOURCE_TYPE,"Animation"); property_editor->set_pos(popup_pos); property_editor->popup(); updating_edit=false; } return; case AnimationTreePlayer::NODE_TIMESCALE: edit_label[0]->set_text("Scale:"); edit_label[0]->set_pos(Point2(5,5)); edit_label[0]->show(); edit_line[0]->set_begin(Point2(15,25)); edit_line[0]->set_text(rtos(anim_tree->timescale_node_get_scale(edited_node))); edit_line[0]->show(); edit_dialog->set_size(Size2(150,50)); break; case AnimationTreePlayer::NODE_ONESHOT: edit_label[0]->set_text("Fade In (s):"); edit_label[0]->set_pos(Point2(5,5)); edit_label[0]->show(); edit_line[0]->set_begin(Point2(15,25)); edit_line[0]->set_text(rtos(anim_tree->oneshot_node_get_fadein_time(edited_node))); edit_line[0]->show(); edit_label[1]->set_text("Fade Out (s):"); edit_label[1]->set_pos(Point2(5,55)); edit_label[1]->show(); edit_line[1]->set_begin(Point2(15,75)); edit_line[1]->set_text(rtos(anim_tree->oneshot_node_get_fadeout_time(edited_node))); edit_line[1]->show(); edit_option->clear(); edit_option->add_item("Blend",0); edit_option->add_item("Mix",1); edit_option->set_begin(Point2(15,105)); edit_option->select( anim_tree->oneshot_node_get_mix_mode(edited_node)); edit_option->show(); edit_check->set_text("Auto Restart:"); edit_check->set_begin(Point2(15,125)); edit_check->set_pressed(anim_tree->oneshot_node_has_autorestart(edited_node)); edit_check->show(); edit_label[2]->set_text("Restart (s):"); edit_label[2]->set_pos(Point2(5,145)); edit_label[2]->show(); edit_line[2]->set_begin(Point2(15,165)); edit_line[2]->set_text(rtos(anim_tree->oneshot_node_get_autorestart_delay(edited_node))); edit_line[2]->show(); edit_label[3]->set_text("Random Restart (s):"); edit_label[3]->set_pos(Point2(5,195)); edit_label[3]->show(); edit_line[3]->set_begin(Point2(15,215)); edit_line[3]->set_text(rtos(anim_tree->oneshot_node_get_autorestart_random_delay(edited_node))); edit_line[3]->show(); filter_button->set_begin(Point2(10,245)); filter_button->show(); edit_button->set_begin(Point2(10,268)); edit_button->set_text("Start!"); edit_button->show(); edit_dialog->set_size(Size2(180,293)); break; case AnimationTreePlayer::NODE_MIX: edit_label[0]->set_text("Amount:"); edit_label[0]->set_pos(Point2(5,5)); edit_label[0]->show(); edit_scroll[0]->set_min(0); edit_scroll[0]->set_max(1); edit_scroll[0]->set_val(anim_tree->mix_node_get_amount(edited_node)); edit_scroll[0]->set_begin(Point2(15,25)); edit_scroll[0]->show(); edit_dialog->set_size(Size2(150,50)); break; case AnimationTreePlayer::NODE_BLEND2: edit_label[0]->set_text("Blend:"); edit_label[0]->set_pos(Point2(5,5)); edit_label[0]->show(); edit_scroll[0]->set_min(0); edit_scroll[0]->set_max(1); edit_scroll[0]->set_val(anim_tree->blend2_node_get_amount(edited_node)); edit_scroll[0]->set_begin(Point2(15,25)); edit_scroll[0]->show(); filter_button->set_begin(Point2(10,47)); filter_button->show(); edit_dialog->set_size(Size2(150,74)); break; case AnimationTreePlayer::NODE_BLEND3: edit_label[0]->set_text("Blend:"); edit_label[0]->set_pos(Point2(5,5)); edit_label[0]->show(); edit_scroll[0]->set_min(-1); edit_scroll[0]->set_max(1); edit_scroll[0]->set_val(anim_tree->blend3_node_get_amount(edited_node)); edit_scroll[0]->set_begin(Point2(15,25)); edit_scroll[0]->show(); edit_dialog->set_size(Size2(150,50)); break; case AnimationTreePlayer::NODE_BLEND4: edit_label[0]->set_text("Blend 0:"); edit_label[0]->set_pos(Point2(5,5)); edit_label[0]->show(); edit_scroll[0]->set_min(0); edit_scroll[0]->set_max(1); edit_scroll[0]->set_val(anim_tree->blend4_node_get_amount(edited_node).x); edit_scroll[0]->set_begin(Point2(15,25)); edit_scroll[0]->show(); edit_label[1]->set_text("Blend 1:"); edit_label[1]->set_pos(Point2(5,55)); edit_label[1]->show(); edit_scroll[1]->set_min(0); edit_scroll[1]->set_max(1); edit_scroll[1]->set_val(anim_tree->blend4_node_get_amount(edited_node).y); edit_scroll[1]->set_begin(Point2(15,75)); edit_scroll[1]->show(); edit_dialog->set_size(Size2(150,100)); break; case AnimationTreePlayer::NODE_TRANSITION: { edit_label[0]->set_text("X-Fade Time (s):"); edit_label[0]->set_pos(Point2(5,5)); edit_label[0]->show(); edit_line[0]->set_begin(Point2(15,25)); edit_line[0]->set_text(rtos(anim_tree->transition_node_get_xfade_time(edited_node))); edit_line[0]->show(); edit_label[1]->set_text("Current:"); edit_label[1]->set_pos(Point2(5,55)); edit_label[1]->show(); edit_option->set_begin(Point2(15,75)); edit_option->clear();; for(int i=0;i<anim_tree->transition_node_get_input_count(edited_node);i++) { edit_option->add_item(itos(i),i); } edit_option->select(anim_tree->transition_node_get_current(edited_node)); edit_option->show(); edit_dialog->set_size(Size2(150,100)); } break; default: {} } } edit_dialog->set_pos(popup_pos); edit_dialog->popup(); updating_edit=false; }
void AnimationNodeBlendTreeEditor::_update_graph() { if (updating) return; graph->set_scroll_ofs(blend_tree->get_graph_offset() * EDSCALE); if (blend_tree->get_parent().is_valid()) { goto_parent->show(); } else { goto_parent->hide(); } graph->clear_connections(); //erase all nodes for (int i = 0; i < graph->get_child_count(); i++) { if (Object::cast_to<GraphNode>(graph->get_child(i))) { memdelete(graph->get_child(i)); i--; } } animations.clear(); List<StringName> nodes; blend_tree->get_node_list(&nodes); for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) { GraphNode *node = memnew(GraphNode); graph->add_child(node); Ref<AnimationNode> agnode = blend_tree->get_node(E->get()); if (!agnode->is_connected("changed", this, "_node_changed")) { agnode->connect("changed", this, "_node_changed", varray(agnode->get_instance_id()), CONNECT_DEFERRED); } node->set_offset(agnode->get_position() * EDSCALE); node->set_title(agnode->get_caption()); node->set_name(E->get()); int base = 0; if (String(E->get()) != "output") { LineEdit *name = memnew(LineEdit); name->set_text(E->get()); name->set_expand_to_text_length(true); node->add_child(name); node->set_slot(0, false, 0, Color(), true, 0, get_color("font_color", "Label")); name->connect("text_entered", this, "_node_renamed", varray(agnode)); name->connect("focus_exited", this, "_node_renamed_focus_out", varray(name, agnode)); base = 1; node->set_show_close_button(true); node->connect("close_request", this, "_delete_request", varray(E->get()), CONNECT_DEFERRED); } for (int i = 0; i < agnode->get_input_count(); i++) { Label *in_name = memnew(Label); node->add_child(in_name); in_name->set_text(agnode->get_input_name(i)); node->set_slot(base + i, true, 0, get_color("font_color", "Label"), false, 0, Color()); } node->connect("dragged", this, "_node_dragged", varray(agnode)); if (EditorNode::get_singleton()->item_has_editor(agnode.ptr())) { node->add_child(memnew(HSeparator)); Button *open_in_editor = memnew(Button); open_in_editor->set_text(TTR("Open Editor")); open_in_editor->set_icon(get_icon("Edit", "EditorIcons")); node->add_child(open_in_editor); open_in_editor->connect("pressed", this, "_open_in_editor", varray(E->get()), CONNECT_DEFERRED); open_in_editor->set_h_size_flags(SIZE_SHRINK_CENTER); } if (agnode->has_filter()) { node->add_child(memnew(HSeparator)); Button *edit_filters = memnew(Button); edit_filters->set_text(TTR("Edit Filters")); edit_filters->set_icon(get_icon("AnimationFilter", "EditorIcons")); node->add_child(edit_filters); edit_filters->connect("pressed", this, "_edit_filters", varray(E->get()), CONNECT_DEFERRED); edit_filters->set_h_size_flags(SIZE_SHRINK_CENTER); } Ref<AnimationNodeAnimation> anim = agnode; if (anim.is_valid()) { MenuButton *mb = memnew(MenuButton); mb->set_text(anim->get_animation()); mb->set_icon(get_icon("Animation", "EditorIcons")); Array options; node->add_child(memnew(HSeparator)); node->add_child(mb); ProgressBar *pb = memnew(ProgressBar); AnimationTree *player = anim->get_tree(); if (player->has_node(player->get_animation_player())) { AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(player->get_node(player->get_animation_player())); if (ap) { List<StringName> anims; ap->get_animation_list(&anims); for (List<StringName>::Element *F = anims.front(); F; F = F->next()) { mb->get_popup()->add_item(F->get()); options.push_back(F->get()); } if (ap->has_animation(anim->get_animation())) { pb->set_max(ap->get_animation(anim->get_animation())->get_length()); } } } pb->set_percent_visible(false); animations[E->get()] = pb; node->add_child(pb); mb->get_popup()->connect("index_pressed", this, "_anim_selected", varray(options, E->get()), CONNECT_DEFERRED); } Ref<AnimationNodeOneShot> oneshot = agnode; if (oneshot.is_valid()) { HBoxContainer *play_stop = memnew(HBoxContainer); play_stop->add_spacer(); Button *play = memnew(Button); play->set_icon(get_icon("Play", "EditorIcons")); play->connect("pressed", this, "_oneshot_start", varray(E->get()), CONNECT_DEFERRED); play_stop->add_child(play); Button *stop = memnew(Button); stop->set_icon(get_icon("Stop", "EditorIcons")); stop->connect("pressed", this, "_oneshot_stop", varray(E->get()), CONNECT_DEFERRED); play_stop->add_child(stop); play_stop->add_spacer(); node->add_child(play_stop); } } List<AnimationNodeBlendTree::NodeConnection> connections; blend_tree->get_node_connections(&connections); for (List<AnimationNodeBlendTree::NodeConnection>::Element *E = connections.front(); E; E = E->next()) { StringName from = E->get().output_node; StringName to = E->get().input_node; int to_idx = E->get().input_index; graph->connect_node(from, 0, to, to_idx); } }
bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &anode) { if (updating || _filter_edit != anode) return false; NodePath player_path = anode->get_tree()->get_animation_player(); if (!anode->get_tree()->has_node(player_path)) { EditorNode::get_singleton()->show_warning(TTR("No animation player set, so unable to retrieve track names.")); return false; } AnimationPlayer *player = Object::cast_to<AnimationPlayer>(anode->get_tree()->get_node(player_path)); if (!player) { EditorNode::get_singleton()->show_warning(TTR("Player path set is invalid, so unable to retrieve track names.")); return false; } Node *base = player->get_node(player->get_root()); if (!base) { EditorNode::get_singleton()->show_warning(TTR("Animation player has no valid root node path, so unable to retrieve track names.")); return false; } updating = true; Set<String> paths; { List<StringName> animations; player->get_animation_list(&animations); for (List<StringName>::Element *E = animations.front(); E; E = E->next()) { Ref<Animation> anim = player->get_animation(E->get()); for (int i = 0; i < anim->get_track_count(); i++) { paths.insert(anim->track_get_path(i)); } } } filter_enabled->set_pressed(anode->is_filter_enabled()); filters->clear(); TreeItem *root = filters->create_item(); Map<String, TreeItem *> parenthood; for (Set<String>::Element *E = paths.front(); E; E = E->next()) { NodePath path = E->get(); TreeItem *ti = NULL; String accum; for (int i = 0; i < path.get_name_count(); i++) { String name = path.get_name(i); if (accum != String()) { accum += "/"; } accum += name; if (!parenthood.has(accum)) { if (ti) { ti = filters->create_item(ti); } else { ti = filters->create_item(root); } parenthood[accum] = ti; ti->set_text(0, name); ti->set_selectable(0, false); ti->set_editable(0, false); if (base->has_node(accum)) { Node *node = base->get_node(accum); if (has_icon(node->get_class(), "EditorIcons")) { ti->set_icon(0, get_icon(node->get_class(), "EditorIcons")); } else { ti->set_icon(0, get_icon("Node", "EditorIcons")); } } } else { ti = parenthood[accum]; } } Node *node = NULL; if (base->has_node(accum)) { node = base->get_node(accum); } if (!node) continue; //no node, cant edit if (path.get_subname_count()) { String concat = path.get_concatenated_subnames(); Skeleton *skeleton = Object::cast_to<Skeleton>(node); if (skeleton && skeleton->find_bone(concat) != -1) { //path in skeleton String bone = concat; int idx = skeleton->find_bone(bone); List<String> bone_path; while (idx != -1) { bone_path.push_front(skeleton->get_bone_name(idx)); idx = skeleton->get_bone_parent(idx); } accum += ":"; for (List<String>::Element *F = bone_path.front(); F; F = F->next()) { if (F != bone_path.front()) { accum += "/"; } accum += F->get(); if (!parenthood.has(accum)) { ti = filters->create_item(ti); parenthood[accum] = ti; ti->set_text(0, F->get()); ti->set_selectable(0, false); ti->set_editable(0, false); ti->set_icon(0, get_icon("BoneAttachment", "EditorIcons")); } else { ti = parenthood[accum]; } } ti->set_editable(0, true); ti->set_selectable(0, true); ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); ti->set_text(0, concat); ti->set_checked(0, anode->is_path_filtered(path)); ti->set_icon(0, get_icon("BoneAttachment", "EditorIcons")); ti->set_metadata(0, path); } else { //just a property ti = filters->create_item(ti); ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); ti->set_text(0, concat); ti->set_editable(0, true); ti->set_selectable(0, true); ti->set_checked(0, anode->is_path_filtered(path)); ti->set_metadata(0, path); } } else { if (ti) { //just a node, likely call or animation track ti->set_editable(0, true); ti->set_selectable(0, true); ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); ti->set_checked(0, anode->is_path_filtered(path)); ti->set_metadata(0, path); } } } updating = false; return true; }
void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_DELETE && !k->is_echo()) { if (selected_node != StringName() || selected_transition_to != StringName() || selected_transition_from != StringName()) { _erase_selected(); accept_event(); } } Ref<InputEventMouseButton> mb = p_event; //Add new node if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) || (tool_create->is_pressed() && mb->get_button_index() == BUTTON_LEFT))) { menu->clear(); animations_menu->clear(); animations_to_add.clear(); List<StringName> classes; classes.sort_custom<StringName::AlphCompare>(); ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); menu->add_submenu_item(TTR("Add Animation"), "animations"); AnimationTree *gp = state_machine->get_tree(); ERR_FAIL_COND(!gp); if (gp && gp->has_node(gp->get_animation_player())) { AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player())); if (ap) { List<StringName> names; ap->get_animation_list(&names); for (List<StringName>::Element *E = names.front(); E; E = E->next()) { animations_menu->add_icon_item(get_icon("Animation", "EditorIcons"), E->get()); animations_to_add.push_back(E->get()); } } } for (List<StringName>::Element *E = classes.front(); E; E = E->next()) { String name = String(E->get()).replace_first("AnimationNode", ""); if (name == "Animation") continue; // nope int idx = menu->get_item_count(); menu->add_item(vformat("Add %s", name)); menu->set_item_metadata(idx, E->get()); } menu->set_global_position(state_machine_draw->get_global_transform().xform(mb->get_position())); menu->popup(); add_node_pos = mb->get_position() / EDSCALE + state_machine->get_graph_offset(); } // select node or push a field inside if (mb.is_valid() && !mb->get_shift() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { selected_transition_from = StringName(); selected_transition_to = StringName(); selected_node = StringName(); for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order if (node_rects[i].play.has_point(mb->get_position())) { //edit name if (play_mode->get_selected() == 1 || !state_machine->is_playing()) { //start state_machine->start(node_rects[i].node_name); } else { //travel if (!state_machine->travel(node_rects[i].node_name)) { state_machine->start(node_rects[i].node_name); //removing this due to usability.. //error_time = 5; //error_text = vformat(TTR("No path found from '%s' to '%s'."), state_machine->get_current_node(), node_rects[i].node_name); } } state_machine_draw->update(); return; } if (node_rects[i].name.has_point(mb->get_position())) { //edit name Ref<StyleBox> line_sb = get_stylebox("normal", "LineEdit"); Rect2 edit_rect = node_rects[i].name; edit_rect.position -= line_sb->get_offset(); edit_rect.size += line_sb->get_minimum_size(); name_edit->set_global_position(state_machine_draw->get_global_transform().xform(edit_rect.position)); name_edit->set_size(edit_rect.size); name_edit->set_text(node_rects[i].node_name); name_edit->show_modal(); name_edit->grab_focus(); name_edit->select_all(); prev_name = node_rects[i].node_name; return; } if (node_rects[i].edit.has_point(mb->get_position())) { //edit name call_deferred("_open_editor", node_rects[i].node_name); return; } if (node_rects[i].node.has_point(mb->get_position())) { //select node since nothing else was selected selected_node = node_rects[i].node_name; Ref<AnimationNode> anode = state_machine->get_node(selected_node); EditorNode::get_singleton()->push_item(anode.ptr(), "", true); state_machine_draw->update(); dragging_selected_attempt = true; dragging_selected = false; drag_from = mb->get_position(); snap_x = StringName(); snap_y = StringName(); _update_mode(); return; } } //test the lines now int closest = -1; float closest_d = 1e20; for (int i = 0; i < transition_lines.size(); i++) { Vector2 s[2] = { transition_lines[i].from, transition_lines[i].to }; Vector2 cpoint = Geometry::get_closest_point_to_segment_2d(mb->get_position(), s); float d = cpoint.distance_to(mb->get_position()); if (d > transition_lines[i].width) { continue; } if (d < closest_d) { closest = i; closest_d = d; } } if (closest >= 0) { selected_transition_from = transition_lines[closest].from_node; selected_transition_to = transition_lines[closest].to_node; Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(closest); EditorNode::get_singleton()->push_item(tr.ptr(), "", true); } state_machine_draw->update(); _update_mode(); } //end moving node if (mb.is_valid() && dragging_selected_attempt && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) { if (dragging_selected) { Ref<AnimationNode> an = state_machine->get_node(selected_node); updating = true; undo_redo->create_action("Move Node"); undo_redo->add_do_method(an.ptr(), "set_position", an->get_position() + drag_ofs / EDSCALE); undo_redo->add_undo_method(an.ptr(), "set_position", an->get_position()); undo_redo->add_do_method(this, "_update_graph"); undo_redo->add_undo_method(this, "_update_graph"); undo_redo->commit_action(); updating = false; } snap_x = StringName(); snap_y = StringName(); dragging_selected_attempt = false; dragging_selected = false; state_machine_draw->update(); } //connect nodes if (mb.is_valid() && ((tool_select->is_pressed() && mb->get_shift()) || tool_connect->is_pressed()) && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) { for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order if (node_rects[i].node.has_point(mb->get_position())) { //select node since nothing else was selected connecting = true; connecting_from = node_rects[i].node_name; connecting_to = mb->get_position(); connecting_to_node = StringName(); return; } } } //end connecting nodes if (mb.is_valid() && connecting && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) { if (connecting_to_node != StringName()) { if (state_machine->has_transition(connecting_from, connecting_to_node)) { EditorNode::get_singleton()->show_warning("Transition exists!"); } else { Ref<AnimationNodeStateMachineTransition> tr; tr.instance(); tr->set_switch_mode(AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected())); updating = true; undo_redo->create_action("Add Transition"); undo_redo->add_do_method(state_machine.ptr(), "add_transition", connecting_from, connecting_to_node, tr); undo_redo->add_undo_method(state_machine.ptr(), "remove_transition", connecting_from, connecting_to_node); undo_redo->add_do_method(this, "_update_graph"); undo_redo->add_undo_method(this, "_update_graph"); undo_redo->commit_action(); updating = false; selected_transition_from = connecting_from; selected_transition_to = connecting_to_node; EditorNode::get_singleton()->push_item(tr.ptr(), "", true); _update_mode(); } } connecting_to_node = StringName(); connecting = false; state_machine_draw->update(); } Ref<InputEventMouseMotion> mm = p_event; //pan window if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_MIDDLE) { h_scroll->set_value(h_scroll->get_value() - mm->get_relative().x); v_scroll->set_value(v_scroll->get_value() - mm->get_relative().y); } //move mouse while connecting if (mm.is_valid() && connecting) { connecting_to = mm->get_position(); connecting_to_node = StringName(); state_machine_draw->update(); for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order if (node_rects[i].node_name != connecting_from && node_rects[i].node.has_point(connecting_to)) { //select node since nothing else was selected connecting_to_node = node_rects[i].node_name; return; } } } //move mouse while moving a node if (mm.is_valid() && dragging_selected_attempt) { dragging_selected = true; drag_ofs = mm->get_position() - drag_from; snap_x = StringName(); snap_y = StringName(); { //snap Vector2 cpos = state_machine->get_node(selected_node)->get_position() + drag_ofs / EDSCALE; List<StringName> nodes; state_machine->get_node_list(&nodes); float best_d_x = 1e20; float best_d_y = 1e20; for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) { if (E->get() == selected_node) continue; Vector2 npos = state_machine->get_node(E->get())->get_position(); float d_x = ABS(npos.x - cpos.x); if (d_x < MIN(5, best_d_x)) { drag_ofs.x -= cpos.x - npos.x; best_d_x = d_x; snap_x = E->get(); } float d_y = ABS(npos.y - cpos.y); if (d_y < MIN(5, best_d_y)) { drag_ofs.y -= cpos.y - npos.y; best_d_y = d_y; snap_y = E->get(); } } } state_machine_draw->update(); } //put ibeam (text cursor) over names to make it clearer that they are editable if (mm.is_valid()) { state_machine_draw->grab_focus(); bool over_text_now = false; String new_over_node = StringName(); int new_over_node_what = -1; if (tool_select->is_pressed()) { for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order if (node_rects[i].name.has_point(mm->get_position())) { over_text_now = true; break; } if (node_rects[i].node.has_point(mm->get_position())) { new_over_node = node_rects[i].node_name; if (node_rects[i].play.has_point(mm->get_position())) { new_over_node_what = 0; } if (node_rects[i].edit.has_point(mm->get_position())) { new_over_node_what = 1; } } } } if (new_over_node != over_node || new_over_node_what != over_node_what) { over_node = new_over_node; over_node_what = new_over_node_what; state_machine_draw->update(); } if (over_text != over_text_now) { if (over_text_now) { state_machine_draw->set_default_cursor_shape(CURSOR_IBEAM); } else { state_machine_draw->set_default_cursor_shape(CURSOR_ARROW); } over_text = over_text_now; } } }
void EditorPropertyRootMotion::_node_assign() { NodePath current = get_edited_object()->get(get_edited_property()); AnimationTree *atree = Object::cast_to<AnimationTree>(get_edited_object()); if (!atree->has_node(atree->get_animation_player())) { EditorNode::get_singleton()->show_warning(TTR("AnimationTree has no path set to an AnimationPlayer")); return; } AnimationPlayer *player = Object::cast_to<AnimationPlayer>(atree->get_node(atree->get_animation_player())); if (!player) { EditorNode::get_singleton()->show_warning(TTR("Path to AnimationPlayer is invalid")); return; } Node *base = player->get_node(player->get_root()); if (!base) { EditorNode::get_singleton()->show_warning(TTR("Animation player has no valid root node path, so unable to retrieve track names.")); return; } Set<String> paths; { List<StringName> animations; player->get_animation_list(&animations); for (List<StringName>::Element *E = animations.front(); E; E = E->next()) { Ref<Animation> anim = player->get_animation(E->get()); for (int i = 0; i < anim->get_track_count(); i++) { paths.insert(anim->track_get_path(i)); } } } filters->clear(); TreeItem *root = filters->create_item(); Map<String, TreeItem *> parenthood; for (Set<String>::Element *E = paths.front(); E; E = E->next()) { NodePath path = E->get(); TreeItem *ti = NULL; String accum; for (int i = 0; i < path.get_name_count(); i++) { String name = path.get_name(i); if (accum != String()) { accum += "/"; } accum += name; if (!parenthood.has(accum)) { if (ti) { ti = filters->create_item(ti); } else { ti = filters->create_item(root); } parenthood[accum] = ti; ti->set_text(0, name); ti->set_selectable(0, false); ti->set_editable(0, false); if (base->has_node(accum)) { Node *node = base->get_node(accum); if (has_icon(node->get_class(), "EditorIcons")) { ti->set_icon(0, get_icon(node->get_class(), "EditorIcons")); } else { ti->set_icon(0, get_icon("Node", "EditorIcons")); } } } else { ti = parenthood[accum]; } } Node *node = NULL; if (base->has_node(accum)) { node = base->get_node(accum); } if (!node) continue; //no node, cant edit if (path.get_subname_count()) { String concat = path.get_concatenated_subnames(); Skeleton *skeleton = Object::cast_to<Skeleton>(node); if (skeleton && skeleton->find_bone(concat) != -1) { //path in skeleton String bone = concat; int idx = skeleton->find_bone(bone); List<String> bone_path; while (idx != -1) { bone_path.push_front(skeleton->get_bone_name(idx)); idx = skeleton->get_bone_parent(idx); } accum += ":"; for (List<String>::Element *F = bone_path.front(); F; F = F->next()) { if (F != bone_path.front()) { accum += "/"; } accum += F->get(); if (!parenthood.has(accum)) { ti = filters->create_item(ti); parenthood[accum] = ti; ti->set_text(0, F->get()); ti->set_selectable(0, true); ti->set_editable(0, false); ti->set_icon(0, get_icon("BoneAttachment", "EditorIcons")); ti->set_metadata(0, accum); } else { ti = parenthood[accum]; } } ti->set_selectable(0, true); ti->set_text(0, concat); ti->set_icon(0, get_icon("BoneAttachment", "EditorIcons")); ti->set_metadata(0, path); if (path == current) { ti->select(0); } } else { //just a property ti = filters->create_item(ti); ti->set_text(0, concat); ti->set_selectable(0, true); ti->set_metadata(0, path); if (path == current) { ti->select(0); } } } else { if (ti) { //just a node, likely call or animation track ti->set_selectable(0, true); ti->set_metadata(0, path); if (path == current) { ti->select(0); } } } } filters->ensure_cursor_is_visible(); filter_dialog->popup_centered_ratio(); }
void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_DELETE && !k->is_echo()) { if (selected_point != -1) { _erase_selected(); accept_event(); } } Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) || (mb->get_button_index() == BUTTON_LEFT && tool_create->is_pressed()))) { menu->clear(); animations_menu->clear(); animations_to_add.clear(); List<StringName> classes; ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); classes.sort_custom<StringName::AlphCompare>(); menu->add_submenu_item(TTR("Add Animation"), "animations"); AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree(); ERR_FAIL_COND(!gp); if (gp->has_node(gp->get_animation_player())) { AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player())); if (ap) { List<StringName> names; ap->get_animation_list(&names); for (List<StringName>::Element *E = names.front(); E; E = E->next()) { animations_menu->add_icon_item(get_icon("Animation", "EditorIcons"), E->get()); animations_to_add.push_back(E->get()); } } } for (List<StringName>::Element *E = classes.front(); E; E = E->next()) { String name = String(E->get()).replace_first("AnimationNode", ""); if (name == "Animation") continue; int idx = menu->get_item_count(); menu->add_item(vformat("Add %s", name), idx); menu->set_item_metadata(idx, E->get()); } Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard(); if (clipb.is_valid()) { menu->add_separator(); menu->add_item(TTR("Paste"), MENU_PASTE); } menu->add_separator(); menu->add_item(TTR("Load.."), MENU_LOAD_FILE); menu->set_global_position(blend_space_draw->get_global_transform().xform(mb->get_position())); menu->popup(); add_point_pos = (mb->get_position() / blend_space_draw->get_size()).x; add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); add_point_pos += blend_space->get_min_space(); if (snap->is_pressed()) { add_point_pos = Math::stepify(add_point_pos, blend_space->get_snap()); } } if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { blend_space_draw->update(); // why not // try to see if a point can be selected selected_point = -1; _update_tool_erase(); for (int i = 0; i < points.size(); i++) { if (Math::abs(float(points[i] - mb->get_position().x)) < 10 * EDSCALE) { selected_point = i; Ref<AnimationNode> node = blend_space->get_blend_point_node(i); EditorNode::get_singleton()->push_item(node.ptr(), "", true); dragging_selected_attempt = true; drag_from = mb->get_position(); _update_tool_erase(); _update_edited_point_pos(); return; } } } if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == BUTTON_LEFT) { if (dragging_selected) { // move float point = blend_space->get_blend_point_position(selected_point); point += drag_ofs.x; if (snap->is_pressed()) { point = Math::stepify(point, blend_space->get_snap()); } updating = true; undo_redo->create_action("Move Node Point"); undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point); undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point)); undo_redo->add_do_method(this, "_update_space"); undo_redo->add_undo_method(this, "_update_space"); undo_redo->add_do_method(this, "_update_edited_point_pos"); undo_redo->add_undo_method(this, "_update_edited_point_pos"); undo_redo->commit_action(); updating = false; _update_edited_point_pos(); } dragging_selected_attempt = false; dragging_selected = false; blend_space_draw->update(); } // *set* the blend if (mb.is_valid() && !mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { float blend_pos = mb->get_position().x / blend_space_draw->get_size().x; blend_pos *= blend_space->get_max_space() - blend_space->get_min_space(); blend_pos += blend_space->get_min_space(); AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos); blend_space_draw->update(); } Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid() && !blend_space_draw->has_focus()) { blend_space_draw->grab_focus(); blend_space_draw->update(); } if (mm.is_valid() && dragging_selected_attempt) { dragging_selected = true; drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * ((blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, 0)); blend_space_draw->update(); _update_edited_point_pos(); } if (mm.is_valid() && tool_blend->is_pressed() && mm->get_button_mask() & BUTTON_MASK_LEFT) { float blend_pos = mm->get_position().x / blend_space_draw->get_size().x; blend_pos *= blend_space->get_max_space() - blend_space->get_min_space(); blend_pos += blend_space->get_min_space(); AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos); blend_space_draw->update(); } }