@@ -64,7 +64,7 @@ class SceneImportSettingsData : public Object {
6464
6565 current[p_name] = p_value;
6666
67- // SceneImportSettings must decide if a new collider should be generated or not
67+ // SceneImportSettings must decide if a new collider should be generated or not.
6868 if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE ) {
6969 SceneImportSettings::get_singleton ()->request_generate_collider ();
7070 }
@@ -350,8 +350,12 @@ void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) {
350350 category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE ;
351351 } else if (Object::cast_to<AnimationPlayer>(p_node)) {
352352 category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE ;
353+
354+ animation_player = Object::cast_to<AnimationPlayer>(p_node);
355+ animation_player->connect (SNAME (" animation_finished" ), callable_mp (this , &SceneImportSettings::_animation_finished));
353356 } else if (Object::cast_to<Skeleton3D>(p_node)) {
354357 category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE ;
358+ skeletons.push_back (Object::cast_to<Skeleton3D>(p_node));
355359 } else {
356360 category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE ;
357361 }
@@ -413,7 +417,7 @@ void SceneImportSettings::_update_scene() {
413417 material_tree->clear ();
414418 mesh_tree->clear ();
415419
416- // hidden roots
420+ // Hidden roots.
417421 material_tree->create_item ();
418422 mesh_tree->create_item ();
419423
@@ -432,7 +436,7 @@ void SceneImportSettings::_update_view_gizmos() {
432436
433437 MeshInstance3D *mesh_node = Object::cast_to<MeshInstance3D>(e.value .node );
434438 if (mesh_node == nullptr || mesh_node->get_mesh ().is_null ()) {
435- // Nothing to do
439+ // Nothing to do.
436440 continue ;
437441 }
438442
@@ -591,7 +595,7 @@ void SceneImportSettings::open_settings(const String &p_path, bool p_for_animati
591595 scene_import_settings_data->settings = nullptr ;
592596 scene_import_settings_data->path = p_path;
593597
594- // Visibility
598+ // Visibility.
595599 data_mode->set_tab_hidden (1 , p_for_animation);
596600 data_mode->set_tab_hidden (2 , p_for_animation);
597601 if (p_for_animation) {
@@ -691,12 +695,13 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
691695 scene_import_settings_data->hide_options = false ;
692696
693697 if (p_type == " Node" ) {
694- node_selected->hide (); // always hide just in case
698+ node_selected->hide (); // Always hide just in case.
695699 mesh_preview->hide ();
700+ _reset_animation ();
701+
696702 if (Object::cast_to<Node3D>(scene)) {
697703 Object::cast_to<Node3D>(scene)->show ();
698704 }
699- // NodeData &nd=node_map[p_id];
700705 material_tree->deselect_all ();
701706 mesh_tree->deselect_all ();
702707 NodeData &nd = node_map[p_id];
@@ -734,12 +739,13 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
734739 }
735740 }
736741 } else if (p_type == " Animation" ) {
737- node_selected->hide (); // always hide just in case
742+ node_selected->hide (); // Always hide just in case.
738743 mesh_preview->hide ();
744+ _reset_animation (p_id);
745+
739746 if (Object::cast_to<Node3D>(scene)) {
740747 Object::cast_to<Node3D>(scene)->show ();
741748 }
742- // NodeData &nd=node_map[p_id];
743749 material_tree->deselect_all ();
744750 mesh_tree->deselect_all ();
745751 AnimationData &ad = animation_map[p_id];
@@ -768,6 +774,7 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
768774
769775 mesh_preview->set_mesh (md.mesh );
770776 mesh_preview->show ();
777+ _reset_animation ();
771778
772779 material_tree->deselect_all ();
773780
@@ -780,6 +787,7 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
780787 }
781788
782789 mesh_preview->show ();
790+ _reset_animation ();
783791
784792 MaterialData &md = material_map[p_id];
785793
@@ -836,7 +844,7 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
836844 if (scene_import_settings_data->settings ) {
837845 for (const ResourceImporter::ImportOption &E : options) {
838846 scene_import_settings_data->defaults [E.option .name ] = E.default_value ;
839- // needed for visibility toggling (fails if something is missing)
847+ // Needed for visibility toggling (fails if something is missing).
840848 if (scene_import_settings_data->settings ->has (E.option .name )) {
841849 scene_import_settings_data->current [E.option .name ] = (*scene_import_settings_data->settings )[E.option .name ];
842850 } else {
@@ -850,6 +858,127 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
850858 scene_import_settings_data->notify_property_list_changed ();
851859}
852860
861+ void SceneImportSettings::_inspector_property_edited (const String &p_name) {
862+ if (p_name == " settings/loop_mode" ) {
863+ if (!animation_map.has (selected_id)) {
864+ return ;
865+ }
866+ HashMap<StringName, Variant> settings = animation_map[selected_id].settings ;
867+ if (settings.has (p_name)) {
868+ animation_loop_mode = static_cast <Animation::LoopMode>((int )settings[p_name]);
869+ } else {
870+ animation_loop_mode = Animation::LoopMode::LOOP_NONE ;
871+ }
872+ }
873+ }
874+
875+ void SceneImportSettings::_reset_bone_transforms () {
876+ for (Skeleton3D *skeleton : skeletons) {
877+ skeleton->reset_bone_poses ();
878+ }
879+ }
880+
881+ void SceneImportSettings::_play_animation () {
882+ if (animation_player == nullptr ) {
883+ return ;
884+ }
885+ StringName id = StringName (selected_id);
886+ if (animation_player->has_animation (id)) {
887+ if (animation_player->is_playing ()) {
888+ animation_player->pause ();
889+ animation_play_button->set_icon (get_theme_icon (SNAME (" MainPlay" ), SNAME (" EditorIcons" )));
890+ set_process (false );
891+ } else {
892+ animation_player->play (id);
893+ animation_play_button->set_icon (get_theme_icon (SNAME (" Pause" ), SNAME (" EditorIcons" )));
894+ set_process (true );
895+ }
896+ }
897+ }
898+
899+ void SceneImportSettings::_stop_current_animation () {
900+ animation_pingpong = false ;
901+ animation_player->stop ();
902+ animation_play_button->set_icon (get_theme_icon (SNAME (" MainPlay" ), SNAME (" EditorIcons" )));
903+ animation_slider->set_value_no_signal (0.0 );
904+ set_process (false );
905+ }
906+
907+ void SceneImportSettings::_reset_animation (const String &p_animation_name) {
908+ if (p_animation_name.is_empty ()) {
909+ animation_preview->hide ();
910+
911+ if (animation_player != nullptr && animation_player->is_playing ()) {
912+ animation_player->stop ();
913+ }
914+ animation_play_button->set_icon (get_theme_icon (SNAME (" MainPlay" ), SNAME (" EditorIcons" )));
915+
916+ _reset_bone_transforms ();
917+ set_process (false );
918+ } else {
919+ _reset_bone_transforms ();
920+ animation_preview->show ();
921+
922+ animation_loop_mode = Animation::LoopMode::LOOP_NONE ;
923+ animation_pingpong = false ;
924+
925+ if (animation_map.has (p_animation_name)) {
926+ HashMap<StringName, Variant> settings = animation_map[p_animation_name].settings ;
927+ if (settings.has (" settings/loop_mode" )) {
928+ animation_loop_mode = static_cast <Animation::LoopMode>((int )settings[" settings/loop_mode" ]);
929+ }
930+ }
931+
932+ if (animation_player->is_playing () && animation_loop_mode != Animation::LoopMode::LOOP_NONE ) {
933+ animation_player->play (p_animation_name);
934+ } else {
935+ animation_player->stop (true );
936+ animation_play_button->set_icon (get_theme_icon (SNAME (" MainPlay" ), SNAME (" EditorIcons" )));
937+ animation_player->set_assigned_animation (p_animation_name);
938+ animation_player->seek (0.0 , true );
939+ animation_slider->set_value_no_signal (0.0 );
940+ set_process (false );
941+ }
942+ }
943+ }
944+
945+ void SceneImportSettings::_animation_slider_value_changed (double p_value) {
946+ if (animation_player == nullptr || !animation_map.has (selected_id) || animation_map[selected_id].animation .is_null ()) {
947+ return ;
948+ }
949+ if (animation_player->is_playing ()) {
950+ animation_player->stop ();
951+ animation_play_button->set_icon (get_theme_icon (SNAME (" MainPlay" ), SNAME (" EditorIcons" )));
952+ set_process (false );
953+ }
954+ animation_player->seek (p_value * animation_map[selected_id].animation ->get_length (), true );
955+ }
956+
957+ void SceneImportSettings::_animation_finished (const StringName &p_name) {
958+ Animation::LoopMode loop_mode = animation_loop_mode;
959+
960+ switch (loop_mode) {
961+ case Animation::LOOP_NONE : {
962+ animation_play_button->set_icon (get_theme_icon (SNAME (" MainPlay" ), SNAME (" EditorIcons" )));
963+ animation_slider->set_value_no_signal (1.0 );
964+ set_process (false );
965+ } break ;
966+ case Animation::LOOP_LINEAR : {
967+ animation_player->play (p_name);
968+ } break ;
969+ case Animation::LOOP_PINGPONG : {
970+ if (animation_pingpong) {
971+ animation_player->play (p_name);
972+ } else {
973+ animation_player->play_backwards (p_name);
974+ }
975+ animation_pingpong = !animation_pingpong;
976+ } break ;
977+ default : {
978+ } break ;
979+ }
980+ }
981+
853982void SceneImportSettings::_material_tree_selected () {
854983 if (selecting) {
855984 return ;
@@ -884,6 +1013,15 @@ void SceneImportSettings::_scene_tree_selected() {
8841013 _select (scene_tree, type, import_id);
8851014}
8861015
1016+ void SceneImportSettings::_cleanup () {
1017+ skeletons.clear ();
1018+ if (animation_player != nullptr ) {
1019+ animation_player->disconnect (SNAME (" animation_finished" ), callable_mp (this , &SceneImportSettings::_animation_finished));
1020+ animation_player = nullptr ;
1021+ }
1022+ set_process (false );
1023+ }
1024+
8871025void SceneImportSettings::_viewport_input (const Ref<InputEvent> &p_input) {
8881026 float *rot_x = &cam_rot_x;
8891027 float *rot_y = &cam_rot_y;
@@ -1005,6 +1143,25 @@ void SceneImportSettings::_notification(int p_what) {
10051143 action_menu->add_theme_style_override (" normal" , get_theme_stylebox (" normal" , " Button" ));
10061144 action_menu->add_theme_style_override (" hover" , get_theme_stylebox (" hover" , " Button" ));
10071145 action_menu->add_theme_style_override (" pressed" , get_theme_stylebox (" pressed" , " Button" ));
1146+
1147+ if (animation_player != nullptr && animation_player->is_playing ()) {
1148+ animation_play_button->set_icon (get_theme_icon (SNAME (" Pause" ), SNAME (" EditorIcons" )));
1149+ } else {
1150+ animation_play_button->set_icon (get_theme_icon (SNAME (" MainPlay" ), SNAME (" EditorIcons" )));
1151+ }
1152+ animation_stop_button->set_icon (get_theme_icon (SNAME (" Stop" ), SNAME (" EditorIcons" )));
1153+ } break ;
1154+
1155+ case NOTIFICATION_PROCESS : {
1156+ if (animation_player != nullptr ) {
1157+ animation_slider->set_value_no_signal (animation_player->get_current_animation_position () / animation_player->get_current_animation_length ());
1158+ }
1159+ } break ;
1160+
1161+ case NOTIFICATION_VISIBILITY_CHANGED : {
1162+ if (!is_visible ()) {
1163+ _cleanup ();
1164+ }
10081165 } break ;
10091166 }
10101167}
@@ -1331,16 +1488,53 @@ SceneImportSettings::SceneImportSettings() {
13311488
13321489 material_tree->set_hide_root (true );
13331490
1491+ VBoxContainer *vp_vb = memnew (VBoxContainer);
1492+ vp_vb->set_h_size_flags (Control::SIZE_EXPAND_FILL );
1493+ vp_vb->set_v_size_flags (Control::SIZE_EXPAND_FILL );
1494+ vp_vb->set_anchors_and_offsets_preset (Control::LayoutPreset::PRESET_FULL_RECT );
1495+ property_split->add_child (vp_vb);
1496+
13341497 SubViewportContainer *vp_container = memnew (SubViewportContainer);
1335- vp_container->set_h_size_flags (Control::SIZE_EXPAND_FILL );
1498+ vp_container->set_v_size_flags (Control::SIZE_EXPAND_FILL );
13361499 vp_container->set_custom_minimum_size (Size2 (10 , 10 ));
13371500 vp_container->set_stretch (true );
13381501 vp_container->connect (" gui_input" , callable_mp (this , &SceneImportSettings::_viewport_input));
1339- property_split ->add_child (vp_container);
1502+ vp_vb ->add_child (vp_container);
13401503
13411504 base_viewport = memnew (SubViewport);
13421505 vp_container->add_child (base_viewport);
13431506
1507+ animation_preview = memnew (PanelContainer);
1508+ animation_preview->set_h_size_flags (Control::SIZE_EXPAND_FILL );
1509+ vp_vb->add_child (animation_preview);
1510+ animation_preview->hide ();
1511+
1512+ HBoxContainer *animation_hbox = memnew (HBoxContainer);
1513+ animation_preview->add_child (animation_hbox);
1514+
1515+ animation_play_button = memnew (Button);
1516+ animation_hbox->add_child (animation_play_button);
1517+ animation_play_button->set_flat (true );
1518+ animation_play_button->set_focus_mode (Control::FOCUS_NONE );
1519+ animation_play_button->set_shortcut (ED_SHORTCUT (" scene_import_settings/play_selected_animation" , TTR (" Selected Animation Play/Pause" ), Key::SPACE ));
1520+ animation_play_button->connect (SNAME (" pressed" ), callable_mp (this , &SceneImportSettings::_play_animation));
1521+
1522+ animation_stop_button = memnew (Button);
1523+ animation_hbox->add_child (animation_stop_button);
1524+ animation_stop_button->set_flat (true );
1525+ animation_stop_button->set_focus_mode (Control::FOCUS_NONE );
1526+ animation_stop_button->connect (SNAME (" pressed" ), callable_mp (this , &SceneImportSettings::_stop_current_animation));
1527+
1528+ animation_slider = memnew (HSlider);
1529+ animation_hbox->add_child (animation_slider);
1530+ animation_slider->set_h_size_flags (Control::SIZE_EXPAND_FILL );
1531+ animation_slider->set_v_size_flags (Control::SIZE_EXPAND_FILL );
1532+ animation_slider->set_max (1.0 );
1533+ animation_slider->set_step (1.0 / 100.0 );
1534+ animation_slider->set_value_no_signal (0.0 );
1535+ animation_slider->set_focus_mode (Control::FOCUS_NONE );
1536+ animation_slider->connect (SNAME (" value_changed" ), callable_mp (this , &SceneImportSettings::_animation_slider_value_changed));
1537+
13441538 base_viewport->set_use_own_world_3d (true );
13451539
13461540 camera = memnew (Camera3D);
@@ -1406,6 +1600,7 @@ SceneImportSettings::SceneImportSettings() {
14061600
14071601 inspector = memnew (EditorInspector);
14081602 inspector->set_custom_minimum_size (Size2 (300 * EDSCALE , 0 ));
1603+ inspector->connect (SNAME (" property_edited" ), callable_mp (this , &SceneImportSettings::_inspector_property_edited));
14091604
14101605 property_split->add_child (inspector);
14111606
0 commit comments