Skip to content

Commit

Permalink
Create AudioStreamPlayer when dropping AudioStream
Browse files Browse the repository at this point in the history
- Create AudioStreamPlayer if dropped in between nodes in the Scene dock
- Create AudioStreamPlayer2D if dropped into 2D editor
- Create AudioStreamPlayer3D if dropped into 3D editor
  • Loading branch information
timothyqiu committed May 19, 2024
1 parent daa81bb commit e5c3214
Show file tree
Hide file tree
Showing 7 changed files with 464 additions and 215 deletions.
21 changes: 17 additions & 4 deletions editor/gui/scene_tree_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1368,22 +1368,35 @@ bool SceneTreeEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_d
}

bool scene_drop = true;
bool audio_drop = true;
for (int i = 0; i < files.size(); i++) {
String ftype = EditorFileSystem::get_singleton()->get_file_type(files[i]);
if (ftype != "PackedScene") {
scene_drop = false;
break;
}
if (audio_drop && !ClassDB::is_parent_class(ftype, "AudioStream")) {
audio_drop = false;
}
}

if (scene_drop) {
tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN | Tree::DROP_MODE_ON_ITEM);
} else {
return true;
}

if (audio_drop) {
if (files.size() > 1) {
return false;
tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN);
} else {
tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN | Tree::DROP_MODE_ON_ITEM);
}
tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM);
return true;
}

if (files.size() > 1) {
return false;
}
tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM);

return true;
}
Expand Down
366 changes: 227 additions & 139 deletions editor/plugins/canvas_item_editor_plugin.cpp

Large diffs are not rendered by default.

20 changes: 10 additions & 10 deletions editor/plugins/canvas_item_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@
#define CANVAS_ITEM_EDITOR_PLUGIN_H

#include "editor/plugins/editor_plugin.h"
#include "scene/gui/base_button.h"
#include "scene/gui/box_container.h"

class AcceptDialog;
class Button;
class ButtonGroup;
class CanvasItemEditorViewport;
class ConfirmationDialog;
class EditorData;
Expand Down Expand Up @@ -409,7 +410,7 @@ class CanvasItemEditor : public VBoxContainer {
void _selection_result_pressed(int);
void _selection_menu_hide();
void _add_node_pressed(int p_result);
void _node_created(Node *p_node);
void _adjust_new_node_position(Node *p_node);
void _reset_create_position();
void _update_editor_settings();
bool _is_grid_visible() const;
Expand Down Expand Up @@ -634,27 +635,26 @@ class CanvasItemEditorViewport : public Control {
CanvasItemEditor *canvas_item_editor = nullptr;
Control *preview_node = nullptr;
AcceptDialog *accept = nullptr;
AcceptDialog *selector = nullptr;
Label *selector_label = nullptr;
AcceptDialog *texture_node_type_selector = nullptr;
Label *label = nullptr;
Label *label_desc = nullptr;
VBoxContainer *btn_group = nullptr;
Ref<ButtonGroup> button_group;

void _on_mouse_exit();
void _on_select_type(Object *selected);
void _on_select_texture_node_type(Object *selected);
void _on_change_type_confirmed();
void _on_change_type_closed();

void _create_preview(const Vector<String> &files) const;
void _remove_preview();

bool _cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node) const;
bool _only_packed_scenes_selected() const;
void _create_nodes(Node *parent, Node *child, String &path, const Point2 &p_point);
bool _create_instance(Node *parent, String &path, const Point2 &p_point);
bool _is_any_texture_selected() const;
void _create_texture_node(Node *p_parent, Node *p_child, const String &p_path, const Point2 &p_point);
void _create_audio_node(Node *p_parent, const String &p_path, const Point2 &p_point);
bool _create_instance(Node *p_parent, const String &p_path, const Point2 &p_point);
void _perform_drop_data();
void _show_resource_type_selector();
void _show_texture_node_type_selector();
void _update_theme();

protected:
Expand Down
148 changes: 107 additions & 41 deletions editor/plugins/node_3d_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand All @@ -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 {
Expand All @@ -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();
}
Expand All @@ -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()) {
Expand Down Expand Up @@ -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());
}
}
Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down
3 changes: 2 additions & 1 deletion editor/plugins/node_3d_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,8 @@ class Node3DEditorViewport : public Control {
void _reset_preview_material() const;
void _remove_preview_material();
bool _cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node) const;
bool _create_instance(Node *parent, String &path, const Point2 &p_point);
bool _create_instance(Node *p_parent, const String &p_path, const Point2 &p_point);
bool _create_audio_node(Node *p_parent, const String &p_path, const Point2 &p_point);
void _perform_drop_data();

bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
Expand Down
Loading

0 comments on commit e5c3214

Please sign in to comment.