diff options
Diffstat (limited to 'editor/plugins/node_3d_editor_plugin.cpp')
-rw-r--r-- | editor/plugins/node_3d_editor_plugin.cpp | 148 |
1 files changed, 107 insertions, 41 deletions
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index ca7ea821e8..c8b229c62a 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -78,12 +78,14 @@ #include "editor/plugins/gizmos/voxel_gi_gizmo_plugin.h" #include "editor/plugins/node_3d_editor_gizmos.h" #include "editor/scene_tree_dock.h" +#include "scene/3d/audio_stream_player_3d.h" #include "scene/3d/camera_3d.h" #include "scene/3d/decal.h" #include "scene/3d/light_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/physics/collision_shape_3d.h" #include "scene/3d/physics/physics_body_3d.h" +#include "scene/3d/sprite_3d.h" #include "scene/3d/visual_instance_3d.h" #include "scene/3d/world_environment.h" #include "scene/gui/center_container.h" @@ -4192,27 +4194,37 @@ Node *Node3DEditorViewport::_sanitize_preview_node(Node *p_node) const { void Node3DEditorViewport::_create_preview_node(const Vector<String> &files) const { bool add_preview = false; - for (int i = 0; i < files.size(); i++) { - Ref<Resource> res = ResourceLoader::load(files[i]); + for (const String &path : files) { + Ref<Resource> res = ResourceLoader::load(path); ERR_CONTINUE(res.is_null()); - Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res)); - Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res)); - if (mesh != nullptr || scene != nullptr) { - if (mesh != nullptr) { - MeshInstance3D *mesh_instance = memnew(MeshInstance3D); - mesh_instance->set_mesh(mesh); - preview_node->add_child(mesh_instance); - } else { - if (scene.is_valid()) { - Node *instance = scene->instantiate(); - if (instance) { - instance = _sanitize_preview_node(instance); - preview_node->add_child(instance); - } - } + + Ref<PackedScene> scene = res; + if (scene.is_valid()) { + Node *instance = scene->instantiate(); + if (instance) { + instance = _sanitize_preview_node(instance); + preview_node->add_child(instance); } add_preview = true; } + + Ref<Mesh> mesh = res; + if (mesh.is_valid()) { + MeshInstance3D *mesh_instance = memnew(MeshInstance3D); + mesh_instance->set_mesh(mesh); + preview_node->add_child(mesh_instance); + add_preview = true; + } + + Ref<AudioStream> audio = res; + if (audio.is_valid()) { + Sprite3D *sprite = memnew(Sprite3D); + sprite->set_texture(get_editor_theme_icon(SNAME("Gizmo3DSamplePlayer"))); + sprite->set_billboard_mode(StandardMaterial3D::BILLBOARD_ENABLED); + sprite->set_pixel_size(0.005); + preview_node->add_child(sprite); + add_preview = true; + } } if (add_preview) { EditorNode::get_singleton()->get_scene_root()->add_child(preview_node); @@ -4346,12 +4358,12 @@ bool Node3DEditorViewport::_cyclical_dependency_exists(const String &p_target_sc return false; } -bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Point2 &p_point) { - Ref<Resource> res = ResourceLoader::load(path); +bool Node3DEditorViewport::_create_instance(Node *p_parent, const String &p_path, const Point2 &p_point) { + Ref<Resource> res = ResourceLoader::load(p_path); ERR_FAIL_COND_V(res.is_null(), false); - Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res)); - Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res)); + Ref<PackedScene> scene = res; + Ref<Mesh> mesh = res; Node *instantiated_scene = nullptr; @@ -4361,8 +4373,10 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po mesh_instance->set_mesh(mesh); // Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others. - String name = path.get_file().get_basename(); - mesh_instance->set_name(Node::adjust_name_casing(name)); + const String &node_name = Node::adjust_name_casing(p_path.get_file().get_basename()); + if (!node_name.is_empty()) { + mesh_instance->set_name(node_name); + } instantiated_scene = mesh_instance; } else { @@ -4386,25 +4400,25 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po } if (scene != nullptr) { - instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path)); + instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(p_path)); } EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->add_do_method(parent, "add_child", instantiated_scene, true); + undo_redo->add_do_method(p_parent, "add_child", instantiated_scene, true); undo_redo->add_do_method(instantiated_scene, "set_owner", EditorNode::get_singleton()->get_edited_scene()); undo_redo->add_do_reference(instantiated_scene); - undo_redo->add_undo_method(parent, "remove_child", instantiated_scene); + undo_redo->add_undo_method(p_parent, "remove_child", instantiated_scene); undo_redo->add_do_method(editor_selection, "add_node", instantiated_scene); - String new_name = parent->validate_child_name(instantiated_scene); + String new_name = p_parent->validate_child_name(instantiated_scene); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); - undo_redo->add_do_method(ed, "live_debug_instantiate_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), path, new_name); - undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); + undo_redo->add_do_method(ed, "live_debug_instantiate_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent), p_path, new_name); + 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)); Node3D *node3d = Object::cast_to<Node3D>(instantiated_scene); if (node3d) { Transform3D parent_tf; - Node3D *parent_node3d = Object::cast_to<Node3D>(parent); + Node3D *parent_node3d = Object::cast_to<Node3D>(p_parent); if (parent_node3d) { parent_tf = parent_node3d->get_global_gizmo_transform(); } @@ -4419,6 +4433,46 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po return true; } +bool Node3DEditorViewport::_create_audio_node(Node *p_parent, const String &p_path, const Point2 &p_point) { + Ref<AudioStream> audio = ResourceLoader::load(p_path); + ERR_FAIL_COND_V(audio.is_null(), false); + + AudioStreamPlayer3D *audio_player = memnew(AudioStreamPlayer3D); + audio_player->set_stream(audio); + + // Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others. + const String &node_name = Node::adjust_name_casing(p_path.get_file().get_basename()); + if (!node_name.is_empty()) { + audio_player->set_name(node_name); + } + + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + undo_redo->add_do_method(p_parent, "add_child", audio_player, true); + undo_redo->add_do_method(audio_player, "set_owner", EditorNode::get_singleton()->get_edited_scene()); + undo_redo->add_do_reference(audio_player); + undo_redo->add_undo_method(p_parent, "remove_child", audio_player); + undo_redo->add_do_method(editor_selection, "add_node", audio_player); + + const String new_name = p_parent->validate_child_name(audio_player); + EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); + undo_redo->add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent), audio_player->get_class(), new_name); + 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)); + + Transform3D parent_tf; + Node3D *parent_node3d = Object::cast_to<Node3D>(p_parent); + if (parent_node3d) { + parent_tf = parent_node3d->get_global_gizmo_transform(); + } + + Transform3D new_tf = audio_player->get_transform(); + new_tf.origin = parent_tf.affine_inverse().xform(preview_node_pos + audio_player->get_position()); + new_tf.basis = parent_tf.affine_inverse().basis * new_tf.basis; + + undo_redo->add_do_method(audio_player, "set_transform", new_tf); + + return true; +} + void Node3DEditorViewport::_perform_drop_data() { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (spatial_editor->get_preview_material_target().is_valid()) { @@ -4453,11 +4507,18 @@ void Node3DEditorViewport::_perform_drop_data() { if (res.is_null()) { continue; } - Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res)); - Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res)); - if (mesh != nullptr || scene != nullptr) { - bool success = _create_instance(target_node, path, drop_pos); - if (!success) { + + Ref<PackedScene> scene = res; + Ref<Mesh> mesh = res; + if (mesh.is_valid() || scene.is_valid()) { + if (!_create_instance(target_node, path, drop_pos)) { + error_files.push_back(path.get_file()); + } + } + + Ref<AudioStream> audio = res; + if (audio.is_valid()) { + if (!_create_audio_node(target_node, path, drop_pos)) { error_files.push_back(path.get_file()); } } @@ -4488,12 +4549,14 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant bool is_other_valid = false; // Check if at least one of the dragged files is a mesh, material, texture or scene. for (int i = 0; i < files.size(); i++) { - bool is_scene = ClassDB::is_parent_class(ResourceLoader::get_resource_type(files[i]), "PackedScene"); - bool is_mesh = ClassDB::is_parent_class(ResourceLoader::get_resource_type(files[i]), "Mesh"); - bool is_material = ClassDB::is_parent_class(ResourceLoader::get_resource_type(files[i]), "Material"); - bool is_texture = ClassDB::is_parent_class(ResourceLoader::get_resource_type(files[i]), "Texture"); - - if (is_mesh || is_scene || is_material || is_texture) { + const String &res_type = ResourceLoader::get_resource_type(files[i]); + bool is_scene = ClassDB::is_parent_class(res_type, "PackedScene"); + bool is_mesh = ClassDB::is_parent_class(res_type, "Mesh"); + bool is_material = ClassDB::is_parent_class(res_type, "Material"); + bool is_texture = ClassDB::is_parent_class(res_type, "Texture"); + bool is_audio = ClassDB::is_parent_class(res_type, "AudioStream"); + + if (is_mesh || is_scene || is_material || is_texture || is_audio) { Ref<Resource> res = ResourceLoader::load(files[i]); if (res.is_null()) { continue; @@ -4502,6 +4565,7 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant Ref<Mesh> mesh = res; Ref<Material> mat = res; Ref<Texture2D> tex = res; + Ref<AudioStream> audio = res; if (scn.is_valid()) { Node *instantiated_scene = scn->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); if (!instantiated_scene) { @@ -4537,6 +4601,8 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant spatial_editor->set_preview_material(new_mat); is_other_valid = true; continue; + } else if (!is_other_valid && audio.is_valid()) { + is_other_valid = true; } else { continue; } |