5858#include " editor/translations/editor_translation_preview_button.h"
5959#include " editor/translations/editor_translation_preview_menu.h"
6060#include " scene/2d/audio_stream_player_2d.h"
61+ #include " scene/2d/mesh_instance_2d.h"
6162#include " scene/2d/physics/touch_screen_button.h"
6263#include " scene/2d/polygon_2d.h"
6364#include " scene/2d/skeleton_2d.h"
@@ -6243,6 +6244,14 @@ void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) cons
62436244 add_preview = true ;
62446245 }
62456246
6247+ Ref<Mesh> mesh = res;
6248+ if (mesh.is_valid ()) {
6249+ MeshInstance2D *mesh_instance = memnew (MeshInstance2D);
6250+ mesh_instance->set_mesh (mesh);
6251+ preview_node->add_child (mesh_instance);
6252+ add_preview = true ;
6253+ }
6254+
62466255 Ref<AudioStream> audio = res;
62476256 if (audio.is_valid ()) {
62486257 Sprite2D *sprite = memnew (Sprite2D);
@@ -6377,6 +6386,56 @@ void CanvasItemEditorViewport::_create_audio_node(Node *p_parent, const String &
63776386 undo_redo->add_do_property (child, " stream" , ResourceCache::get_ref (p_path));
63786387}
63796388
6389+ void CanvasItemEditorViewport::_create_mesh_node (Node *p_parent, const String &p_path, const Point2 &p_point) {
6390+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton ();
6391+
6392+ Ref<Mesh> mesh = ResourceCache::get_ref (p_path);
6393+
6394+ MeshInstance2D *child = memnew (MeshInstance2D);
6395+
6396+ // Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others.
6397+ const String &node_name = Node::adjust_name_casing (p_path.get_file ().get_basename ());
6398+ if (!node_name.is_empty ()) {
6399+ child->set_name (node_name);
6400+ }
6401+
6402+ if (p_parent) {
6403+ undo_redo->add_do_method (p_parent, " add_child" , child, true );
6404+ undo_redo->add_do_method (child, " set_owner" , EditorNode::get_singleton ()->get_edited_scene ());
6405+ undo_redo->add_do_reference (child);
6406+ undo_redo->add_undo_method (p_parent, " remove_child" , child);
6407+ } else { // If no parent is selected, set as root node of the scene.
6408+ undo_redo->add_do_method (EditorNode::get_singleton (), " set_edited_scene" , child);
6409+ undo_redo->add_do_method (child, " set_owner" , EditorNode::get_singleton ()->get_edited_scene ());
6410+ undo_redo->add_do_reference (child);
6411+ undo_redo->add_undo_method (EditorNode::get_singleton (), " set_edited_scene" , (Object *)nullptr );
6412+ }
6413+
6414+ if (p_parent) {
6415+ String new_name = p_parent->validate_child_name (child);
6416+ EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton ();
6417+ undo_redo->add_do_method (ed, " live_debug_create_node" , EditorNode::get_singleton ()->get_edited_scene ()->get_path_to (p_parent), child->get_class (), new_name);
6418+ undo_redo->add_undo_method (ed, " live_debug_remove_node" , NodePath (String (EditorNode::get_singleton ()->get_edited_scene ()->get_path_to (p_parent)) + " /" + new_name));
6419+ }
6420+
6421+ undo_redo->add_do_property (child, " mesh" , mesh);
6422+
6423+ // Compute the global position
6424+ Transform2D xform = canvas_item_editor->get_canvas_transform ();
6425+ Point2 target_position = xform.affine_inverse ().xform (p_point);
6426+
6427+ // There's nothing to be used as source position, so snapping will work as absolute if enabled.
6428+ target_position = canvas_item_editor->snap_point (target_position);
6429+
6430+ CanvasItem *parent_ci = Object::cast_to<CanvasItem>(p_parent);
6431+ Point2 local_target_pos = parent_ci ? parent_ci->get_global_transform ().affine_inverse ().xform (target_position) : target_position;
6432+
6433+ undo_redo->add_do_method (child, " set_position" , local_target_pos);
6434+
6435+ EditorSelection *editor_selection = EditorNode::get_singleton ()->get_editor_selection ();
6436+ undo_redo->add_do_method (editor_selection, " add_node" , child);
6437+ }
6438+
63806439bool CanvasItemEditorViewport::_create_instance (Node *p_parent, const String &p_path, const Point2 &p_point) {
63816440 Ref<PackedScene> sdata = ResourceLoader::load (p_path);
63826441 if (sdata.is_null ()) { // invalid scene
@@ -6490,6 +6549,11 @@ void CanvasItemEditorViewport::_perform_drop_data() {
64906549 if (audio.is_valid ()) {
64916550 _create_audio_node (target_node, path, drop_pos);
64926551 }
6552+
6553+ Ref<Mesh> mesh = res;
6554+ if (mesh.is_valid ()) {
6555+ _create_mesh_node (target_node, path, drop_pos);
6556+ }
64936557 }
64946558
64956559 undo_redo->commit_action ();
@@ -6533,6 +6597,7 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian
65336597 SCENE = 1 << 0 ,
65346598 TEXTURE = 1 << 1 ,
65356599 AUDIO = 1 << 2 ,
6600+ MESH = 1 << 3 ,
65366601 };
65376602 int instantiate_type = 0 ;
65386603
@@ -6558,6 +6623,8 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian
65586623 instantiate_type |= TEXTURE ;
65596624 } else if (ClassDB::is_parent_class (res_type, SNAME (" AudioStream" ))) {
65606625 instantiate_type |= AUDIO ;
6626+ } else if (ClassDB::is_parent_class (res_type, " Mesh" )) {
6627+ instantiate_type |= MESH ;
65616628 }
65626629 }
65636630
@@ -6616,6 +6683,8 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian
66166683 } else if (instantiate_type & TEXTURE ) {
66176684 // TRANSLATORS: The placeholders are the types of nodes being instantiated.
66186685 title = vformat (TTR (" Dropping a Texture file as a %s node..." ), default_texture_node_type);
6686+ } else if (instantiate_type & MESH ) {
6687+ title = TTR (" Dropping a Mesh file..." );
66196688 }
66206689 if (instantiate_type & TEXTURE ) {
66216690 desc += " \n " + TTR (" [b]Hold Alt + Shift:[/b] Add Texture as a different node type." );
0 commit comments