summaryrefslogtreecommitdiffstats
path: root/editor/plugins/node_3d_editor_plugin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/plugins/node_3d_editor_plugin.cpp')
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp148
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;
}