diff options
Diffstat (limited to 'editor/plugins')
82 files changed, 1615 insertions, 711 deletions
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index f73c494b25..60d808952e 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -620,9 +620,6 @@ void AbstractPolygon2DEditor::edit(Node *p_polygon) { canvas_item_editor->update_viewport(); } -void AbstractPolygon2DEditor::_bind_methods() { -} - void AbstractPolygon2DEditor::remove_point(const Vertex &p_vertex) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); Vector<Vector2> vertices = _get_polygon(p_vertex.polygon); diff --git a/editor/plugins/abstract_polygon_2d_editor.h b/editor/plugins/abstract_polygon_2d_editor.h index 42170d9ffd..66d4e1b7ef 100644 --- a/editor/plugins/abstract_polygon_2d_editor.h +++ b/editor/plugins/abstract_polygon_2d_editor.h @@ -109,7 +109,6 @@ protected: void _notification(int p_what); void _node_removed(Node *p_node); - static void _bind_methods(); void remove_point(const Vertex &p_vertex); Vertex get_active_point() const; diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp index b07db993ba..38f8b16b34 100644 --- a/editor/plugins/animation_library_editor.cpp +++ b/editor/plugins/animation_library_editor.cpp @@ -561,7 +561,9 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int return; } - anim = anim->duplicate(); // Users simply dont care about referencing, so making a copy works better here. + if (!anim->get_path().is_resource_file()) { + anim = anim->duplicate(); // Users simply dont care about referencing, so making a copy works better here. + } String base_name; if (anim->get_name() != "") { diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index f64c4532a1..660e4647a1 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -1295,7 +1295,7 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_timeline_o } pos = CLAMP(pos, 0, (double)anim->get_length() - CMP_EPSILON2); // Hack: Avoid fposmod with LOOP_LINEAR. - if (!p_timeline_only && anim.is_valid()) { + if (!p_timeline_only && anim.is_valid() && (!player->is_valid() || !Math::is_equal_approx(pos, player->get_current_animation_position()))) { player->seek_internal(pos, true, true, false); } diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp index 757d410b78..7906b50c2c 100644 --- a/editor/plugins/animation_tree_editor_plugin.cpp +++ b/editor/plugins/animation_tree_editor_plugin.cpp @@ -199,9 +199,6 @@ void AnimationTreeEditor::_notification(int p_what) { } } -void AnimationTreeEditor::_bind_methods() { -} - AnimationTreeEditor *AnimationTreeEditor::singleton = nullptr; void AnimationTreeEditor::add_plugin(AnimationTreeNodeEditorPlugin *p_editor) { diff --git a/editor/plugins/animation_tree_editor_plugin.h b/editor/plugins/animation_tree_editor_plugin.h index 8dc820695a..a234af6874 100644 --- a/editor/plugins/animation_tree_editor_plugin.h +++ b/editor/plugins/animation_tree_editor_plugin.h @@ -72,7 +72,6 @@ class AnimationTreeEditor : public VBoxContainer { protected: void _notification(int p_what); void _node_removed(Node *p_node); - static void _bind_methods(); static AnimationTreeEditor *singleton; diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp index c00436b01f..32ff478c33 100644 --- a/editor/plugins/bone_map_editor_plugin.cpp +++ b/editor/plugins/bone_map_editor_plugin.cpp @@ -252,9 +252,6 @@ StringName BonePicker::get_selected_bone() { return selected->get_text(0); } -void BonePicker::_bind_methods() { -} - void BonePicker::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { @@ -1232,9 +1229,11 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) { picklist.push_back("face"); int head = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_NONE, neck); if (head == -1) { - search_path = skeleton->get_bone_children(neck); - if (search_path.size() == 1) { - head = search_path[0]; // Maybe only one child of the Neck is Head. + if (neck != -1) { + search_path = skeleton->get_bone_children(neck); + if (search_path.size() == 1) { + head = search_path[0]; // Maybe only one child of the Neck is Head. + } } } if (head == -1) { diff --git a/editor/plugins/bone_map_editor_plugin.h b/editor/plugins/bone_map_editor_plugin.h index f3aa2fc84d..988ad40ec4 100644 --- a/editor/plugins/bone_map_editor_plugin.h +++ b/editor/plugins/bone_map_editor_plugin.h @@ -122,8 +122,6 @@ public: protected: void _notification(int p_what); - static void _bind_methods(); - void _confirm(); private: diff --git a/editor/plugins/camera_3d_editor_plugin.cpp b/editor/plugins/camera_3d_editor_plugin.cpp index 62b40043c1..f4116ed364 100644 --- a/editor/plugins/camera_3d_editor_plugin.cpp +++ b/editor/plugins/camera_3d_editor_plugin.cpp @@ -46,9 +46,6 @@ void Camera3DEditor::_pressed() { Node3DEditor::get_singleton()->set_custom_camera(sn); } -void Camera3DEditor::_bind_methods() { -} - void Camera3DEditor::edit(Node *p_camera) { node = p_camera; diff --git a/editor/plugins/camera_3d_editor_plugin.h b/editor/plugins/camera_3d_editor_plugin.h index 2e4d8a1ee3..1c6838aa02 100644 --- a/editor/plugins/camera_3d_editor_plugin.h +++ b/editor/plugins/camera_3d_editor_plugin.h @@ -45,7 +45,6 @@ class Camera3DEditor : public Control { protected: void _node_removed(Node *p_node); - static void _bind_methods(); public: void edit(Node *p_camera); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 1afe2ddda7..8dad6d6dbd 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -64,6 +64,7 @@ #include "scene/resources/style_box_texture.h" #define RULER_WIDTH (15 * EDSCALE) +#define DRAG_THRESHOLD (8 * EDSCALE) constexpr real_t SCALE_HANDLE_DISTANCE = 25; constexpr real_t MOVE_HANDLE_DISTANCE = 25; @@ -2319,7 +2320,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { Ref<InputEventMouseMotion> m = p_event; Ref<InputEventKey> k = p_event; - if (drag_type == DRAG_NONE) { + if (drag_type == DRAG_NONE || (drag_type == DRAG_BOX_SELECTION && b.is_valid() && !b->is_pressed())) { if (b.is_valid() && b->is_pressed() && ((b->get_button_index() == MouseButton::RIGHT && b->is_alt_pressed() && tool == TOOL_SELECT) || (b->get_button_index() == MouseButton::LEFT && tool == TOOL_LIST_SELECT))) { @@ -2411,47 +2412,58 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { return true; } - if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && !panner->is_panning() && (tool == TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_SCALE || tool == TOOL_ROTATE)) { - // Single item selection - Point2 click = transform.affine_inverse().xform(b->get_position()); + Point2 click; + bool can_select = b.is_valid() && b->get_button_index() == MouseButton::LEFT && !panner->is_panning() && (tool == TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_SCALE || tool == TOOL_ROTATE); + if (can_select) { + click = transform.affine_inverse().xform(b->get_position()); + // Allow selecting on release when performed very small box selection (necessary when Shift is pressed, see below). + can_select = b->is_pressed() || (drag_type == DRAG_BOX_SELECTION && click.distance_to(drag_from) <= DRAG_THRESHOLD); + } + if (can_select) { + // Single item selection. Node *scene = EditorNode::get_singleton()->get_edited_scene(); if (!scene) { return true; } - // Find the item to select + // Find the item to select. CanvasItem *ci = nullptr; Vector<_SelectResult> selection = Vector<_SelectResult>(); - // Retrieve the canvas items + // Retrieve the canvas items. _get_canvas_items_at_pos(click, selection); if (!selection.is_empty()) { ci = selection[0].item; } - if (!ci) { - // Start a box selection + // Shift also allows forcing box selection when item was clicked. + if (!ci || (b->is_shift_pressed() && b->is_pressed())) { + // Start a box selection. if (!b->is_shift_pressed()) { - // Clear the selection if not additive + // Clear the selection if not additive. editor_selection->clear(); viewport->queue_redraw(); selected_from_canvas = true; }; - drag_from = click; - drag_type = DRAG_BOX_SELECTION; - box_selecting_to = drag_from; - return true; + if (b->is_pressed()) { + drag_from = click; + drag_type = DRAG_BOX_SELECTION; + box_selecting_to = drag_from; + return true; + } } else { bool still_selected = _select_click_on_item(ci, click, b->is_shift_pressed()); - // Start dragging - if (still_selected && (tool == TOOL_SELECT || tool == TOOL_MOVE)) { - // Drag the node(s) if requested + // Start dragging. + if (still_selected && (tool == TOOL_SELECT || tool == TOOL_MOVE) && b->is_pressed()) { + // Drag the node(s) if requested. drag_start_origin = click; drag_type = DRAG_QUEUED; + } else if (!b->is_pressed()) { + _reset_drag(); } - // Select the item + // Select the item. return true; } } diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp index 92c0fd847b..4869a202d7 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp @@ -258,9 +258,6 @@ void CPUParticles2DEditorPlugin::_notification(int p_what) { } } -void CPUParticles2DEditorPlugin::_bind_methods() { -} - CPUParticles2DEditorPlugin::CPUParticles2DEditorPlugin() { particles = nullptr; diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.h b/editor/plugins/cpu_particles_2d_editor_plugin.h index 4d59c9981e..645e6d8345 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.h +++ b/editor/plugins/cpu_particles_2d_editor_plugin.h @@ -79,7 +79,6 @@ class CPUParticles2DEditorPlugin : public EditorPlugin { protected: void _notification(int p_what); - static void _bind_methods(); public: virtual String get_name() const override { return "CPUParticles2D"; } diff --git a/editor/plugins/cpu_particles_3d_editor_plugin.cpp b/editor/plugins/cpu_particles_3d_editor_plugin.cpp index be2847d1d7..69f287c134 100644 --- a/editor/plugins/cpu_particles_3d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_3d_editor_plugin.cpp @@ -157,9 +157,6 @@ void CPUParticles3DEditor::_generate_emission_points() { } } -void CPUParticles3DEditor::_bind_methods() { -} - CPUParticles3DEditor::CPUParticles3DEditor() { particles_editor_hb = memnew(HBoxContainer); Node3DEditor::get_singleton()->add_control_to_menu_panel(particles_editor_hb); diff --git a/editor/plugins/cpu_particles_3d_editor_plugin.h b/editor/plugins/cpu_particles_3d_editor_plugin.h index 99178b7fde..2a1ea93ac8 100644 --- a/editor/plugins/cpu_particles_3d_editor_plugin.h +++ b/editor/plugins/cpu_particles_3d_editor_plugin.h @@ -60,7 +60,6 @@ class CPUParticles3DEditor : public GPUParticles3DEditorBase { protected: void _notification(int p_notification); void _node_removed(Node *p_node); - static void _bind_methods(); public: void edit(CPUParticles3D *p_particles); diff --git a/editor/plugins/editor_plugin_settings.cpp b/editor/plugins/editor_plugin_settings.cpp index afc60b09d6..5949bc141f 100644 --- a/editor/plugins/editor_plugin_settings.cpp +++ b/editor/plugins/editor_plugin_settings.cpp @@ -199,9 +199,6 @@ Vector<String> EditorPluginSettings::_get_plugins(const String &p_dir) { return plugins; } -void EditorPluginSettings::_bind_methods() { -} - EditorPluginSettings::EditorPluginSettings() { ProjectSettings::get_singleton()->add_hidden_prefix("editor_plugins/"); diff --git a/editor/plugins/editor_plugin_settings.h b/editor/plugins/editor_plugin_settings.h index 5b470b3e58..ea7d0ea8b3 100644 --- a/editor/plugins/editor_plugin_settings.h +++ b/editor/plugins/editor_plugin_settings.h @@ -67,8 +67,6 @@ class EditorPluginSettings : public VBoxContainer { protected: void _notification(int p_what); - static void _bind_methods(); - public: void update_plugins(); diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp index e6ce63fe36..ec9513363d 100644 --- a/editor/plugins/font_config_plugin.cpp +++ b/editor/plugins/font_config_plugin.cpp @@ -30,6 +30,7 @@ #include "font_config_plugin.h" +#include "core/string/translation_server.h" #include "editor/editor_settings.h" #include "editor/import/dynamic_font_import_settings.h" #include "editor/themes/editor_scale.h" @@ -63,9 +64,6 @@ bool EditorPropertyFontMetaObject::_get(const StringName &p_name, Variant &r_ret return false; } -void EditorPropertyFontMetaObject::_bind_methods() { -} - void EditorPropertyFontMetaObject::set_dict(const Dictionary &p_dict) { dict = p_dict; } @@ -924,7 +922,8 @@ void FontPreview::_notification(int p_what) { name = vformat("%s (%s)", prev_font->get_font_name(), prev_font->get_font_style_name()); } if (prev_font->is_class("FontVariation")) { - name += " " + TTR(" - Variation"); + // TRANSLATORS: This refers to variable font config, appended to the font name. + name += " - " + TTR("Variation"); } font->draw_string(get_canvas_item(), Point2(0, font->get_height(font_size) + 2 * EDSCALE), name, HORIZONTAL_ALIGNMENT_CENTER, get_size().x, font_size, text_color); diff --git a/editor/plugins/font_config_plugin.h b/editor/plugins/font_config_plugin.h index 4e798fc3e8..e83f29a77b 100644 --- a/editor/plugins/font_config_plugin.h +++ b/editor/plugins/font_config_plugin.h @@ -46,7 +46,6 @@ class EditorPropertyFontMetaObject : public RefCounted { protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; - static void _bind_methods(); public: void set_dict(const Dictionary &p_dict); diff --git a/editor/plugins/gdextension_export_plugin.h b/editor/plugins/gdextension_export_plugin.h index da136b70ae..0de6b7b611 100644 --- a/editor/plugins/gdextension_export_plugin.h +++ b/editor/plugins/gdextension_export_plugin.h @@ -31,6 +31,7 @@ #ifndef GDEXTENSION_EXPORT_PLUGIN_H #define GDEXTENSION_EXPORT_PLUGIN_H +#include "core/extension/gdextension_library_loader.h" #include "editor/export/editor_export.h" class GDExtensionExportPlugin : public EditorExportPlugin { @@ -92,7 +93,7 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p for (const String &arch_tag : archs) { PackedStringArray tags; - String library_path = GDExtension::find_extension_library( + String library_path = GDExtensionLibraryLoader::find_extension_library( p_path, config, [features_wo_arch, arch_tag](const String &p_feature) { return features_wo_arch.has(p_feature) || (p_feature == arch_tag); }, &tags); if (libs_added.has(library_path)) { continue; // Universal library, already added for another arch, do not duplicate. @@ -129,7 +130,7 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p ERR_FAIL_MSG(vformat("No suitable library found for GDExtension: %s. Possible feature flags for your platform: %s", p_path, String(", ").join(features_vector))); } - Vector<SharedObject> dependencies_shared_objects = GDExtension::find_extension_dependencies(p_path, config, [p_features](String p_feature) { return p_features.has(p_feature); }); + Vector<SharedObject> dependencies_shared_objects = GDExtensionLibraryLoader::find_extension_dependencies(p_path, config, [p_features](String p_feature) { return p_features.has(p_feature); }); for (const SharedObject &shared_object : dependencies_shared_objects) { _add_shared_object(shared_object); } diff --git a/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp index 19dd45a3ea..8d0222215c 100644 --- a/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp @@ -112,9 +112,12 @@ void Camera3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, float a = _find_closest_angle_to_half_pi_arc(s[0], s[1], 1.0, gt2); camera->set("fov", CLAMP(a * 2.0, 1, 179)); } else { + Camera3D::KeepAspect aspect = camera->get_keep_aspect_mode(); + Vector3 camera_far = aspect == Camera3D::KeepAspect::KEEP_WIDTH ? Vector3(4096, 0, -1) : Vector3(0, 4096, -1); + Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(Vector3(0, 0, -1), Vector3(4096, 0, -1), s[0], s[1], ra, rb); - float d = ra.x * 2; + Geometry3D::get_closest_points_between_segments(Vector3(0, 0, -1), camera_far, s[0], s[1], ra, rb); + float d = aspect == Camera3D::KeepAspect::KEEP_WIDTH ? ra.x * 2 : ra.y * 2; if (Node3DEditor::get_singleton()->is_snap_enabled()) { d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); } @@ -213,25 +216,33 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { } break; case Camera3D::PROJECTION_ORTHOGONAL: { + Camera3D::KeepAspect aspect = camera->get_keep_aspect_mode(); + float size = camera->get_size(); + float keep_size = size * 0.5; - float hsize = size * 0.5; - Vector3 right(hsize * size_factor.x, 0, 0); - Vector3 up(0, hsize * size_factor.y, 0); + Vector3 right, up; Vector3 back(0, 0, -1.0); Vector3 front(0, 0, 0); + if (aspect == Camera3D::KeepAspect::KEEP_WIDTH) { + right = Vector3(keep_size, 0, 0); + up = Vector3(0, keep_size / viewport_aspect, 0); + handles.push_back(right + back); + } else { + right = Vector3(keep_size * viewport_aspect, 0, 0); + up = Vector3(0, keep_size, 0); + handles.push_back(up + back); + } + ADD_QUAD(-up - right, -up + right, up + right, up - right); ADD_QUAD(-up - right + back, -up + right + back, up + right + back, up - right + back); ADD_QUAD(up + right, up + right + back, up - right + back, up - right); ADD_QUAD(-up + right, -up + right + back, -up - right + back, -up - right); - handles.push_back(right + back); - - right.x = MIN(right.x, hsize * 0.25); - Vector3 tup(0, up.y + hsize / 2, back.z); + right.x = MIN(right.x, keep_size * 0.25); + Vector3 tup(0, up.y + keep_size / 2, back.z); ADD_TRIANGLE(tup, right + up + back, -right + up + back); - } break; case Camera3D::PROJECTION_FRUSTUM: { diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp index b70c34b785..1b68b55ff6 100644 --- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp @@ -360,9 +360,6 @@ void GPUParticles2DEditorPlugin::_notification(int p_what) { } } -void GPUParticles2DEditorPlugin::_bind_methods() { -} - GPUParticles2DEditorPlugin::GPUParticles2DEditorPlugin() { particles = nullptr; diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.h b/editor/plugins/gpu_particles_2d_editor_plugin.h index bb0ca5de3a..658e4d87e5 100644 --- a/editor/plugins/gpu_particles_2d_editor_plugin.h +++ b/editor/plugins/gpu_particles_2d_editor_plugin.h @@ -86,7 +86,6 @@ class GPUParticles2DEditorPlugin : public EditorPlugin { protected: void _notification(int p_what); - static void _bind_methods(); public: virtual String get_name() const override { return "GPUParticles2D"; } diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp index 00c5332464..4e9be0aa53 100644 --- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp @@ -198,9 +198,6 @@ void GPUParticles3DEditorBase::_node_selected(const NodePath &p_path) { emission_dialog->popup_centered(Size2(300, 130)); } -void GPUParticles3DEditorBase::_bind_methods() { -} - GPUParticles3DEditorBase::GPUParticles3DEditorBase() { emission_dialog = memnew(ConfirmationDialog); emission_dialog->set_title(TTR("Create Emitter")); @@ -402,9 +399,6 @@ void GPUParticles3DEditor::_generate_emission_points() { } } -void GPUParticles3DEditor::_bind_methods() { -} - GPUParticles3DEditor::GPUParticles3DEditor() { node = nullptr; particles_editor_hb = memnew(HBoxContainer); diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.h b/editor/plugins/gpu_particles_3d_editor_plugin.h index 3b2ab2f8ca..5f59f6dca7 100644 --- a/editor/plugins/gpu_particles_3d_editor_plugin.h +++ b/editor/plugins/gpu_particles_3d_editor_plugin.h @@ -62,8 +62,6 @@ protected: virtual void _generate_emission_points(){}; void _node_selected(const NodePath &p_path); - static void _bind_methods(); - public: GPUParticles3DEditorBase(); }; @@ -95,7 +93,6 @@ class GPUParticles3DEditor : public GPUParticles3DEditorBase { protected: void _notification(int p_notification); void _node_removed(Node *p_node); - static void _bind_methods(); public: void edit(GPUParticles3D *p_particles); diff --git a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp index 25b076d0e5..c21a1b5dd6 100644 --- a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp @@ -175,9 +175,6 @@ void GPUParticlesCollisionSDF3DEditorPlugin::_sdf_save_path_and_bake(const Strin } } -void GPUParticlesCollisionSDF3DEditorPlugin::_bind_methods() { -} - GPUParticlesCollisionSDF3DEditorPlugin::GPUParticlesCollisionSDF3DEditorPlugin() { bake_hb = memnew(HBoxContainer); bake_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); diff --git a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.h b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.h index bba8bd2584..3e1dae77ea 100644 --- a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.h +++ b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.h @@ -58,7 +58,6 @@ class GPUParticlesCollisionSDF3DEditorPlugin : public EditorPlugin { void _sdf_save_path_and_bake(const String &p_path); protected: - static void _bind_methods(); void _notification(int p_what); public: diff --git a/editor/plugins/input_event_editor_plugin.cpp b/editor/plugins/input_event_editor_plugin.cpp index 5a90d2de61..30debfc14f 100644 --- a/editor/plugins/input_event_editor_plugin.cpp +++ b/editor/plugins/input_event_editor_plugin.cpp @@ -33,9 +33,6 @@ #include "editor/event_listener_line_edit.h" #include "editor/input_event_configuration_dialog.h" -void InputEventConfigContainer::_bind_methods() { -} - void InputEventConfigContainer::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: diff --git a/editor/plugins/input_event_editor_plugin.h b/editor/plugins/input_event_editor_plugin.h index 48c16a4807..276bb74f6b 100644 --- a/editor/plugins/input_event_editor_plugin.h +++ b/editor/plugins/input_event_editor_plugin.h @@ -51,7 +51,6 @@ class InputEventConfigContainer : public VBoxContainer { protected: void _notification(int p_what); - static void _bind_methods(); public: void set_event(const Ref<InputEvent> &p_event); diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index 602e6f945c..2702b6c909 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -33,6 +33,7 @@ #include "core/config/project_settings.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" +#include "editor/editor_string_names.h" #include "editor/editor_undo_redo_manager.h" #include "editor/themes/editor_scale.h" #include "scene/3d/camera_3d.h" @@ -41,6 +42,7 @@ #include "scene/gui/box_container.h" #include "scene/gui/button.h" #include "scene/gui/color_rect.h" +#include "scene/gui/label.h" #include "scene/gui/subviewport_container.h" #include "scene/main/viewport.h" #include "scene/resources/3d/fog_material.h" @@ -80,11 +82,15 @@ void MaterialEditor::_notification(int p_what) { sphere_switch->set_icon(theme_cache.sphere_icon); box_switch->set_icon(theme_cache.box_icon); + + error_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("error_color"), EditorStringName(Editor))); } break; case NOTIFICATION_DRAW: { - Size2 size = get_size(); - draw_texture_rect(theme_cache.checkerboard, Rect2(Point2(), size), true); + if (!is_unsupported_shader_mode) { + Size2 size = get_size(); + draw_texture_rect(theme_cache.checkerboard, Rect2(Point2(), size), true); + } } break; } } @@ -99,16 +105,20 @@ void MaterialEditor::_update_rotation() { void MaterialEditor::edit(Ref<Material> p_material, const Ref<Environment> &p_env) { material = p_material; camera->set_environment(p_env); + + is_unsupported_shader_mode = false; if (!material.is_null()) { Shader::Mode mode = p_material->get_shader_mode(); switch (mode) { case Shader::MODE_CANVAS_ITEM: + layout_error->hide(); layout_3d->hide(); layout_2d->show(); vc->hide(); rect_instance->set_material(material); break; case Shader::MODE_SPATIAL: + layout_error->hide(); layout_2d->hide(); layout_3d->show(); vc->show(); @@ -116,6 +126,11 @@ void MaterialEditor::edit(Ref<Material> p_material, const Ref<Environment> &p_en box_instance->set_material_override(material); break; default: + layout_error->show(); + layout_2d->hide(); + layout_3d->hide(); + vc->hide(); + is_unsupported_shader_mode = true; break; } } else { @@ -175,6 +190,20 @@ MaterialEditor::MaterialEditor() { layout_2d->set_visible(false); + layout_error = memnew(VBoxContainer); + layout_error->set_alignment(BoxContainer::ALIGNMENT_CENTER); + layout_error->set_anchors_and_offsets_preset(PRESET_FULL_RECT); + + error_label = memnew(Label); + error_label->set_text(TTR("Preview is not available for this shader mode.")); + error_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); + error_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); + error_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); + + layout_error->add_child(error_label); + layout_error->hide(); + add_child(layout_error); + // Spatial vc = memnew(SubViewportContainer); diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h index fb6bafc0ef..28c59d27db 100644 --- a/editor/plugins/material_editor_plugin.h +++ b/editor/plugins/material_editor_plugin.h @@ -45,6 +45,7 @@ class MeshInstance3D; class SubViewport; class SubViewportContainer; class Button; +class Label; class MaterialEditor : public Control { GDCLASS(MaterialEditor, Control); @@ -69,6 +70,10 @@ class MaterialEditor : public Control { Ref<SphereMesh> sphere_mesh; Ref<BoxMesh> box_mesh; + VBoxContainer *layout_error = nullptr; + Label *error_label = nullptr; + bool is_unsupported_shader_mode = false; + HBoxContainer *layout_3d = nullptr; Ref<Material> material; diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp index 4ebacbd0b3..369d6ab009 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp @@ -214,28 +214,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { } break; case MENU_OPTION_CREATE_NAVMESH: { - Ref<NavigationMesh> nmesh = memnew(NavigationMesh); - - if (nmesh.is_null()) { - return; - } - - nmesh->create_from_mesh(mesh); - NavigationRegion3D *nmi = memnew(NavigationRegion3D); - nmi->set_navigation_mesh(nmesh); - - Node *owner = get_tree()->get_edited_scene_root(); - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - ur->create_action(TTR("Create Navigation Mesh")); - - ur->add_do_method(node, "add_child", nmi, true); - ur->add_do_method(nmi, "set_owner", owner); - ur->add_do_method(Node3DEditor::get_singleton(), SceneStringName(_request_gizmo), nmi); - - ur->add_do_reference(nmi); - ur->add_undo_method(node, "remove_child", nmi); - ur->commit_action(); + navigation_mesh_dialog->popup_centered(Vector2(200, 90)); } break; case MENU_OPTION_CREATE_OUTLINE_MESH: { @@ -472,6 +451,36 @@ void MeshInstance3DEditor::_debug_uv_draw() { debug_uv->draw_multiline(uv_lines, get_theme_color(SNAME("mono_color"), EditorStringName(Editor)) * Color(1, 1, 1, 0.5)); } +void MeshInstance3DEditor::_create_navigation_mesh() { + Ref<Mesh> mesh = node->get_mesh(); + if (mesh.is_null()) { + return; + } + + Ref<NavigationMesh> nmesh = memnew(NavigationMesh); + + if (nmesh.is_null()) { + return; + } + + nmesh->create_from_mesh(mesh); + NavigationRegion3D *nmi = memnew(NavigationRegion3D); + nmi->set_navigation_mesh(nmesh); + + Node *owner = get_tree()->get_edited_scene_root(); + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Create Navigation Mesh")); + + ur->add_do_method(node, "add_child", nmi, true); + ur->add_do_method(nmi, "set_owner", owner); + ur->add_do_method(Node3DEditor::get_singleton(), SceneStringName(_request_gizmo), nmi); + + ur->add_do_reference(nmi); + ur->add_undo_method(node, "remove_child", nmi); + ur->commit_action(); +} + void MeshInstance3DEditor::_create_outline_mesh() { Ref<Mesh> mesh = node->get_mesh(); if (mesh.is_null()) { @@ -608,6 +617,20 @@ MeshInstance3DEditor::MeshInstance3DEditor() { debug_uv->set_custom_minimum_size(Size2(600, 600) * EDSCALE); debug_uv->connect(SceneStringName(draw), callable_mp(this, &MeshInstance3DEditor::_debug_uv_draw)); debug_uv_dialog->add_child(debug_uv); + + navigation_mesh_dialog = memnew(ConfirmationDialog); + navigation_mesh_dialog->set_title(TTR("Create NavigationMesh")); + navigation_mesh_dialog->set_ok_button_text(TTR("Create")); + + VBoxContainer *navigation_mesh_dialog_vbc = memnew(VBoxContainer); + navigation_mesh_dialog->add_child(navigation_mesh_dialog_vbc); + + Label *navigation_mesh_l = memnew(Label); + navigation_mesh_l->set_text(TTR("Before converting a rendering mesh to a navigation mesh, please verify:\n\n- The mesh is two-dimensional.\n- The mesh has no surface overlap.\n- The mesh has no self-intersection.\n- The mesh surfaces have indices.\n\nIf the mesh does not fulfill these requirements, the pathfinding will be broken.")); + navigation_mesh_dialog_vbc->add_child(navigation_mesh_l); + + add_child(navigation_mesh_dialog); + navigation_mesh_dialog->connect("confirmed", callable_mp(this, &MeshInstance3DEditor::_create_navigation_mesh)); } void MeshInstance3DEditorPlugin::edit(Object *p_object) { diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.h b/editor/plugins/mesh_instance_3d_editor_plugin.h index 20c151fb92..c982df9c5f 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.h +++ b/editor/plugins/mesh_instance_3d_editor_plugin.h @@ -82,10 +82,13 @@ class MeshInstance3DEditor : public Control { Control *debug_uv = nullptr; Vector<Vector2> uv_lines; + ConfirmationDialog *navigation_mesh_dialog = nullptr; + void _create_collision_shape(); Vector<Ref<Shape3D>> create_shape_from_mesh(Ref<Mesh> p_mesh, int p_option, bool p_verbose); void _menu_option(int p_option); void _create_outline_mesh(); + void _create_navigation_mesh(); void _create_uv_lines(int p_layer); friend class MeshInstance3DEditorPlugin; diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp index 0b2549986c..58cc670475 100644 --- a/editor/plugins/mesh_library_editor_plugin.cpp +++ b/editor/plugins/mesh_library_editor_plugin.cpp @@ -242,9 +242,6 @@ void MeshLibraryEditor::_menu_cbk(int p_option) { } } -void MeshLibraryEditor::_bind_methods() { -} - MeshLibraryEditor::MeshLibraryEditor() { file = memnew(EditorFileDialog); file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); diff --git a/editor/plugins/mesh_library_editor_plugin.h b/editor/plugins/mesh_library_editor_plugin.h index 94f46beea1..5a9e32178d 100644 --- a/editor/plugins/mesh_library_editor_plugin.h +++ b/editor/plugins/mesh_library_editor_plugin.h @@ -68,9 +68,6 @@ class MeshLibraryEditor : public Control { static void _import_scene(Node *p_scene, Ref<MeshLibrary> p_library, bool p_merge, bool p_apply_xforms); static void _import_scene_parse_node(Ref<MeshLibrary> p_library, HashMap<int, MeshInstance3D *> &p_mesh_instances, Node *p_node, bool p_merge, bool p_apply_xforms); -protected: - static void _bind_methods(); - public: MenuButton *get_menu_button() const { return menu; } diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp index 3980f23c8a..76ffdb02e1 100644 --- a/editor/plugins/multimesh_editor_plugin.cpp +++ b/editor/plugins/multimesh_editor_plugin.cpp @@ -266,9 +266,6 @@ void MultiMeshEditor::_browse(bool p_source) { std->popup_scenetree_dialog(browsed_node); } -void MultiMeshEditor::_bind_methods() { -} - MultiMeshEditor::MultiMeshEditor() { options = memnew(MenuButton); options->set_switch_on_hover(true); diff --git a/editor/plugins/multimesh_editor_plugin.h b/editor/plugins/multimesh_editor_plugin.h index 5051926c64..3fe63bfa92 100644 --- a/editor/plugins/multimesh_editor_plugin.h +++ b/editor/plugins/multimesh_editor_plugin.h @@ -79,7 +79,6 @@ class MultiMeshEditor : public Control { protected: void _node_removed(Node *p_node); - static void _bind_methods(); public: void edit(MultiMeshInstance3D *p_multimesh); diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index de56767929..67d5e44ce5 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -81,6 +81,8 @@ void EditorNode3DGizmo::redraw() { gizmo_plugin->redraw(this); } + _update_bvh(); + if (Node3DEditor::get_singleton()->is_current_selected_gizmo(this)) { Node3DEditor::get_singleton()->update_transform_gizmo(); } @@ -244,6 +246,32 @@ void EditorNode3DGizmo::add_mesh(const Ref<Mesh> &p_mesh, const Ref<Material> &p instances.push_back(ins); } +void EditorNode3DGizmo::_update_bvh() { + ERR_FAIL_NULL(spatial_node); + + Transform3D transform = spatial_node->get_global_transform(); + + float effective_icon_size = selectable_icon_size > 0.0f ? selectable_icon_size : 0.0f; + Vector3 icon_size_vector3 = Vector3(effective_icon_size, effective_icon_size, effective_icon_size); + AABB aabb(spatial_node->get_position() - icon_size_vector3 * 100.0f, icon_size_vector3 * 200.0f); + + for (const Vector3 &segment_end : collision_segments) { + aabb.expand_to(transform.xform(segment_end)); + } + + if (collision_mesh.is_valid()) { + for (const Face3 &face : collision_mesh->get_faces()) { + aabb.expand_to(transform.xform(face.vertex[0])); + aabb.expand_to(transform.xform(face.vertex[1])); + aabb.expand_to(transform.xform(face.vertex[2])); + } + } + + Node3DEditor::get_singleton()->update_gizmo_bvh_node( + bvh_node_id, + aabb); +} + void EditorNode3DGizmo::add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard, const Color &p_modulate) { add_vertices(p_lines, p_material, Mesh::PRIMITIVE_LINES, p_billboard, p_modulate); } @@ -765,6 +793,10 @@ void EditorNode3DGizmo::create() { instances.write[i].create_instance(spatial_node, hidden); } + bvh_node_id = Node3DEditor::get_singleton()->insert_gizmo_bvh_node( + spatial_node, + AABB(spatial_node->get_position(), Vector3(0, 0, 0))); + transform(); } @@ -774,6 +806,8 @@ void EditorNode3DGizmo::transform() { for (int i = 0; i < instances.size(); i++) { RS::get_singleton()->instance_set_transform(instances[i].instance, spatial_node->get_global_transform() * instances[i].xform); } + + _update_bvh(); } void EditorNode3DGizmo::free() { @@ -790,6 +824,9 @@ void EditorNode3DGizmo::free() { clear(); + Node3DEditor::get_singleton()->remove_gizmo_bvh_node(bvh_node_id); + bvh_node_id = DynamicBVH::ID(); + valid = false; } diff --git a/editor/plugins/node_3d_editor_gizmos.h b/editor/plugins/node_3d_editor_gizmos.h index d7c368d5d0..c4b275032a 100644 --- a/editor/plugins/node_3d_editor_gizmos.h +++ b/editor/plugins/node_3d_editor_gizmos.h @@ -31,6 +31,7 @@ #ifndef NODE_3D_EDITOR_GIZMOS_H #define NODE_3D_EDITOR_GIZMOS_H +#include "core/math/dynamic_bvh.h" #include "core/templates/hash_map.h" #include "core/templates/local_vector.h" #include "scene/3d/camera_3d.h" @@ -72,8 +73,12 @@ class EditorNode3DGizmo : public Node3DGizmo { Vector<Instance> instances; Node3D *spatial_node = nullptr; + DynamicBVH::ID bvh_node_id; + void _set_node_3d(Node *p_node) { set_node_3d(Object::cast_to<Node3D>(p_node)); } + void _update_bvh(); + protected: static void _bind_methods(); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 59a4ac8075..c58109427b 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -800,7 +800,6 @@ ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos) const { RS::get_singleton()->sdfgi_set_debug_probe_select(pos, ray); } - Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_ray(pos, pos + ray * camera->get_far(), get_tree()->get_root()->get_world_3d()->get_scenario()); HashSet<Ref<EditorNode3DGizmo>> found_gizmos; Node *edited_scene = get_tree()->get_edited_scene_root(); @@ -808,9 +807,9 @@ ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos) const { Node *item = nullptr; float closest_dist = 1e20; - for (int i = 0; i < instances.size(); i++) { - Node3D *spat = Object::cast_to<Node3D>(ObjectDB::get_instance(instances[i])); + Vector<Node3D *> nodes_with_gizmos = Node3DEditor::get_singleton()->gizmo_bvh_ray_query(pos, pos + ray * camera->get_far()); + for (Node3D *spat : nodes_with_gizmos) { if (!spat) { continue; } @@ -863,12 +862,11 @@ void Node3DEditorViewport::_find_items_at_pos(const Point2 &p_pos, Vector<_RayRe Vector3 ray = get_ray(p_pos); Vector3 pos = get_ray_pos(p_pos); - Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_ray(pos, pos + ray * camera->get_far(), get_tree()->get_root()->get_world_3d()->get_scenario()); - HashSet<Node3D *> found_nodes; + Vector<Node3D *> nodes_with_gizmos = Node3DEditor::get_singleton()->gizmo_bvh_ray_query(pos, pos + ray * camera->get_far()); - for (int i = 0; i < instances.size(); i++) { - Node3D *spat = Object::cast_to<Node3D>(ObjectDB::get_instance(instances[i])); + HashSet<Node3D *> found_nodes; + for (Node3D *spat : nodes_with_gizmos) { if (!spat) { continue; } @@ -1046,7 +1044,7 @@ void Node3DEditorViewport::_select_region() { _clear_selected(); } - Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_convex(frustum, get_tree()->get_root()->get_world_3d()->get_scenario()); + Vector<Node3D *> nodes_with_gizmos = Node3DEditor::get_singleton()->gizmo_bvh_frustum_query(frustum); HashSet<Node3D *> found_nodes; Vector<Node *> selected; @@ -1055,8 +1053,7 @@ void Node3DEditorViewport::_select_region() { return; } - for (int i = 0; i < instances.size(); i++) { - Node3D *sp = Object::cast_to<Node3D>(ObjectDB::get_instance(instances[i])); + for (Node3D *sp : nodes_with_gizmos) { if (!sp || _is_node_locked(sp)) { continue; } @@ -1064,21 +1061,23 @@ void Node3DEditorViewport::_select_region() { if (found_nodes.has(sp)) { continue; } - found_nodes.insert(sp); Node *node = Object::cast_to<Node>(sp); + + // Selection requires that the node is the edited scene or its descendant, and has an owner. if (node != edited_scene) { + if (!node->get_owner() || !edited_scene->is_ancestor_of(node)) { + continue; + } node = edited_scene->get_deepest_editable_node(node); - } - - // Prevent selection of nodes not owned by the edited scene. - while (node && node != edited_scene->get_parent()) { - Node *node_owner = node->get_owner(); - if (node_owner == edited_scene || node == edited_scene || (node_owner != nullptr && edited_scene->is_editable_instance(node_owner))) { - break; + while (node != edited_scene) { + Node *node_owner = node->get_owner(); + if (node_owner == edited_scene || (node_owner != nullptr && edited_scene->is_editable_instance(node_owner))) { + break; + } + node = node->get_parent(); } - node = node->get_parent(); } // Replace the node by the group if grouped @@ -1179,7 +1178,7 @@ void Node3DEditorViewport::_update_name() { if (auto_orthogonal) { // TRANSLATORS: This will be appended to the view name when Auto Orthogonal is enabled. - name += TTR(" [auto]"); + name += " " + TTR("[auto]"); } view_menu->set_text(name); @@ -1693,6 +1692,10 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (b.is_valid()) { emit_signal(SNAME("clicked"), this); + ViewportNavMouseButton orbit_mouse_preference = (ViewportNavMouseButton)EDITOR_GET("editors/3d/navigation/orbit_mouse_button").operator int(); + ViewportNavMouseButton pan_mouse_preference = (ViewportNavMouseButton)EDITOR_GET("editors/3d/navigation/pan_mouse_button").operator int(); + ViewportNavMouseButton zoom_mouse_preference = (ViewportNavMouseButton)EDITOR_GET("editors/3d/navigation/zoom_mouse_button").operator int(); + const real_t zoom_factor = 1 + (ZOOM_FREELOOK_MULTIPLIER - 1) * b->get_factor(); switch (b->get_button_index()) { case MouseButton::WHEEL_UP: { @@ -1710,8 +1713,6 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } } break; case MouseButton::RIGHT: { - NavigationScheme nav_scheme = (NavigationScheme)EDITOR_GET("editors/3d/navigation/navigation_scheme").operator int(); - if (b->is_pressed() && _edit.gizmo.is_valid()) { //restore _edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_handle_secondary, _edit.gizmo_initial_value, true); @@ -1719,11 +1720,15 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } if (_edit.mode == TRANSFORM_NONE && b->is_pressed()) { - if (b->is_alt_pressed()) { - if (nav_scheme == NAVIGATION_MAYA) { - break; - } + if (orbit_mouse_preference == NAVIGATION_RIGHT_MOUSE && _is_nav_modifier_pressed("spatial_editor/viewport_orbit_modifier_1") && _is_nav_modifier_pressed("spatial_editor/viewport_orbit_modifier_2")) { + break; + } else if (pan_mouse_preference == NAVIGATION_RIGHT_MOUSE && _is_nav_modifier_pressed("spatial_editor/viewport_pan_modifier_1") && _is_nav_modifier_pressed("spatial_editor/viewport_pan_modifier_2")) { + break; + } else if (zoom_mouse_preference == NAVIGATION_RIGHT_MOUSE && _is_nav_modifier_pressed("spatial_editor/viewport_zoom_modifier_1") && _is_nav_modifier_pressed("spatial_editor/viewport_zoom_modifier_2")) { + break; + } + if (b->is_alt_pressed()) { _list_select(b); return; } @@ -1754,6 +1759,14 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } break; case MouseButton::MIDDLE: { if (b->is_pressed() && _edit.mode != TRANSFORM_NONE) { + if (orbit_mouse_preference == NAVIGATION_MIDDLE_MOUSE && _is_nav_modifier_pressed("spatial_editor/viewport_orbit_modifier_1") && _is_nav_modifier_pressed("spatial_editor/viewport_orbit_modifier_2")) { + break; + } else if (pan_mouse_preference == NAVIGATION_MIDDLE_MOUSE && _is_nav_modifier_pressed("spatial_editor/viewport_pan_modifier_1") && _is_nav_modifier_pressed("spatial_editor/viewport_pan_modifier_2")) { + break; + } else if (zoom_mouse_preference == NAVIGATION_MIDDLE_MOUSE && _is_nav_modifier_pressed("spatial_editor/viewport_zoom_modifier_1") && _is_nav_modifier_pressed("spatial_editor/viewport_zoom_modifier_2")) { + break; + } + switch (_edit.plane) { case TRANSFORM_VIEW: { _edit.plane = TRANSFORM_X_AXIS; @@ -1792,8 +1805,11 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { commit_transform(); break; // just commit the edit, stop processing the event so we don't deselect the object } - NavigationScheme nav_scheme = (NavigationScheme)EDITOR_GET("editors/3d/navigation/navigation_scheme").operator int(); - if ((nav_scheme == NAVIGATION_MAYA || nav_scheme == NAVIGATION_MODO) && b->is_alt_pressed()) { + if (orbit_mouse_preference == NAVIGATION_LEFT_MOUSE && _is_nav_modifier_pressed("spatial_editor/viewport_orbit_modifier_1") && _is_nav_modifier_pressed("spatial_editor/viewport_orbit_modifier_2")) { + break; + } else if (pan_mouse_preference == NAVIGATION_LEFT_MOUSE && _is_nav_modifier_pressed("spatial_editor/viewport_pan_modifier_1") && _is_nav_modifier_pressed("spatial_editor/viewport_pan_modifier_2")) { + break; + } else if (zoom_mouse_preference == NAVIGATION_LEFT_MOUSE && _is_nav_modifier_pressed("spatial_editor/viewport_zoom_modifier_1") && _is_nav_modifier_pressed("spatial_editor/viewport_zoom_modifier_2")) { break; } @@ -1812,7 +1828,9 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { { int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS); + int idx2 = view_menu->get_popup()->get_item_index(VIEW_TRANSFORM_GIZMO); can_select_gizmos = can_select_gizmos && view_menu->get_popup()->is_item_checked(idx); + transform_gizmo_visible = view_menu->get_popup()->is_item_checked(idx2); } // Gizmo handles @@ -1916,12 +1934,17 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } if (after != EditorPlugin::AFTER_GUI_INPUT_CUSTOM) { - //clicking is always deferred to either move or release - clicked = _select_ray(b->get_position()); + // Single item selection. + Vector<_RayResult> selection; + _find_items_at_pos(b->get_position(), selection, false); + if (!selection.is_empty()) { + clicked = selection[0].item->get_instance_id(); + } + selection_in_progress = true; if (clicked.is_null()) { - //default to regionselect + // Default to region select. cursor.region_select = true; cursor.region_begin = b->get_position(); cursor.region_end = b->get_position(); @@ -1984,6 +2007,24 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } } + ViewportNavMouseButton orbit_mouse_preference = (ViewportNavMouseButton)EDITOR_GET("editors/3d/navigation/orbit_mouse_button").operator int(); + ViewportNavMouseButton pan_mouse_preference = (ViewportNavMouseButton)EDITOR_GET("editors/3d/navigation/pan_mouse_button").operator int(); + ViewportNavMouseButton zoom_mouse_preference = (ViewportNavMouseButton)EDITOR_GET("editors/3d/navigation/zoom_mouse_button").operator int(); + bool orbit_mod_pressed = _is_nav_modifier_pressed("spatial_editor/viewport_orbit_modifier_1") && _is_nav_modifier_pressed("spatial_editor/viewport_orbit_modifier_2"); + bool pan_mod_pressed = _is_nav_modifier_pressed("spatial_editor/viewport_pan_modifier_1") && _is_nav_modifier_pressed("spatial_editor/viewport_pan_modifier_2"); + bool zoom_mod_pressed = _is_nav_modifier_pressed("spatial_editor/viewport_zoom_modifier_1") && _is_nav_modifier_pressed("spatial_editor/viewport_zoom_modifier_2"); + int orbit_mod_input_count = _get_shortcut_input_count("spatial_editor/viewport_orbit_modifier_1") + _get_shortcut_input_count("spatial_editor/viewport_orbit_modifier_2"); + int pan_mod_input_count = _get_shortcut_input_count("spatial_editor/viewport_pan_modifier_1") + _get_shortcut_input_count("spatial_editor/viewport_pan_modifier_2"); + int zoom_mod_input_count = _get_shortcut_input_count("spatial_editor/viewport_zoom_modifier_1") + _get_shortcut_input_count("spatial_editor/viewport_zoom_modifier_2"); + bool orbit_not_empty = !_is_shortcut_empty("spatial_editor/viewport_zoom_modifier_1") || !_is_shortcut_empty("spatial_editor/viewport_zoom_modifier_2"); + bool pan_not_empty = !_is_shortcut_empty("spatial_editor/viewport_pan_modifier_1") || !_is_shortcut_empty("spatial_editor/viewport_pan_modifier_2"); + bool zoom_not_empty = !_is_shortcut_empty("spatial_editor/viewport_orbit_modifier_1") || !_is_shortcut_empty("spatial_editor/viewport_orbit_modifier_2"); + Vector<ShortcutCheckSet> shortcut_check_sets; + shortcut_check_sets.push_back(ShortcutCheckSet(orbit_mod_pressed, orbit_not_empty, orbit_mod_input_count, orbit_mouse_preference, NAVIGATION_ORBIT)); + shortcut_check_sets.push_back(ShortcutCheckSet(pan_mod_pressed, pan_not_empty, pan_mod_input_count, pan_mouse_preference, NAVIGATION_PAN)); + shortcut_check_sets.push_back(ShortcutCheckSet(zoom_mod_pressed, zoom_not_empty, zoom_mod_input_count, zoom_mouse_preference, NAVIGATION_ZOOM)); + shortcut_check_sets.sort_custom<ShortcutCheckSetComparator>(); + Ref<InputEventMouseMotion> m = p_event; // Instant transforms process mouse motion in input() to handle wrapping. @@ -2028,7 +2069,6 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { _transform_gizmo_select(_edit.mouse_pos, true); } - NavigationScheme nav_scheme = (NavigationScheme)EDITOR_GET("editors/3d/navigation/navigation_scheme").operator int(); NavigationMode nav_mode = NAVIGATION_NONE; if (_edit.gizmo.is_valid()) { @@ -2038,14 +2078,9 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { set_message(n + ": " + String(v)); } else if (m->get_button_mask().has_flag(MouseButtonMask::LEFT)) { - if (nav_scheme == NAVIGATION_MAYA && m->is_alt_pressed()) { - nav_mode = NAVIGATION_ORBIT; - } else if (nav_scheme == NAVIGATION_MODO && m->is_alt_pressed() && m->is_shift_pressed()) { - nav_mode = NAVIGATION_PAN; - } else if (nav_scheme == NAVIGATION_MODO && m->is_alt_pressed() && m->is_command_or_control_pressed()) { - nav_mode = NAVIGATION_ZOOM; - } else if (nav_scheme == NAVIGATION_MODO && m->is_alt_pressed()) { - nav_mode = NAVIGATION_ORBIT; + NavigationMode change_nav_from_shortcut = _get_nav_mode_from_shortcut_check(NAVIGATION_LEFT_MOUSE, shortcut_check_sets, false); + if (change_nav_from_shortcut != NAVIGATION_NONE) { + nav_mode = change_nav_from_shortcut; } else { const bool movement_threshold_passed = _edit.original_mouse_pos.distance_to(_edit.mouse_pos) > 8 * EDSCALE; @@ -2076,8 +2111,9 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { update_transform(_get_key_modifier(m) == Key::SHIFT); } } else if (m->get_button_mask().has_flag(MouseButtonMask::RIGHT) || freelook_active) { - if (nav_scheme == NAVIGATION_MAYA && m->is_alt_pressed()) { - nav_mode = NAVIGATION_ZOOM; + NavigationMode change_nav_from_shortcut = _get_nav_mode_from_shortcut_check(NAVIGATION_RIGHT_MOUSE, shortcut_check_sets, false); + if (m->get_button_mask().has_flag(MouseButtonMask::RIGHT) && change_nav_from_shortcut != NAVIGATION_NONE) { + nav_mode = change_nav_from_shortcut; } else if (freelook_active) { nav_mode = NAVIGATION_LOOK; } else if (orthogonal) { @@ -2085,34 +2121,16 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } } else if (m->get_button_mask().has_flag(MouseButtonMask::MIDDLE)) { - const Key mod = _get_key_modifier(m); - if (nav_scheme == NAVIGATION_GODOT) { - if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) { - nav_mode = NAVIGATION_PAN; - } else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier")) { - nav_mode = NAVIGATION_ZOOM; - } else if (mod == Key::ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) { - // Always allow Alt as a modifier to better support graphic tablets. - nav_mode = NAVIGATION_ORBIT; - } - } else if (nav_scheme == NAVIGATION_MAYA) { - if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) { - nav_mode = NAVIGATION_PAN; - } + NavigationMode change_nav_from_shortcut = _get_nav_mode_from_shortcut_check(NAVIGATION_MIDDLE_MOUSE, shortcut_check_sets, false); + if (change_nav_from_shortcut != NAVIGATION_NONE) { + nav_mode = change_nav_from_shortcut; } + } else if (EDITOR_GET("editors/3d/navigation/emulate_3_button_mouse")) { // Handle trackpad (no external mouse) use case - const Key mod = _get_key_modifier(m); - - if (mod != Key::NONE) { - if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) { - nav_mode = NAVIGATION_PAN; - } else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier")) { - nav_mode = NAVIGATION_ZOOM; - } else if (mod == Key::ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) { - // Always allow Alt as a modifier to better support graphic tablets. - nav_mode = NAVIGATION_ORBIT; - } + NavigationMode change_nav_from_shortcut = _get_nav_mode_from_shortcut_check(NAVIGATION_LEFT_MOUSE, shortcut_check_sets, true); + if (change_nav_from_shortcut != NAVIGATION_NONE) { + nav_mode = change_nav_from_shortcut; } } @@ -2153,25 +2171,11 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { Ref<InputEventPanGesture> pan_gesture = p_event; if (pan_gesture.is_valid()) { - NavigationScheme nav_scheme = (NavigationScheme)EDITOR_GET("editors/3d/navigation/navigation_scheme").operator int(); NavigationMode nav_mode = NAVIGATION_NONE; - if (nav_scheme == NAVIGATION_GODOT) { - const Key mod = _get_key_modifier(pan_gesture); - - if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) { - nav_mode = NAVIGATION_PAN; - } else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier")) { - nav_mode = NAVIGATION_ZOOM; - } else if (mod == Key::ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) { - // Always allow Alt as a modifier to better support graphic tablets. - nav_mode = NAVIGATION_ORBIT; - } - - } else if (nav_scheme == NAVIGATION_MAYA) { - if (pan_gesture->is_alt_pressed()) { - nav_mode = NAVIGATION_PAN; - } + NavigationMode change_nav_from_shortcut = _get_nav_mode_from_shortcut_check(NAVIGATION_LEFT_MOUSE, shortcut_check_sets, true); + if (change_nav_from_shortcut != NAVIGATION_NONE) { + nav_mode = change_nav_from_shortcut; } switch (nav_mode) { @@ -2252,6 +2256,11 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } if (_edit.mode == TRANSFORM_NONE) { + if (_edit.gizmo.is_null() && is_freelook_active() && k->get_keycode() == Key::ESCAPE) { + set_freelook_active(false); + return; + } + if (_edit.gizmo.is_valid() && (k->get_keycode() == Key::ESCAPE || k->get_keycode() == Key::BACKSPACE)) { // Restore. _edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_handle_secondary, _edit.gizmo_initial_value, true); @@ -2436,6 +2445,32 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } } +int Node3DEditorViewport::_get_shortcut_input_count(const String &p_name) { + Ref<Shortcut> check_shortcut = ED_GET_SHORTCUT(p_name); + + ERR_FAIL_COND_V_MSG(check_shortcut.is_null(), 0, "The Shortcut was null, possible name mismatch."); + + return check_shortcut->get_events().size(); +} + +Node3DEditorViewport::NavigationMode Node3DEditorViewport::_get_nav_mode_from_shortcut_check(ViewportNavMouseButton p_mouse_button, Vector<ShortcutCheckSet> p_shortcut_check_sets, bool p_use_not_empty) { + if (p_use_not_empty) { + for (const ShortcutCheckSet &shortcut_check_set : p_shortcut_check_sets) { + if (shortcut_check_set.mod_pressed && shortcut_check_set.shortcut_not_empty) { + return shortcut_check_set.result_nav_mode; + } + } + } else { + for (const ShortcutCheckSet &shortcut_check_set : p_shortcut_check_sets) { + if (shortcut_check_set.mouse_preference == p_mouse_button && shortcut_check_set.mod_pressed) { + return shortcut_check_set.result_nav_mode; + } + } + } + + return NAVIGATION_NONE; +} + void Node3DEditorViewport::_nav_pan(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) { const NavigationScheme nav_scheme = (NavigationScheme)EDITOR_GET("editors/3d/navigation/navigation_scheme").operator int(); @@ -2635,6 +2670,18 @@ void Node3DEditorViewport::scale_freelook_speed(real_t scale) { surface->queue_redraw(); } +bool Node3DEditorViewport::_is_nav_modifier_pressed(const String &p_name) { + return _is_shortcut_empty(p_name) || Input::get_singleton()->is_action_pressed(p_name); +} + +bool Node3DEditorViewport::_is_shortcut_empty(const String &p_name) { + Ref<Shortcut> check_shortcut = ED_GET_SHORTCUT(p_name); + + ERR_FAIL_COND_V_MSG(check_shortcut.is_null(), true, "The Shortcut was null, possible name mismatch."); + + return check_shortcut->get_events().is_empty(); +} + Point2 Node3DEditorViewport::_get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const { Point2 relative; if (bool(EDITOR_GET("editors/3d/navigation/warped_mouse_panning"))) { @@ -3107,6 +3154,7 @@ void Node3DEditorViewport::_notification(int p_what) { case NOTIFICATION_DRAG_END: { // Clear preview material when dropped outside applicable object. if (spatial_editor->get_preview_material().is_valid() && !is_drag_successful()) { + _reset_preview_material(); _remove_preview_material(); } else { _remove_preview_node(); @@ -3529,6 +3577,15 @@ void Node3DEditorViewport::_menu_option(int p_option) { view_menu->get_popup()->set_item_checked(idx, current); } break; + case VIEW_TRANSFORM_GIZMO: { + int idx = view_menu->get_popup()->get_item_index(VIEW_TRANSFORM_GIZMO); + bool current = view_menu->get_popup()->is_item_checked(idx); + current = !current; + transform_gizmo_visible = current; + + spatial_editor->update_transform_gizmo(); + view_menu->get_popup()->set_item_checked(idx, current); + } break; case VIEW_HALF_RESOLUTION: { int idx = view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION); bool current = view_menu->get_popup()->is_item_checked(idx); @@ -3893,7 +3950,7 @@ void Node3DEditorViewport::update_transform_gizmo_view() { return; } - bool show_gizmo = spatial_editor->is_gizmo_visible() && !_edit.instant; + bool show_gizmo = spatial_editor->is_gizmo_visible() && !_edit.instant && transform_gizmo_visible; for (int i = 0; i < 3; i++) { Transform3D axis_angle; if (xform.basis.get_column(i).normalized().dot(xform.basis.get_column((i + 1) % 3).normalized()) < 1.0) { @@ -3924,7 +3981,7 @@ void Node3DEditorViewport::update_transform_gizmo_view() { xform.orthonormalize(); xform.basis.scale(scale); RenderingServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[3], xform); - RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE)); + RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], spatial_editor->is_gizmo_visible() && transform_gizmo_visible && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE)); } void Node3DEditorViewport::set_state(const Dictionary &p_state) { @@ -4001,6 +4058,14 @@ void Node3DEditorViewport::set_state(const Dictionary &p_state) { _menu_option(VIEW_GIZMOS); } } + if (p_state.has("grid")) { + bool grid = p_state["grid"]; + + int idx = view_menu->get_popup()->get_item_index(VIEW_GRID); + if (view_menu->get_popup()->is_item_checked(idx) != grid) { + _menu_option(VIEW_GRID); + } + } if (p_state.has("information")) { bool information = p_state["information"]; @@ -4079,6 +4144,7 @@ Dictionary Node3DEditorViewport::get_state() const { d["listener"] = viewport->is_audio_listener_3d(); d["doppler"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER)); d["gizmos"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS)); + d["grid"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GRID)); d["information"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION)); d["frame_time"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME)); d["half_res"] = subviewport_container->get_stretch_shrink() > 1; @@ -5001,14 +5067,24 @@ void Node3DEditorViewport::update_transform(bool p_shift) { } break; case TRANSFORM_ROTATE: { - Plane plane = Plane(_get_camera_normal(), _edit.center); + Plane plane; + if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) { + Vector3 cam_to_obj = _edit.center - _get_camera_position(); + if (!cam_to_obj.is_zero_approx()) { + plane = Plane(cam_to_obj.normalized(), _edit.center); + } else { + plane = Plane(_get_camera_normal(), _edit.center); + } + } else { + plane = Plane(_get_camera_normal(), _edit.center); + } Vector3 local_axis; Vector3 global_axis; switch (_edit.plane) { case TRANSFORM_VIEW: // local_axis unused - global_axis = _get_camera_normal(); + global_axis = plane.normal; break; case TRANSFORM_X_AXIS: local_axis = Vector3(1, 0, 0); @@ -5039,7 +5115,7 @@ void Node3DEditorViewport::update_transform(bool p_shift) { break; } - static const float orthogonal_threshold = Math::cos(Math::deg_to_rad(87.0f)); + static const float orthogonal_threshold = Math::cos(Math::deg_to_rad(85.0f)); bool axis_is_orthogonal = ABS(plane.normal.dot(global_axis)) < orthogonal_threshold; double angle = 0.0f; @@ -5301,6 +5377,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p view_menu->get_popup()->add_separator(); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_environment", TTR("View Environment")), VIEW_ENVIRONMENT); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_gizmos", TTR("View Gizmos")), VIEW_GIZMOS); + view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_transform_gizmo", TTR("View Transform Gizmo")), VIEW_TRANSFORM_GIZMO); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid_lines", TTR("View Grid")), VIEW_GRID); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_information", TTR("View Information")), VIEW_INFORMATION); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_fps", TTR("View Frame Time")), VIEW_FRAME_TIME); @@ -5311,6 +5388,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_audio_listener", TTR("Audio Listener")), VIEW_AUDIO_LISTENER); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_audio_doppler", TTR("Enable Doppler")), VIEW_AUDIO_DOPPLER); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS), true); + view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_TRANSFORM_GIZMO), true); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_GRID), true); view_menu->get_popup()->add_separator(); @@ -5345,6 +5423,14 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p view_menu->get_popup()->set_item_tooltip(shadeless_idx, unsupported_tooltip); } + // Registering with Key::NONE intentionally creates an empty Array. + register_shortcut_action("spatial_editor/viewport_orbit_modifier_1", TTR("Viewport Orbit Modifier 1"), Key::NONE); + register_shortcut_action("spatial_editor/viewport_orbit_modifier_2", TTR("Viewport Orbit Modifier 2"), Key::NONE); + register_shortcut_action("spatial_editor/viewport_pan_modifier_1", TTR("Viewport Pan Modifier 1"), Key::SHIFT); + register_shortcut_action("spatial_editor/viewport_pan_modifier_2", TTR("Viewport Pan Modifier 2"), Key::NONE); + register_shortcut_action("spatial_editor/viewport_zoom_modifier_1", TTR("Viewport Zoom Modifier 1"), Key::SHIFT); + register_shortcut_action("spatial_editor/viewport_zoom_modifier_2", TTR("Viewport Zoom Modifier 2"), Key::CTRL); + register_shortcut_action("spatial_editor/freelook_left", TTR("Freelook Left"), Key::A, true); register_shortcut_action("spatial_editor/freelook_right", TTR("Freelook Right"), Key::D, true); register_shortcut_action("spatial_editor/freelook_forward", TTR("Freelook Forward"), Key::W, true); @@ -7289,9 +7375,15 @@ void Node3DEditor::_init_grid() { bool orthogonal = camera->get_projection() == Camera3D::PROJECTION_ORTHOGONAL; - Vector<Color> grid_colors[3]; - Vector<Vector3> grid_points[3]; - Vector<Vector3> grid_normals[3]; + static LocalVector<Color> grid_colors[3]; + static LocalVector<Vector3> grid_points[3]; + static LocalVector<Vector3> grid_normals[3]; + + for (uint32_t n = 0; n < 3; n++) { + grid_colors[n].clear(); + grid_points[n].clear(); + grid_normals[n].clear(); + } Color primary_grid_color = EDITOR_GET("editors/3d/primary_grid_color"); Color secondary_grid_color = EDITOR_GET("editors/3d/secondary_grid_color"); @@ -7299,9 +7391,9 @@ void Node3DEditor::_init_grid() { int primary_grid_steps = EDITOR_GET("editors/3d/primary_grid_steps"); // Which grid planes are enabled? Which should we generate? - grid_enable[0] = grid_visible[0] = EDITOR_GET("editors/3d/grid_xy_plane"); - grid_enable[1] = grid_visible[1] = EDITOR_GET("editors/3d/grid_yz_plane"); - grid_enable[2] = grid_visible[2] = EDITOR_GET("editors/3d/grid_xz_plane"); + grid_enable[0] = grid_visible[0] = orthogonal || EDITOR_GET("editors/3d/grid_xy_plane"); + grid_enable[1] = grid_visible[1] = orthogonal || EDITOR_GET("editors/3d/grid_yz_plane"); + grid_enable[2] = grid_visible[2] = orthogonal || EDITOR_GET("editors/3d/grid_xz_plane"); // Offsets division_level for bigger or smaller grids. // Default value is -0.2. -1.0 gives Blender-like behavior, 0.5 gives huge grids. @@ -7367,10 +7459,9 @@ void Node3DEditor::_init_grid() { grid_mat[c]->set_shader_parameter("grid_size", grid_fade_size); grid_mat[c]->set_shader_parameter("orthogonal", orthogonal); - // Cache these so we don't have to re-access memory. - Vector<Vector3> &ref_grid = grid_points[c]; - Vector<Vector3> &ref_grid_normals = grid_normals[c]; - Vector<Color> &ref_grid_colors = grid_colors[c]; + LocalVector<Vector3> &ref_grid = grid_points[c]; + LocalVector<Vector3> &ref_grid_normals = grid_normals[c]; + LocalVector<Color> &ref_grid_colors = grid_colors[c]; // Count our elements same as code below it. int expected_size = 0; @@ -7415,12 +7506,12 @@ void Node3DEditor::_init_grid() { line_end[a] = position_a; line_bgn[b] = bgn_b; line_end[b] = end_b; - ref_grid.set(idx, line_bgn); - ref_grid.set(idx + 1, line_end); - ref_grid_colors.set(idx, line_color); - ref_grid_colors.set(idx + 1, line_color); - ref_grid_normals.set(idx, normal); - ref_grid_normals.set(idx + 1, normal); + ref_grid[idx] = line_bgn; + ref_grid[idx + 1] = line_end; + ref_grid_colors[idx] = line_color; + ref_grid_colors[idx + 1] = line_color; + ref_grid_normals[idx] = normal; + ref_grid_normals[idx + 1] = normal; idx += 2; } @@ -7431,12 +7522,12 @@ void Node3DEditor::_init_grid() { line_end[b] = position_b; line_bgn[a] = bgn_a; line_end[a] = end_a; - ref_grid.set(idx, line_bgn); - ref_grid.set(idx + 1, line_end); - ref_grid_colors.set(idx, line_color); - ref_grid_colors.set(idx + 1, line_color); - ref_grid_normals.set(idx, normal); - ref_grid_normals.set(idx + 1, normal); + ref_grid[idx] = line_bgn; + ref_grid[idx + 1] = line_end; + ref_grid_colors[idx] = line_color; + ref_grid_colors[idx + 1] = line_color; + ref_grid_normals[idx] = normal; + ref_grid_normals[idx + 1] = normal; idx += 2; } } @@ -7445,9 +7536,9 @@ void Node3DEditor::_init_grid() { grid[c] = RenderingServer::get_singleton()->mesh_create(); Array d; d.resize(RS::ARRAY_MAX); - d[RenderingServer::ARRAY_VERTEX] = grid_points[c]; - d[RenderingServer::ARRAY_COLOR] = grid_colors[c]; - d[RenderingServer::ARRAY_NORMAL] = grid_normals[c]; + d[RenderingServer::ARRAY_VERTEX] = (Vector<Vector3>)grid_points[c]; + d[RenderingServer::ARRAY_COLOR] = (Vector<Color>)grid_colors[c]; + d[RenderingServer::ARRAY_NORMAL] = (Vector<Vector3>)grid_normals[c]; RenderingServer::get_singleton()->mesh_add_surface_from_arrays(grid[c], RenderingServer::PRIMITIVE_LINES, d); RenderingServer::get_singleton()->mesh_surface_set_material(grid[c], 0, grid_mat[c]->get_rid()); grid_instance[c] = RenderingServer::get_singleton()->instance_create2(grid[c], get_tree()->get_root()->get_world_3d()->get_scenario()); @@ -9208,6 +9299,49 @@ void Node3DEditor::remove_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin) { _update_gizmos_menu(); } +DynamicBVH::ID Node3DEditor::insert_gizmo_bvh_node(Node3D *p_node, const AABB &p_aabb) { + return gizmo_bvh.insert(p_aabb, p_node); +} + +void Node3DEditor::update_gizmo_bvh_node(DynamicBVH::ID p_id, const AABB &p_aabb) { + gizmo_bvh.update(p_id, p_aabb); + gizmo_bvh.optimize_incremental(1); +} + +void Node3DEditor::remove_gizmo_bvh_node(DynamicBVH::ID p_id) { + gizmo_bvh.remove(p_id); +} + +Vector<Node3D *> Node3DEditor::gizmo_bvh_ray_query(const Vector3 &p_ray_start, const Vector3 &p_ray_end) { + struct Result { + Vector<Node3D *> nodes; + bool operator()(void *p_data) { + nodes.append((Node3D *)p_data); + return false; + } + } result; + + gizmo_bvh.ray_query(p_ray_start, p_ray_end, result); + + return result.nodes; +} + +Vector<Node3D *> Node3DEditor::gizmo_bvh_frustum_query(const Vector<Plane> &p_frustum) { + Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&p_frustum[0], p_frustum.size()); + + struct Result { + Vector<Node3D *> nodes; + bool operator()(void *p_data) { + nodes.append((Node3D *)p_data); + return false; + } + } result; + + gizmo_bvh.convex_query(p_frustum.ptr(), p_frustum.size(), points.ptr(), points.size(), result); + + return result.nodes; +} + Node3DEditorPlugin::Node3DEditorPlugin() { spatial_editor = memnew(Node3DEditor); spatial_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 5bd14748c0..2cfe784ca6 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -31,6 +31,7 @@ #ifndef NODE_3D_EDITOR_PLUGIN_H #define NODE_3D_EDITOR_PLUGIN_H +#include "core/math/dynamic_bvh.h" #include "editor/plugins/editor_plugin.h" #include "editor/plugins/node_3d_editor_gizmos.h" #include "editor/themes/editor_scale.h" @@ -124,6 +125,7 @@ class Node3DEditorViewport : public Control { VIEW_AUDIO_LISTENER, VIEW_AUDIO_DOPPLER, VIEW_GIZMOS, + VIEW_TRANSFORM_GIZMO, VIEW_GRID, VIEW_INFORMATION, VIEW_FRAME_TIME, @@ -191,6 +193,7 @@ public: NAVIGATION_GODOT, NAVIGATION_MAYA, NAVIGATION_MODO, + NAVIGATION_CUSTOM, }; enum FreelookNavigationScheme { @@ -199,6 +202,12 @@ public: FREELOOK_FULLY_AXIS_LOCKED, }; + enum ViewportNavMouseButton { + NAVIGATION_LEFT_MOUSE, + NAVIGATION_MIDDLE_MOUSE, + NAVIGATION_RIGHT_MOUSE, + }; + private: double cpu_time_history[FRAME_TIME_HISTORY]; int cpu_time_history_index; @@ -235,6 +244,7 @@ private: bool orthogonal; bool auto_orthogonal; bool lock_rotation; + bool transform_gizmo_visible = true; real_t gizmo_scale; bool freelook_active; @@ -293,6 +303,10 @@ private: void _nav_orbit(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative); void _nav_look(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative); + bool _is_shortcut_empty(const String &p_name); + bool _is_nav_modifier_pressed(const String &p_name); + int _get_shortcut_input_count(const String &p_name); + float get_znear() const; float get_zfar() const; float get_fov() const; @@ -389,6 +403,28 @@ private: void reset_fov(); void scale_cursor_distance(real_t scale); + struct ShortcutCheckSet { + bool mod_pressed = false; + bool shortcut_not_empty = true; + int input_count = 0; + ViewportNavMouseButton mouse_preference = NAVIGATION_LEFT_MOUSE; + NavigationMode result_nav_mode = NAVIGATION_NONE; + + ShortcutCheckSet() {} + + ShortcutCheckSet(bool p_mod_pressed, bool p_shortcut_not_empty, int p_input_count, const ViewportNavMouseButton &p_mouse_preference, const NavigationMode &p_result_nav_mode) : + mod_pressed(p_mod_pressed), shortcut_not_empty(p_shortcut_not_empty), input_count(p_input_count), mouse_preference(p_mouse_preference), result_nav_mode(p_result_nav_mode) { + } + }; + + struct ShortcutCheckSetComparator { + _FORCE_INLINE_ bool operator()(const ShortcutCheckSet &A, const ShortcutCheckSet &B) const { + return A.input_count > B.input_count; + } + }; + + NavigationMode _get_nav_mode_from_shortcut_check(ViewportNavMouseButton p_mouse_button, Vector<ShortcutCheckSet> p_shortcut_check_sets, bool p_use_not_empty); + void set_freelook_active(bool active_now); void scale_freelook_speed(real_t scale); @@ -629,6 +665,8 @@ private: int current_hover_gizmo_handle; bool current_hover_gizmo_handle_secondary; + DynamicBVH gizmo_bvh; + real_t snap_translate_value; real_t snap_rotate_value; real_t snap_scale_value; @@ -933,6 +971,12 @@ public: void add_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin); void remove_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin); + DynamicBVH::ID insert_gizmo_bvh_node(Node3D *p_node, const AABB &p_aabb); + void update_gizmo_bvh_node(DynamicBVH::ID p_id, const AABB &p_aabb); + void remove_gizmo_bvh_node(DynamicBVH::ID p_id); + Vector<Node3D *> gizmo_bvh_ray_query(const Vector3 &p_ray_start, const Vector3 &p_ray_end); + Vector<Node3D *> gizmo_bvh_frustum_query(const Vector<Plane> &p_frustum); + void edit(Node3D *p_spatial); void clear(); diff --git a/editor/plugins/packed_scene_translation_parser_plugin.cpp b/editor/plugins/packed_scene_translation_parser_plugin.cpp index e9ddaeb3fe..b38965753e 100644 --- a/editor/plugins/packed_scene_translation_parser_plugin.cpp +++ b/editor/plugins/packed_scene_translation_parser_plugin.cpp @@ -83,9 +83,8 @@ Error PackedSceneEditorTranslationParserPlugin::parse_file(const String &p_path, int idx_last = atr_owners.size() - 1; if (idx_last > 0 && !parent_path.begins_with(atr_owners[idx_last].first)) { - // Switch to the previous auto translation owner this was nested in, if that was the case. + // Exit from the current owner nesting into the previous one. atr_owners.remove_at(idx_last); - idx_last -= 1; } if (property == "auto_translate_mode") { @@ -106,7 +105,7 @@ Error PackedSceneEditorTranslationParserPlugin::parse_file(const String &p_path, // If `auto_translate_mode` wasn't found, that means it is set to its default value (`AUTO_TRANSLATE_MODE_INHERIT`). if (!auto_translate_mode_found) { int idx_last = atr_owners.size() - 1; - if (idx_last > 0 && atr_owners[idx_last].first == parent_path) { + if (idx_last > 0 && parent_path.begins_with(atr_owners[idx_last].first)) { auto_translating = atr_owners[idx_last].second; } else { atr_owners.push_back(Pair(state->get_node_path(i), true)); diff --git a/editor/plugins/physical_bone_3d_editor_plugin.cpp b/editor/plugins/physical_bone_3d_editor_plugin.cpp index b7c12ab5c0..d7e9701452 100644 --- a/editor/plugins/physical_bone_3d_editor_plugin.cpp +++ b/editor/plugins/physical_bone_3d_editor_plugin.cpp @@ -36,9 +36,6 @@ #include "scene/3d/physics/physical_bone_3d.h" #include "scene/gui/separator.h" -void PhysicalBone3DEditor::_bind_methods() { -} - void PhysicalBone3DEditor::_on_toggle_button_transform_joint(bool p_is_pressed) { _set_move_joint(); } diff --git a/editor/plugins/physical_bone_3d_editor_plugin.h b/editor/plugins/physical_bone_3d_editor_plugin.h index fb6f30cc57..b057644bb1 100644 --- a/editor/plugins/physical_bone_3d_editor_plugin.h +++ b/editor/plugins/physical_bone_3d_editor_plugin.h @@ -45,9 +45,6 @@ class PhysicalBone3DEditor : public Object { PhysicalBone3D *selected = nullptr; -protected: - static void _bind_methods(); - private: void _on_toggle_button_transform_joint(bool p_is_pressed); void _set_move_joint(); diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index e442c37edd..7c350f1e6d 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -181,7 +181,7 @@ void Polygon2DEditor::_sync_bones() { } if (weights.size() == 0) { //create them - weights.resize(node->get_polygon().size()); + weights.resize(wc); float *w = weights.ptrw(); for (int j = 0; j < wc; j++) { w[j] = 0.0; @@ -850,8 +850,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { if (mm.is_valid()) { if (uv_drag) { Vector2 uv_drag_to = mm->get_position(); - uv_drag_to = snap_point(uv_drag_to); // FIXME: Only works correctly with 'UV_MODE_EDIT_POINT', it's imprecise with the rest. - Vector2 drag = mtx.affine_inverse().xform(uv_drag_to) - mtx.affine_inverse().xform(uv_drag_from); + uv_drag_to = snap_point(uv_drag_to); + Vector2 drag = mtx.affine_inverse().basis_xform(uv_drag_to - uv_drag_from); switch (uv_move_current) { case UV_MODE_CREATE: { @@ -1166,12 +1166,8 @@ void Polygon2DEditor::_uv_draw() { poly_line_color.a *= 0.25; } Color polygon_line_color = Color(0.5, 0.5, 0.9); - Vector<Color> polygon_fill_color; - { - Color pf = polygon_line_color; - pf.a *= 0.5; - polygon_fill_color.push_back(pf); - } + Color polygon_fill_color = polygon_line_color; + polygon_fill_color.a *= 0.5; Color prev_color = Color(0.5, 0.5, 0.5); int uv_draw_max = uvs.size(); @@ -1216,7 +1212,7 @@ void Polygon2DEditor::_uv_draw() { uv_edit_draw->draw_line(mtx.xform(uvs[idx]), mtx.xform(uvs[idx_next]), polygon_line_color, Math::round(EDSCALE)); } if (points.size() >= 3) { - uv_edit_draw->draw_polygon(polypoints, polygon_fill_color); + uv_edit_draw->draw_colored_polygon(polypoints, polygon_fill_color); } } @@ -1255,44 +1251,43 @@ void Polygon2DEditor::_uv_draw() { //draw skeleton NodePath skeleton_path = node->get_skeleton(); - if (node->has_node(skeleton_path)) { - Skeleton2D *skeleton = Object::cast_to<Skeleton2D>(node->get_node(skeleton_path)); - if (skeleton) { - for (int i = 0; i < skeleton->get_bone_count(); i++) { - Bone2D *bone = skeleton->get_bone(i); - if (bone->get_rest() == Transform2D(0, 0, 0, 0, 0, 0)) { - continue; //not set - } + Skeleton2D *skeleton = Object::cast_to<Skeleton2D>(node->get_node_or_null(skeleton_path)); + if (skeleton) { + Transform2D skeleton_xform = node->get_global_transform().affine_inverse().translated(-node->get_offset()) * skeleton->get_global_transform(); + for (int i = 0; i < skeleton->get_bone_count(); i++) { + Bone2D *bone = skeleton->get_bone(i); + if (bone->get_rest() == Transform2D(0, 0, 0, 0, 0, 0)) { + continue; //not set + } - bool current = bone_path == skeleton->get_path_to(bone); + bool current = bone_path == skeleton->get_path_to(bone); - bool found_child = false; + bool found_child = false; - for (int j = 0; j < bone->get_child_count(); j++) { - Bone2D *n = Object::cast_to<Bone2D>(bone->get_child(j)); - if (!n) { - continue; - } + for (int j = 0; j < bone->get_child_count(); j++) { + Bone2D *n = Object::cast_to<Bone2D>(bone->get_child(j)); + if (!n) { + continue; + } - found_child = true; + found_child = true; - Transform2D bone_xform = node->get_global_transform().affine_inverse().translated(-node->get_offset()) * (skeleton->get_global_transform() * bone->get_skeleton_rest()); - Transform2D endpoint_xform = bone_xform * n->get_transform(); + Transform2D bone_xform = skeleton_xform * bone->get_skeleton_rest(); + Transform2D endpoint_xform = bone_xform * n->get_transform(); - Color color = current ? Color(1, 1, 1) : Color(0.5, 0.5, 0.5); - uv_edit_draw->draw_line(mtx.xform(bone_xform.get_origin()), mtx.xform(endpoint_xform.get_origin()), Color(0, 0, 0), Math::round((current ? 5 : 4) * EDSCALE)); - uv_edit_draw->draw_line(mtx.xform(bone_xform.get_origin()), mtx.xform(endpoint_xform.get_origin()), color, Math::round((current ? 3 : 2) * EDSCALE)); - } + Color color = current ? Color(1, 1, 1) : Color(0.5, 0.5, 0.5); + uv_edit_draw->draw_line(mtx.xform(bone_xform.get_origin()), mtx.xform(endpoint_xform.get_origin()), Color(0, 0, 0), Math::round((current ? 5 : 4) * EDSCALE)); + uv_edit_draw->draw_line(mtx.xform(bone_xform.get_origin()), mtx.xform(endpoint_xform.get_origin()), color, Math::round((current ? 3 : 2) * EDSCALE)); + } - if (!found_child) { - //draw normally - Transform2D bone_xform = node->get_global_transform().affine_inverse().translated(-node->get_offset()) * (skeleton->get_global_transform() * bone->get_skeleton_rest()); - Transform2D endpoint_xform = bone_xform * Transform2D(0, Vector2(bone->get_length(), 0)); + if (!found_child) { + //draw normally + Transform2D bone_xform = skeleton_xform * bone->get_skeleton_rest(); + Transform2D endpoint_xform = bone_xform * Transform2D(0, Vector2(bone->get_length(), 0)).rotated(bone->get_bone_angle()); - Color color = current ? Color(1, 1, 1) : Color(0.5, 0.5, 0.5); - uv_edit_draw->draw_line(mtx.xform(bone_xform.get_origin()), mtx.xform(endpoint_xform.get_origin()), Color(0, 0, 0), Math::round((current ? 5 : 4) * EDSCALE)); - uv_edit_draw->draw_line(mtx.xform(bone_xform.get_origin()), mtx.xform(endpoint_xform.get_origin()), color, Math::round((current ? 3 : 2) * EDSCALE)); - } + Color color = current ? Color(1, 1, 1) : Color(0.5, 0.5, 0.5); + uv_edit_draw->draw_line(mtx.xform(bone_xform.get_origin()), mtx.xform(endpoint_xform.get_origin()), Color(0, 0, 0), Math::round((current ? 5 : 4) * EDSCALE)); + uv_edit_draw->draw_line(mtx.xform(bone_xform.get_origin()), mtx.xform(endpoint_xform.get_origin()), color, Math::round((current ? 3 : 2) * EDSCALE)); } } } @@ -1309,8 +1304,8 @@ void Polygon2DEditor::_bind_methods() { Vector2 Polygon2DEditor::snap_point(Vector2 p_target) const { if (use_snap) { - p_target.x = Math::snap_scalar(snap_offset.x * uv_draw_zoom - uv_draw_ofs.x, snap_step.x * uv_draw_zoom, p_target.x); - p_target.y = Math::snap_scalar(snap_offset.y * uv_draw_zoom - uv_draw_ofs.y, snap_step.y * uv_draw_zoom, p_target.y); + p_target.x = Math::snap_scalar((snap_offset.x - uv_draw_ofs.x) * uv_draw_zoom, snap_step.x * uv_draw_zoom, p_target.x); + p_target.y = Math::snap_scalar((snap_offset.y - uv_draw_ofs.y) * uv_draw_zoom, snap_step.y * uv_draw_zoom, p_target.y); } return p_target; @@ -1388,7 +1383,8 @@ Polygon2DEditor::Polygon2DEditor() { uv_button[UV_MODE_CREATE_INTERNAL]->set_tooltip_text(TTR("Create Internal Vertex")); uv_button[UV_MODE_REMOVE_INTERNAL]->set_tooltip_text(TTR("Remove Internal Vertex")); Key key = (OS::get_singleton()->has_feature("macos") || OS::get_singleton()->has_feature("web_macos") || OS::get_singleton()->has_feature("web_ios")) ? Key::META : Key::CTRL; - uv_button[UV_MODE_EDIT_POINT]->set_tooltip_text(TTR("Move Points") + "\n" + find_keycode_name(key) + TTR(": Rotate") + "\n" + TTR("Shift: Move All") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Shift: Scale")); + // TRANSLATORS: %s is Control or Command key name. + uv_button[UV_MODE_EDIT_POINT]->set_tooltip_text(TTR("Move Points") + "\n" + vformat(TTR("%s: Rotate"), find_keycode_name(key)) + "\n" + TTR("Shift: Move All") + "\n" + vformat(TTR("%s + Shift: Scale"), find_keycode_name(key))); uv_button[UV_MODE_MOVE]->set_tooltip_text(TTR("Move Polygon")); uv_button[UV_MODE_ROTATE]->set_tooltip_text(TTR("Rotate Polygon")); uv_button[UV_MODE_SCALE]->set_tooltip_text(TTR("Scale Polygon")); diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp index 8b31aa92b3..cd422fc291 100644 --- a/editor/plugins/root_motion_editor_plugin.cpp +++ b/editor/plugins/root_motion_editor_plugin.cpp @@ -193,9 +193,6 @@ void EditorPropertyRootMotion::_notification(int p_what) { } } -void EditorPropertyRootMotion::_bind_methods() { -} - EditorPropertyRootMotion::EditorPropertyRootMotion() { HBoxContainer *hbc = memnew(HBoxContainer); add_child(hbc); diff --git a/editor/plugins/root_motion_editor_plugin.h b/editor/plugins/root_motion_editor_plugin.h index 5befdb6006..a3e90360ae 100644 --- a/editor/plugins/root_motion_editor_plugin.h +++ b/editor/plugins/root_motion_editor_plugin.h @@ -52,7 +52,6 @@ class EditorPropertyRootMotion : public EditorProperty { void _node_clear(); protected: - static void _bind_methods(); void _notification(int p_what); public: diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index c51eb44aee..7a052ebc19 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -493,7 +493,7 @@ void ScriptEditor::_goto_script_line(Ref<RefCounted> p_script, int p_line) { if (ScriptTextEditor *script_text_editor = Object::cast_to<ScriptTextEditor>(current)) { script_text_editor->goto_line_centered(p_line); } else if (current) { - current->goto_line(p_line, true); + current->goto_line(p_line); } _save_history(); @@ -1079,8 +1079,12 @@ void ScriptEditor::_mark_built_in_scripts_as_saved(const String &p_parent_path) } Ref<Script> scr = edited_res; - if (scr.is_valid() && scr->is_tool()) { - scr->reload(true); + if (scr.is_valid()) { + trigger_live_script_reload(scr->get_path()); + + if (scr->is_tool()) { + scr->reload(true); + } } } } @@ -1857,17 +1861,13 @@ void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) { } void ScriptEditor::_members_overview_selected(int p_idx) { - ScriptEditorBase *se = _get_current_editor(); - if (!se) { - return; + int line = members_overview->get_item_metadata(p_idx); + ScriptEditorBase *current = _get_current_editor(); + if (ScriptTextEditor *script_text_editor = Object::cast_to<ScriptTextEditor>(current)) { + script_text_editor->goto_line_centered(line); + } else if (current) { + current->goto_line(line); } - // Go to the member's line and reset the cursor column. We can't change scroll_position - // directly until we have gone to the line first, since code might be folded. - se->goto_line(members_overview->get_item_metadata(p_idx)); - Dictionary state = se->get_edit_state(); - state["column"] = 0; - state["scroll_position"] = members_overview->get_item_metadata(p_idx); - se->set_edit_state(state); } void ScriptEditor::_help_overview_selected(int p_idx) { @@ -2711,9 +2711,11 @@ void ScriptEditor::apply_scripts() const { } void ScriptEditor::reload_scripts(bool p_refresh_only) { - if (external_editor_active) { - return; - } + // Call deferred to make sure it runs on the main thread. + callable_mp(this, &ScriptEditor::_reload_scripts).call_deferred(p_refresh_only); +} + +void ScriptEditor::_reload_scripts(bool p_refresh_only) { for (int i = 0; i < tab_container->get_tab_count(); i++) { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i)); if (!se) { @@ -3799,7 +3801,10 @@ void ScriptEditor::_on_find_in_files_result_selected(const String &fpath, int li ShaderEditorPlugin *shader_editor = Object::cast_to<ShaderEditorPlugin>(EditorNode::get_editor_data().get_editor_by_name("Shader")); shader_editor->edit(res.ptr()); shader_editor->make_visible(true); - shader_editor->get_shader_editor(res)->goto_line_selection(line_number - 1, begin, end); + TextShaderEditor *text_shader_editor = Object::cast_to<TextShaderEditor>(shader_editor->get_shader_editor(res)); + if (text_shader_editor) { + text_shader_editor->goto_line_selection(line_number - 1, begin, end); + } return; } else if (fpath.get_extension() == "tscn") { Ref<FileAccess> f = FileAccess::open(fpath, FileAccess::READ); @@ -4412,13 +4417,9 @@ bool ScriptEditorPlugin::handles(Object *p_object) const { void ScriptEditorPlugin::make_visible(bool p_visible) { if (p_visible) { window_wrapper->show(); - script_editor->set_process(true); script_editor->ensure_select_current(); } else { window_wrapper->hide(); - if (!window_wrapper->get_window_enabled()) { - script_editor->set_process(false); - } } } diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 9db1aff76a..66885790a7 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -55,7 +55,7 @@ class EditorSyntaxHighlighter : public SyntaxHighlighter { GDCLASS(EditorSyntaxHighlighter, SyntaxHighlighter) private: - Ref<RefCounted> edited_resourse; + Ref<RefCounted> edited_resource; protected: static void _bind_methods(); @@ -67,8 +67,8 @@ public: virtual String _get_name() const; virtual PackedStringArray _get_supported_languages() const; - void _set_edited_resource(const Ref<Resource> &p_res) { edited_resourse = p_res; } - Ref<RefCounted> _get_edited_resource() { return edited_resourse; } + void _set_edited_resource(const Ref<Resource> &p_res) { edited_resource = p_res; } + Ref<RefCounted> _get_edited_resource() { return edited_resource; } virtual Ref<EditorSyntaxHighlighter> _create() const; }; @@ -170,7 +170,7 @@ public: virtual Variant get_edit_state() = 0; virtual void set_edit_state(const Variant &p_state) = 0; virtual Variant get_navigation_state() = 0; - virtual void goto_line(int p_line, bool p_with_error = false) = 0; + virtual void goto_line(int p_line, int p_column = 0) = 0; virtual void set_executing_line(int p_line) = 0; virtual void clear_executing_line() = 0; virtual void trim_trailing_whitespace() = 0; @@ -436,6 +436,7 @@ class ScriptEditor : public PanelContainer { void _file_removed(const String &p_file); void _autosave_scripts(); void _update_autosave_timer(); + void _reload_scripts(bool p_refresh_only = false); void _update_members_overview_visibility(); void _update_members_overview(); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 070471f3f3..eb39a27d02 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -302,16 +302,14 @@ void ScriptTextEditor::_warning_clicked(const Variant &p_line) { void ScriptTextEditor::_error_clicked(const Variant &p_line) { if (p_line.get_type() == Variant::INT) { - code_editor->get_text_editor()->remove_secondary_carets(); - code_editor->get_text_editor()->set_caret_line(p_line.operator int64_t()); + goto_line_centered(p_line.operator int64_t()); } else if (p_line.get_type() == Variant::DICTIONARY) { Dictionary meta = p_line.operator Dictionary(); const String path = meta["path"].operator String(); const int line = meta["line"].operator int64_t(); const int column = meta["column"].operator int64_t(); if (path.is_empty()) { - code_editor->get_text_editor()->remove_secondary_carets(); - code_editor->get_text_editor()->set_caret_line(line); + goto_line_centered(line, column); } else { Ref<Resource> scr = ResourceLoader::load(path); if (!scr.is_valid()) { @@ -456,16 +454,16 @@ void ScriptTextEditor::tag_saved_version() { code_editor->get_text_editor()->tag_saved_version(); } -void ScriptTextEditor::goto_line(int p_line, bool p_with_error) { - code_editor->goto_line(p_line); +void ScriptTextEditor::goto_line(int p_line, int p_column) { + code_editor->goto_line(p_line, p_column); } void ScriptTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) { code_editor->goto_line_selection(p_line, p_begin, p_end); } -void ScriptTextEditor::goto_line_centered(int p_line) { - code_editor->goto_line_centered(p_line); +void ScriptTextEditor::goto_line_centered(int p_line, int p_column) { + code_editor->goto_line_centered(p_line, p_column); } void ScriptTextEditor::set_executing_line(int p_line) { @@ -919,8 +917,7 @@ void ScriptTextEditor::_breakpoint_item_pressed(int p_idx) { if (p_idx < 4) { // Any item before the separator. _edit_option(breakpoints_menu->get_item_id(p_idx)); } else { - code_editor->goto_line(breakpoints_menu->get_item_metadata(p_idx)); - callable_mp((TextEdit *)code_editor->get_text_editor(), &TextEdit::center_viewport_to_caret).call_deferred(0); // Needs to be deferred, because goto uses call_deferred(). + code_editor->goto_line_centered(breakpoints_menu->get_item_metadata(p_idx)); } } @@ -1816,9 +1813,9 @@ static String _get_dropped_resource_line(const Ref<Resource> &p_resource, bool p } if (is_script) { - variable_name = variable_name.to_pascal_case().validate_identifier(); + variable_name = variable_name.to_pascal_case().validate_ascii_identifier(); } else { - variable_name = variable_name.to_snake_case().to_upper().validate_identifier(); + variable_name = variable_name.to_snake_case().to_upper().validate_ascii_identifier(); } return vformat("const %s = preload(%s)", variable_name, _quote_drop_data(path)); } @@ -1932,13 +1929,13 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data path = sn->get_path_to(node); } for (const String &segment : path.split("/")) { - if (!segment.is_valid_identifier()) { + if (!segment.is_valid_ascii_identifier()) { path = _quote_drop_data(path); break; } } - String variable_name = String(node->get_name()).to_snake_case().validate_identifier(); + String variable_name = String(node->get_name()).to_snake_case().validate_ascii_identifier(); if (use_type) { StringName class_name = node->get_class_name(); Ref<Script> node_script = node->get_script(); @@ -1975,7 +1972,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data } for (const String &segment : path.split("/")) { - if (!segment.is_valid_identifier()) { + if (!segment.is_valid_ascii_identifier()) { path = _quote_drop_data(path); break; } diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 8c2ec1561b..7aa0726479 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -234,9 +234,9 @@ public: virtual void convert_indent() override; virtual void tag_saved_version() override; - virtual void goto_line(int p_line, bool p_with_error = false) override; + virtual void goto_line(int p_line, int p_column = 0) override; void goto_line_selection(int p_line, int p_begin, int p_end); - void goto_line_centered(int p_line); + void goto_line_centered(int p_line, int p_column = 0); virtual void set_executing_line(int p_line) override; virtual void clear_executing_line() override; diff --git a/editor/plugins/shader/shader_editor.h b/editor/plugins/shader/shader_editor.h new file mode 100644 index 0000000000..32e690015b --- /dev/null +++ b/editor/plugins/shader/shader_editor.h @@ -0,0 +1,50 @@ +/**************************************************************************/ +/* shader_editor.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef SHADER_EDITOR_H +#define SHADER_EDITOR_H + +#include "scene/gui/control.h" +#include "scene/resources/shader.h" + +class ShaderEditor : public Control { + GDCLASS(ShaderEditor, Control); + +public: + virtual void edit_shader(const Ref<Shader> &p_shader) = 0; + virtual void edit_shader_include(const Ref<ShaderInclude> &p_shader_inc) {} + + virtual void apply_shaders() = 0; + virtual bool is_unsaved() const = 0; + virtual void save_external_data(const String &p_str = "") = 0; + virtual void validate_script() = 0; +}; + +#endif // SHADER_EDITOR_H diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 9d1576cdf2..04a392768a 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -45,6 +45,16 @@ #include "scene/gui/item_list.h" #include "scene/gui/texture_rect.h" +Ref<Resource> ShaderEditorPlugin::_get_current_shader() { + int index = shader_tabs->get_current_tab(); + ERR_FAIL_INDEX_V(index, shader_tabs->get_tab_count(), Ref<Resource>()); + if (edited_shaders[index].shader.is_valid()) { + return edited_shaders[index].shader; + } else { + return edited_shaders[index].shader_inc; + } +} + void ShaderEditorPlugin::_update_shader_list() { shader_list->clear(); for (EditedShader &edited_shader : edited_shaders) { @@ -93,9 +103,7 @@ void ShaderEditorPlugin::_update_shader_list() { shader_list->select(shader_tabs->get_current_tab()); } - for (int i = FILE_SAVE; i < FILE_MAX; i++) { - file_menu->get_popup()->set_item_disabled(file_menu->get_popup()->get_item_index(i), edited_shaders.is_empty()); - } + _set_file_specific_items_disabled(edited_shaders.is_empty()); _update_shader_list_status(); } @@ -142,7 +150,7 @@ void ShaderEditorPlugin::edit(Object *p_object) { } es.shader_inc = Ref<ShaderInclude>(si); es.shader_editor = memnew(TextShaderEditor); - es.shader_editor->edit(si); + es.shader_editor->edit_shader_include(si); shader_tabs->add_child(es.shader_editor); } else { Shader *s = Object::cast_to<Shader>(p_object); @@ -156,20 +164,18 @@ void ShaderEditorPlugin::edit(Object *p_object) { es.shader = Ref<Shader>(s); Ref<VisualShader> vs = es.shader; if (vs.is_valid()) { - es.visual_shader_editor = memnew(VisualShaderEditor); - shader_tabs->add_child(es.visual_shader_editor); - es.visual_shader_editor->edit(vs.ptr()); + es.shader_editor = memnew(VisualShaderEditor); } else { es.shader_editor = memnew(TextShaderEditor); - shader_tabs->add_child(es.shader_editor); - es.shader_editor->edit(s); } + shader_tabs->add_child(es.shader_editor); + es.shader_editor->edit_shader(es.shader); } - if (es.shader_editor) { - es.shader_editor->connect("validation_changed", callable_mp(this, &ShaderEditorPlugin::_update_shader_list)); - - CodeTextEditor *cte = es.shader_editor->get_code_editor(); + TextShaderEditor *text_shader_editor = Object::cast_to<TextShaderEditor>(es.shader_editor); + if (text_shader_editor) { + text_shader_editor->connect("validation_changed", callable_mp(this, &ShaderEditorPlugin::_update_shader_list)); + CodeTextEditor *cte = text_shader_editor->get_code_editor(); if (cte) { cte->set_zoom_factor(text_shader_zoom_factor); cte->connect("zoomed", callable_mp(this, &ShaderEditorPlugin::_set_text_shader_zoom_factor)); @@ -194,7 +200,7 @@ void ShaderEditorPlugin::make_visible(bool p_visible) { void ShaderEditorPlugin::selected_notify() { } -TextShaderEditor *ShaderEditorPlugin::get_shader_editor(const Ref<Shader> &p_for_shader) { +ShaderEditor *ShaderEditorPlugin::get_shader_editor(const Ref<Shader> &p_for_shader) { for (EditedShader &edited_shader : edited_shaders) { if (edited_shader.shader == p_for_shader) { return edited_shader.shader_editor; @@ -203,15 +209,6 @@ TextShaderEditor *ShaderEditorPlugin::get_shader_editor(const Ref<Shader> &p_for return nullptr; } -VisualShaderEditor *ShaderEditorPlugin::get_visual_shader_editor(const Ref<Shader> &p_for_shader) { - for (EditedShader &edited_shader : edited_shaders) { - if (edited_shader.shader == p_for_shader) { - return edited_shader.visual_shader_editor; - } - } - return nullptr; -} - void ShaderEditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) { if (EDITOR_GET("interface/multi_window/restore_windows_on_load") && window_wrapper->is_window_available() && p_layout->has_section_key("ShaderEditor", "window_rect")) { window_wrapper->restore_window_from_saved_position( @@ -280,7 +277,7 @@ void ShaderEditorPlugin::get_window_layout(Ref<ConfigFile> p_layout) { String selected_shader; for (int i = 0; i < shader_tabs->get_tab_count(); i++) { EditedShader edited_shader = edited_shaders[i]; - if (edited_shader.shader_editor || edited_shader.visual_shader_editor) { + if (edited_shader.shader_editor) { String shader_path; if (edited_shader.shader.is_valid()) { shader_path = edited_shader.shader->get_path(); @@ -290,10 +287,9 @@ void ShaderEditorPlugin::get_window_layout(Ref<ConfigFile> p_layout) { } shaders.push_back(shader_path); - TextShaderEditor *shader_editor = Object::cast_to<TextShaderEditor>(shader_tabs->get_current_tab_control()); - VisualShaderEditor *visual_shader_editor = Object::cast_to<VisualShaderEditor>(shader_tabs->get_current_tab_control()); + ShaderEditor *shader_editor = Object::cast_to<ShaderEditor>(shader_tabs->get_current_tab_control()); - if ((shader_editor && edited_shader.shader_editor == shader_editor) || (visual_shader_editor && edited_shader.visual_shader_editor == visual_shader_editor)) { + if (shader_editor && edited_shader.shader_editor == shader_editor) { selected_shader = shader_path; } } @@ -366,10 +362,6 @@ void ShaderEditorPlugin::_shader_selected(int p_index) { edited_shaders[p_index].shader_editor->validate_script(); } - if (edited_shaders[p_index].visual_shader_editor) { - edited_shaders[p_index].visual_shader_editor->validate_script(); - } - shader_tabs->set_current_tab(p_index); shader_list->select(p_index); } @@ -378,6 +370,61 @@ void ShaderEditorPlugin::_shader_list_clicked(int p_item, Vector2 p_local_mouse_ if (p_mouse_button_index == MouseButton::MIDDLE) { _close_shader(p_item); } + if (p_mouse_button_index == MouseButton::RIGHT) { + _make_script_list_context_menu(); + } +} + +void ShaderEditorPlugin::_setup_popup_menu(PopupMenuType p_type, PopupMenu *p_menu) { + if (p_type == FILE) { + p_menu->add_shortcut(ED_SHORTCUT("shader_editor/new", TTR("New Shader..."), KeyModifierMask::CMD_OR_CTRL | Key::N), FILE_NEW); + p_menu->add_shortcut(ED_SHORTCUT("shader_editor/new_include", TTR("New Shader Include..."), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::N), FILE_NEW_INCLUDE); + p_menu->add_separator(); + p_menu->add_shortcut(ED_SHORTCUT("shader_editor/open", TTR("Load Shader File..."), KeyModifierMask::CMD_OR_CTRL | Key::O), FILE_OPEN); + p_menu->add_shortcut(ED_SHORTCUT("shader_editor/open_include", TTR("Load Shader Include File..."), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::O), FILE_OPEN_INCLUDE); + } + + if (p_type == FILE || p_type == CONTEXT_VALID_ITEM) { + p_menu->add_shortcut(ED_SHORTCUT("shader_editor/save", TTR("Save File"), KeyModifierMask::ALT | KeyModifierMask::CMD_OR_CTRL | Key::S), FILE_SAVE); + p_menu->add_shortcut(ED_SHORTCUT("shader_editor/save_as", TTR("Save File As...")), FILE_SAVE_AS); + } + + if (p_type == FILE) { + p_menu->add_separator(); + p_menu->add_item(TTR("Open File in Inspector"), FILE_INSPECT); + p_menu->add_separator(); + p_menu->add_shortcut(ED_SHORTCUT("shader_editor/close_file", TTR("Close File"), KeyModifierMask::CMD_OR_CTRL | Key::W), FILE_CLOSE); + } else { + p_menu->add_shortcut(ED_SHORTCUT("shader_editor/close_file", TTR("Close File"), KeyModifierMask::CMD_OR_CTRL | Key::W), FILE_CLOSE); + p_menu->add_item(TTR("Close All"), CLOSE_ALL); + p_menu->add_item(TTR("Close Other Tabs"), CLOSE_OTHER_TABS); + if (p_type == CONTEXT_VALID_ITEM) { + p_menu->add_separator(); + p_menu->add_item(TTR("Copy Script Path"), COPY_PATH); + p_menu->add_item(TTR("Show in File System"), SHOW_IN_FILE_SYSTEM); + } + } +} + +void ShaderEditorPlugin::_make_script_list_context_menu() { + context_menu->clear(); + + int selected = shader_tabs->get_current_tab(); + if (selected < 0 || selected >= shader_tabs->get_tab_count()) { + return; + } + + Control *control = shader_tabs->get_tab_control(selected); + bool is_valid_editor_control = Object::cast_to<TextShaderEditor>(control) || Object::cast_to<VisualShaderEditor>(control); + + _setup_popup_menu(is_valid_editor_control ? CONTEXT_VALID_ITEM : CONTEXT, context_menu); + + context_menu->set_item_disabled(context_menu->get_item_index(CLOSE_ALL), shader_tabs->get_tab_count() <= 0); + context_menu->set_item_disabled(context_menu->get_item_index(CLOSE_OTHER_TABS), shader_tabs->get_tab_count() <= 1); + + context_menu->set_position(main_split->get_screen_position() + main_split->get_local_mouse_position()); + context_menu->reset_size(); + context_menu->popup(); } void ShaderEditorPlugin::_close_shader(int p_index) { @@ -440,7 +487,7 @@ void ShaderEditorPlugin::_menu_item_pressed(int p_index) { case FILE_SAVE: { int index = shader_tabs->get_current_tab(); ERR_FAIL_INDEX(index, shader_tabs->get_tab_count()); - TextShaderEditor *editor = edited_shaders[index].shader_editor; + TextShaderEditor *editor = Object::cast_to<TextShaderEditor>(edited_shaders[index].shader_editor); if (editor) { if (editor->get_trim_trailing_whitespace_on_save()) { editor->trim_trailing_whitespace(); @@ -462,7 +509,7 @@ void ShaderEditorPlugin::_menu_item_pressed(int p_index) { case FILE_SAVE_AS: { int index = shader_tabs->get_current_tab(); ERR_FAIL_INDEX(index, shader_tabs->get_tab_count()); - TextShaderEditor *editor = edited_shaders[index].shader_editor; + TextShaderEditor *editor = Object::cast_to<TextShaderEditor>(edited_shaders[index].shader_editor); if (editor) { if (editor->get_trim_trailing_whitespace_on_save()) { editor->trim_trailing_whitespace(); @@ -502,6 +549,31 @@ void ShaderEditorPlugin::_menu_item_pressed(int p_index) { case FILE_CLOSE: { _close_shader(shader_tabs->get_current_tab()); } break; + case CLOSE_ALL: { + while (shader_tabs->get_tab_count() > 0) { + _close_shader(0); + } + } break; + case CLOSE_OTHER_TABS: { + int index = shader_tabs->get_current_tab(); + for (int i = 0; i < index; i++) { + _close_shader(0); + } + while (shader_tabs->get_tab_count() > 1) { + _close_shader(1); + } + } break; + case SHOW_IN_FILE_SYSTEM: { + Ref<Resource> shader = _get_current_shader(); + String path = shader->get_path(); + if (!path.is_empty()) { + FileSystemDock::get_singleton()->navigate_to_path(path); + } + } break; + case COPY_PATH: { + Ref<Resource> shader = _get_current_shader(); + DisplayServer::get_singleton()->clipboard_set(shader->get_path()); + } break; } } @@ -623,8 +695,9 @@ void ShaderEditorPlugin::_set_text_shader_zoom_factor(float p_zoom_factor) { if (text_shader_zoom_factor != p_zoom_factor) { text_shader_zoom_factor = p_zoom_factor; for (const EditedShader &edited_shader : edited_shaders) { - if (edited_shader.shader_editor) { - CodeTextEditor *cte = edited_shader.shader_editor->get_code_editor(); + TextShaderEditor *text_shader_editor = Object::cast_to<TextShaderEditor>(edited_shader.shader_editor); + if (text_shader_editor) { + CodeTextEditor *cte = text_shader_editor->get_code_editor(); if (cte && cte->get_zoom_factor() != text_shader_zoom_factor) { cte->set_zoom_factor(text_shader_zoom_factor); } @@ -655,17 +728,26 @@ void ShaderEditorPlugin::_res_saved_callback(const Ref<Resource> &p_res) { } ERR_FAIL_COND(shader_res.is_null()); - if (!edited.shader_editor || !shader_res->is_built_in()) { + TextShaderEditor *text_shader_editor = Object::cast_to<TextShaderEditor>(edited.shader_editor); + if (!text_shader_editor || !shader_res->is_built_in()) { continue; } if (shader_res->get_path().get_slice("::", 0) == path) { - edited.shader_editor->tag_saved_version(); + text_shader_editor->tag_saved_version(); _update_shader_list(); } } } +void ShaderEditorPlugin::_set_file_specific_items_disabled(bool p_disabled) { + PopupMenu *file_popup_menu = file_menu->get_popup(); + file_popup_menu->set_item_disabled(file_popup_menu->get_item_index(FILE_SAVE), p_disabled); + file_popup_menu->set_item_disabled(file_popup_menu->get_item_index(FILE_SAVE_AS), p_disabled); + file_popup_menu->set_item_disabled(file_popup_menu->get_item_index(FILE_INSPECT), p_disabled); + file_popup_menu->set_item_disabled(file_popup_menu->get_item_index(FILE_CLOSE), p_disabled); +} + void ShaderEditorPlugin::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: { @@ -693,23 +775,15 @@ ShaderEditorPlugin::ShaderEditorPlugin() { file_menu = memnew(MenuButton); file_menu->set_text(TTR("File")); file_menu->set_shortcut_context(main_split); - file_menu->get_popup()->add_item(TTR("New Shader..."), FILE_NEW); - file_menu->get_popup()->add_item(TTR("New Shader Include..."), FILE_NEW_INCLUDE); - file_menu->get_popup()->add_separator(); - file_menu->get_popup()->add_item(TTR("Load Shader File..."), FILE_OPEN); - file_menu->get_popup()->add_item(TTR("Load Shader Include File..."), FILE_OPEN_INCLUDE); - file_menu->get_popup()->add_shortcut(ED_SHORTCUT("shader_editor/save", TTR("Save File"), KeyModifierMask::ALT | KeyModifierMask::CMD_OR_CTRL | Key::S), FILE_SAVE); - file_menu->get_popup()->add_shortcut(ED_SHORTCUT("shader_editor/save_as", TTR("Save File As...")), FILE_SAVE_AS); - file_menu->get_popup()->add_separator(); - file_menu->get_popup()->add_item(TTR("Open File in Inspector"), FILE_INSPECT); - file_menu->get_popup()->add_separator(); - file_menu->get_popup()->add_item(TTR("Close File"), FILE_CLOSE); + _setup_popup_menu(FILE, file_menu->get_popup()); file_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &ShaderEditorPlugin::_menu_item_pressed)); menu_hb->add_child(file_menu); - for (int i = FILE_SAVE; i < FILE_MAX; i++) { - file_menu->get_popup()->set_item_disabled(file_menu->get_popup()->get_item_index(i), true); - } + _set_file_specific_items_disabled(true); + + context_menu = memnew(PopupMenu); + add_child(context_menu); + context_menu->connect(SceneStringName(id_pressed), callable_mp(this, &ShaderEditorPlugin::_menu_item_pressed)); Control *padding = memnew(Control); padding->set_h_size_flags(Control::SIZE_EXPAND_FILL); @@ -732,6 +806,7 @@ ShaderEditorPlugin::ShaderEditorPlugin() { vb->add_child(shader_list); shader_list->connect(SceneStringName(item_selected), callable_mp(this, &ShaderEditorPlugin::_shader_selected)); shader_list->connect("item_clicked", callable_mp(this, &ShaderEditorPlugin::_shader_list_clicked)); + shader_list->set_allow_rmb_select(true); SET_DRAG_FORWARDING_GCD(shader_list, ShaderEditorPlugin); main_split->add_child(vb); diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h index 386261d844..31be64a56c 100644 --- a/editor/plugins/shader_editor_plugin.h +++ b/editor/plugins/shader_editor_plugin.h @@ -37,6 +37,7 @@ class HSplitContainer; class ItemList; class MenuButton; class ShaderCreateDialog; +class ShaderEditor; class TabContainer; class TextShaderEditor; class VisualShaderEditor; @@ -52,16 +53,13 @@ class ShaderEditorPlugin : public EditorPlugin { struct EditedShader { Ref<Shader> shader; Ref<ShaderInclude> shader_inc; - TextShaderEditor *shader_editor = nullptr; - VisualShaderEditor *visual_shader_editor = nullptr; + ShaderEditor *shader_editor = nullptr; String path; String name; }; LocalVector<EditedShader> edited_shaders; - // Always valid operations come first in the enum, file-specific ones - // should go after FILE_SAVE which is used to build the menu accordingly. enum { FILE_NEW, FILE_NEW_INCLUDE, @@ -71,7 +69,16 @@ class ShaderEditorPlugin : public EditorPlugin { FILE_SAVE_AS, FILE_INSPECT, FILE_CLOSE, - FILE_MAX + CLOSE_ALL, + CLOSE_OTHER_TABS, + SHOW_IN_FILE_SYSTEM, + COPY_PATH, + }; + + enum PopupMenuType { + FILE, + CONTEXT, + CONTEXT_VALID_ITEM, }; HSplitContainer *main_split = nullptr; @@ -80,6 +87,7 @@ class ShaderEditorPlugin : public EditorPlugin { Button *button = nullptr; MenuButton *file_menu = nullptr; + PopupMenu *context_menu = nullptr; WindowWrapper *window_wrapper = nullptr; Button *make_floating = nullptr; @@ -88,15 +96,19 @@ class ShaderEditorPlugin : public EditorPlugin { float text_shader_zoom_factor = 1.0f; + Ref<Resource> _get_current_shader(); void _update_shader_list(); void _shader_selected(int p_index); void _shader_list_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index); + void _setup_popup_menu(PopupMenuType p_type, PopupMenu *p_menu); + void _make_script_list_context_menu(); void _menu_item_pressed(int p_index); void _resource_saved(Object *obj); void _close_shader(int p_index); void _close_builtin_shaders_from_scene(const String &p_scene); void _file_removed(const String &p_removed_file); void _res_saved_callback(const Ref<Resource> &p_res); + void _set_file_specific_items_disabled(bool p_disabled); void _shader_created(Ref<Shader> p_shader); void _shader_include_created(Ref<ShaderInclude> p_shader_inc); @@ -121,8 +133,7 @@ public: virtual void make_visible(bool p_visible) override; virtual void selected_notify() override; - TextShaderEditor *get_shader_editor(const Ref<Shader> &p_for_shader); - VisualShaderEditor *get_visual_shader_editor(const Ref<Shader> &p_for_shader); + ShaderEditor *get_shader_editor(const Ref<Shader> &p_for_shader); virtual void set_window_layout(Ref<ConfigFile> p_layout) override; virtual void get_window_layout(Ref<ConfigFile> p_layout) override; diff --git a/editor/plugins/shader_file_editor_plugin.cpp b/editor/plugins/shader_file_editor_plugin.cpp index 05919fb0f6..d732d51f69 100644 --- a/editor/plugins/shader_file_editor_plugin.cpp +++ b/editor/plugins/shader_file_editor_plugin.cpp @@ -218,9 +218,6 @@ void ShaderFileEditor::_editor_settings_changed() { } } -void ShaderFileEditor::_bind_methods() { -} - void ShaderFileEditor::edit(const Ref<RDShaderFile> &p_shader) { if (p_shader.is_null()) { if (shader_file.is_valid()) { diff --git a/editor/plugins/shader_file_editor_plugin.h b/editor/plugins/shader_file_editor_plugin.h index 9a915513ef..fea770b7e0 100644 --- a/editor/plugins/shader_file_editor_plugin.h +++ b/editor/plugins/shader_file_editor_plugin.h @@ -62,7 +62,6 @@ class ShaderFileEditor : public PanelContainer { protected: void _notification(int p_what); - static void _bind_methods(); public: static ShaderFileEditor *singleton; diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp index 8308fe6d6e..97c5c0c7dd 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.cpp +++ b/editor/plugins/skeleton_2d_editor_plugin.cpp @@ -90,9 +90,6 @@ void Skeleton2DEditor::_menu_option(int p_option) { } } -void Skeleton2DEditor::_bind_methods() { -} - Skeleton2DEditor::Skeleton2DEditor() { options = memnew(MenuButton); diff --git a/editor/plugins/skeleton_2d_editor_plugin.h b/editor/plugins/skeleton_2d_editor_plugin.h index 74fd59f1c4..89e2e5d0f2 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.h +++ b/editor/plugins/skeleton_2d_editor_plugin.h @@ -57,7 +57,6 @@ class Skeleton2DEditor : public Control { protected: void _node_removed(Node *p_node); - static void _bind_methods(); public: void edit(Skeleton2D *p_sprite); diff --git a/editor/plugins/skeleton_ik_3d_editor_plugin.cpp b/editor/plugins/skeleton_ik_3d_editor_plugin.cpp index 1753df5cb7..9b98b6ffa2 100644 --- a/editor/plugins/skeleton_ik_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_ik_3d_editor_plugin.cpp @@ -73,9 +73,6 @@ void SkeletonIK3DEditorPlugin::make_visible(bool p_visible) { } } -void SkeletonIK3DEditorPlugin::_bind_methods() { -} - SkeletonIK3DEditorPlugin::SkeletonIK3DEditorPlugin() { play_btn = memnew(Button); play_btn->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Play"), EditorStringName(EditorIcons))); diff --git a/editor/plugins/skeleton_ik_3d_editor_plugin.h b/editor/plugins/skeleton_ik_3d_editor_plugin.h index 2ef5467263..95ab3696be 100644 --- a/editor/plugins/skeleton_ik_3d_editor_plugin.h +++ b/editor/plugins/skeleton_ik_3d_editor_plugin.h @@ -45,9 +45,6 @@ class SkeletonIK3DEditorPlugin : public EditorPlugin { void _play(); -protected: - static void _bind_methods(); - public: virtual String get_name() const override { return "SkeletonIK3D"; } bool has_main_screen() const override { return false; } diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index 48087e3166..ff5aca6cb0 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -504,6 +504,82 @@ void SpriteFramesEditor::_update_show_settings() { } } +void SpriteFramesEditor::_auto_slice_sprite_sheet() { + if (updating_split_settings) { + return; + } + updating_split_settings = true; + + const Size2i size = split_sheet_preview->get_texture()->get_size(); + + const Size2i split_sheet = _estimate_sprite_sheet_size(split_sheet_preview->get_texture()); + split_sheet_h->set_value(split_sheet.x); + split_sheet_v->set_value(split_sheet.y); + split_sheet_size_x->set_value(size.x / split_sheet.x); + split_sheet_size_y->set_value(size.y / split_sheet.y); + split_sheet_sep_x->set_value(0); + split_sheet_sep_y->set_value(0); + split_sheet_offset_x->set_value(0); + split_sheet_offset_y->set_value(0); + + updating_split_settings = false; + + frames_selected.clear(); + selected_count = 0; + last_frame_selected = -1; + split_sheet_preview->queue_redraw(); +} + +bool SpriteFramesEditor::_matches_background_color(const Color &p_background_color, const Color &p_pixel_color) { + if ((p_background_color.a == 0 && p_pixel_color.a == 0) || p_background_color.is_equal_approx(p_pixel_color)) { + return true; + } + + Color d = p_background_color - p_pixel_color; + // 0.04f is the threshold for how much a colour can deviate from background colour and still be considered a match. Arrived at through experimentation, can be tweaked. + return (d.r * d.r) + (d.g * d.g) + (d.b * d.b) + (d.a * d.a) < 0.04f; +} + +Size2i SpriteFramesEditor::_estimate_sprite_sheet_size(const Ref<Texture2D> p_texture) { + Ref<Image> image = p_texture->get_image(); + Size2i size = p_texture->get_size(); + + Color assumed_background_color = image->get_pixel(0, 0); + Size2i sheet_size; + + bool previous_line_background = true; + for (int x = 0; x < size.x; x++) { + int y = 0; + while (y < size.y && _matches_background_color(assumed_background_color, image->get_pixel(x, y))) { + y++; + } + bool current_line_background = (y == size.y); + if (previous_line_background && !current_line_background) { + sheet_size.x++; + } + previous_line_background = current_line_background; + } + + previous_line_background = true; + for (int y = 0; y < size.y; y++) { + int x = 0; + while (x < size.x && _matches_background_color(assumed_background_color, image->get_pixel(x, y))) { + x++; + } + bool current_line_background = (x == size.x); + if (previous_line_background && !current_line_background) { + sheet_size.y++; + } + previous_line_background = current_line_background; + } + + if (sheet_size == Size2i(0, 0) || sheet_size == Size2i(1, 1)) { + sheet_size = Size2i(4, 4); + } + + return sheet_size; +} + void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) { Ref<Texture2D> texture = ResourceLoader::load(p_file); if (texture.is_null()) { @@ -530,10 +606,11 @@ void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) { // Different texture, reset to 4x4. dominant_param = PARAM_FRAME_COUNT; updating_split_settings = true; - split_sheet_h->set_value(4); - split_sheet_v->set_value(4); - split_sheet_size_x->set_value(size.x / 4); - split_sheet_size_y->set_value(size.y / 4); + const Size2i split_sheet = Size2i(4, 4); + split_sheet_h->set_value(split_sheet.x); + split_sheet_v->set_value(split_sheet.y); + split_sheet_size_x->set_value(size.x / split_sheet.x); + split_sheet_size_y->set_value(size.y / split_sheet.y); split_sheet_sep_x->set_value(0); split_sheet_sep_y->set_value(0); split_sheet_offset_x->set_value(0); @@ -2290,6 +2367,11 @@ SpriteFramesEditor::SpriteFramesEditor() { split_sheet_offset_hb->add_child(split_sheet_offset_vb); split_sheet_settings_vb->add_child(split_sheet_offset_hb); + Button *auto_slice = memnew(Button); + auto_slice->set_text(TTR("Auto Slice")); + auto_slice->connect(SceneStringName(pressed), callable_mp(this, &SpriteFramesEditor::_auto_slice_sprite_sheet)); + split_sheet_settings_vb->add_child(auto_slice); + split_sheet_hb->add_child(split_sheet_settings_vb); file_split_sheet = memnew(EditorFileDialog); diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h index 9b6aaf98fe..d6345a3ac8 100644 --- a/editor/plugins/sprite_frames_editor_plugin.h +++ b/editor/plugins/sprite_frames_editor_plugin.h @@ -234,6 +234,9 @@ class SpriteFramesEditor : public HSplitContainer { void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); void _open_sprite_sheet(); + void _auto_slice_sprite_sheet(); + bool _matches_background_color(const Color &p_background_color, const Color &p_pixel_color); + Size2i _estimate_sprite_sheet_size(const Ref<Texture2D> p_texture); void _prepare_sprite_sheet(const String &p_file); int _sheet_preview_position_to_frame_index(const Vector2 &p_position); void _sheet_preview_draw(); diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index ecdc4acf47..cb1f6c1ec6 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -304,8 +304,8 @@ void TextEditor::tag_saved_version() { code_editor->get_text_editor()->tag_saved_version(); } -void TextEditor::goto_line(int p_line, bool p_with_error) { - code_editor->goto_line(p_line); +void TextEditor::goto_line(int p_line, int p_column) { + code_editor->goto_line(p_line, p_column); } void TextEditor::goto_line_selection(int p_line, int p_begin, int p_end) { diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index 268e5c32b4..1acec4e959 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -129,7 +129,7 @@ public: virtual PackedInt32Array get_breakpoints() override; virtual void set_breakpoint(int p_line, bool p_enabled) override{}; virtual void clear_breakpoints() override{}; - virtual void goto_line(int p_line, bool p_with_error = false) override; + virtual void goto_line(int p_line, int p_column = 0) override; void goto_line_selection(int p_line, int p_begin, int p_end); virtual void set_executing_line(int p_line) override; virtual void clear_executing_line() override; diff --git a/editor/plugins/text_shader_editor.cpp b/editor/plugins/text_shader_editor.cpp index 276c57533f..4d8f3298b6 100644 --- a/editor/plugins/text_shader_editor.cpp +++ b/editor/plugins/text_shader_editor.cpp @@ -779,7 +779,7 @@ void TextShaderEditor::_show_warnings_panel(bool p_show) { void TextShaderEditor::_warning_clicked(const Variant &p_line) { if (p_line.get_type() == Variant::INT) { - code_editor->get_text_editor()->set_caret_line(p_line.operator int64_t()); + code_editor->goto_line_centered(p_line.operator int64_t()); } } @@ -895,7 +895,7 @@ void TextShaderEditor::_reload() { } } -void TextShaderEditor::edit(const Ref<Shader> &p_shader) { +void TextShaderEditor::edit_shader(const Ref<Shader> &p_shader) { if (p_shader.is_null() || !p_shader->is_text_shader()) { return; } @@ -910,7 +910,7 @@ void TextShaderEditor::edit(const Ref<Shader> &p_shader) { code_editor->set_edited_shader(shader); } -void TextShaderEditor::edit(const Ref<ShaderInclude> &p_shader_inc) { +void TextShaderEditor::edit_shader_include(const Ref<ShaderInclude> &p_shader_inc) { if (p_shader_inc.is_null()) { return; } @@ -1141,6 +1141,7 @@ TextShaderEditor::TextShaderEditor() { context_menu->connect(SceneStringName(id_pressed), callable_mp(this, &TextShaderEditor::_menu_option)); VBoxContainer *main_container = memnew(VBoxContainer); + main_container->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); HBoxContainer *hbc = memnew(HBoxContainer); edit_menu = memnew(MenuButton); diff --git a/editor/plugins/text_shader_editor.h b/editor/plugins/text_shader_editor.h index 61066ed7c6..55efb4e30e 100644 --- a/editor/plugins/text_shader_editor.h +++ b/editor/plugins/text_shader_editor.h @@ -32,6 +32,7 @@ #define TEXT_SHADER_EDITOR_H #include "editor/code_editor.h" +#include "editor/plugins/shader/shader_editor.h" #include "scene/gui/margin_container.h" #include "scene/gui/menu_button.h" #include "scene/gui/rich_text_label.h" @@ -104,8 +105,8 @@ public: ShaderTextEditor(); }; -class TextShaderEditor : public MarginContainer { - GDCLASS(TextShaderEditor, MarginContainer); +class TextShaderEditor : public ShaderEditor { + GDCLASS(TextShaderEditor, ShaderEditor); enum { EDIT_UNDO, @@ -188,19 +189,21 @@ protected: void _bookmark_item_pressed(int p_idx); public: + virtual void edit_shader(const Ref<Shader> &p_shader) override; + virtual void edit_shader_include(const Ref<ShaderInclude> &p_shader_inc) override; + + virtual void apply_shaders() override; + virtual bool is_unsaved() const override; + virtual void save_external_data(const String &p_str = "") override; + virtual void validate_script() override; + bool was_compilation_successful() const { return compilation_success; } bool get_trim_trailing_whitespace_on_save() const { return trim_trailing_whitespace_on_save; } bool get_trim_final_newlines_on_save() const { return trim_final_newlines_on_save; } - void apply_shaders(); void ensure_select_current(); - void edit(const Ref<Shader> &p_shader); - void edit(const Ref<ShaderInclude> &p_shader_inc); void goto_line_selection(int p_line, int p_begin, int p_end); - void save_external_data(const String &p_str = ""); void trim_trailing_whitespace(); void trim_final_newlines(); - void validate_script(); - bool is_unsaved() const; void tag_saved_version(); ShaderTextEditor *get_code_editor() { return code_editor; } diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp index fa90e982fe..9fce79622a 100644 --- a/editor/plugins/texture_3d_editor_plugin.cpp +++ b/editor/plugins/texture_3d_editor_plugin.cpp @@ -30,8 +30,25 @@ #include "texture_3d_editor_plugin.h" +#include "editor/editor_string_names.h" +#include "editor/themes/editor_scale.h" #include "scene/gui/label.h" +// Shader sources. + +constexpr const char *texture_3d_shader = R"( + // Texture3DEditor preview shader. + + shader_type canvas_item; + + uniform sampler3D tex; + uniform float layer; + + void fragment() { + COLOR = textureLod(tex, vec3(UV, layer), 0.0); + } +)"; + void Texture3DEditor::_texture_rect_draw() { texture_rect->draw_rect(Rect2(Point2(), texture_rect->get_size()), Color(1, 1, 1, 1)); } @@ -48,6 +65,13 @@ void Texture3DEditor::_notification(int p_what) { draw_texture_rect(checkerboard, Rect2(Point2(), size), true); } break; + + case NOTIFICATION_THEME_CHANGED: { + if (info) { + Ref<Font> metadata_label_font = get_theme_font(SNAME("expression"), EditorStringName(EditorFonts)); + info->add_theme_font_override(SceneStringName(font), metadata_label_font); + } + } break; } } @@ -55,35 +79,27 @@ void Texture3DEditor::_texture_changed() { if (!is_visible()) { return; } + + setting = true; + _update_gui(); + setting = false; + + _update_material(true); queue_redraw(); } -void Texture3DEditor::_update_material() { +void Texture3DEditor::_update_material(bool p_texture_changed) { material->set_shader_parameter("layer", (layer->get_value() + 0.5) / texture->get_depth()); - material->set_shader_parameter("tex", texture->get_rid()); - - String format = Image::get_format_name(texture->get_format()); - - String text; - text = itos(texture->get_width()) + "x" + itos(texture->get_height()) + "x" + itos(texture->get_depth()) + " " + format; - info->set_text(text); + if (p_texture_changed) { + material->set_shader_parameter("tex", texture->get_rid()); + } } void Texture3DEditor::_make_shaders() { shader.instantiate(); - shader->set_code(R"( -// Texture3DEditor preview shader. - -shader_type canvas_item; - -uniform sampler3D tex; -uniform float layer; + shader->set_code(texture_3d_shader); -void fragment() { - COLOR = textureLod(tex, vec3(UV, layer), 0.0); -} -)"); material.instantiate(); material->set_shader(shader); } @@ -113,6 +129,41 @@ void Texture3DEditor::_texture_rect_update_area() { texture_rect->set_size(Vector2(tex_width, tex_height)); } +void Texture3DEditor::_update_gui() { + if (texture.is_null()) { + return; + } + + _texture_rect_update_area(); + + layer->set_max(texture->get_depth() - 1); + + const String format = Image::get_format_name(texture->get_format()); + + if (texture->has_mipmaps()) { + const int mip_count = Image::get_image_required_mipmaps(texture->get_width(), texture->get_height(), texture->get_format()); + const int memory = Image::get_image_data_size(texture->get_width(), texture->get_height(), texture->get_format(), true) * texture->get_depth(); + + info->set_text(vformat(String::utf8("%d×%d×%d %s\n") + TTR("%s Mipmaps") + "\n" + TTR("Memory: %s"), + texture->get_width(), + texture->get_height(), + texture->get_depth(), + format, + mip_count, + String::humanize_size(memory))); + + } else { + const int memory = Image::get_image_data_size(texture->get_width(), texture->get_height(), texture->get_format(), false) * texture->get_depth(); + + info->set_text(vformat(String::utf8("%d×%d×%d %s\n") + TTR("No Mipmaps") + "\n" + TTR("Memory: %s"), + texture->get_width(), + texture->get_height(), + texture->get_depth(), + format, + String::humanize_size(memory))); + } +} + void Texture3DEditor::edit(Ref<Texture3D> p_texture) { if (!texture.is_null()) { texture->disconnect_changed(callable_mp(this, &Texture3DEditor::_texture_changed)); @@ -126,15 +177,17 @@ void Texture3DEditor::edit(Ref<Texture3D> p_texture) { } texture->connect_changed(callable_mp(this, &Texture3DEditor::_texture_changed)); - queue_redraw(); texture_rect->set_material(material); + setting = true; - layer->set_max(texture->get_depth() - 1); layer->set_value(0); layer->show(); - _update_material(); + _update_gui(); setting = false; - _texture_rect_update_area(); + + _update_material(true); + queue_redraw(); + } else { hide(); } @@ -142,36 +195,43 @@ void Texture3DEditor::edit(Ref<Texture3D> p_texture) { Texture3DEditor::Texture3DEditor() { set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED); - set_custom_minimum_size(Size2(1, 150)); + set_custom_minimum_size(Size2(1, 256.0) * EDSCALE); texture_rect = memnew(Control); texture_rect->set_mouse_filter(MOUSE_FILTER_IGNORE); - add_child(texture_rect); texture_rect->connect(SceneStringName(draw), callable_mp(this, &Texture3DEditor::_texture_rect_draw)); + add_child(texture_rect); + layer = memnew(SpinBox); layer->set_step(1); layer->set_max(100); - layer->set_h_grow_direction(GROW_DIRECTION_BEGIN); + layer->set_modulate(Color(1, 1, 1, 0.8)); - add_child(layer); + layer->set_h_grow_direction(GROW_DIRECTION_BEGIN); layer->set_anchor(SIDE_RIGHT, 1); layer->set_anchor(SIDE_LEFT, 1); layer->connect(SceneStringName(value_changed), callable_mp(this, &Texture3DEditor::_layer_changed)); + add_child(layer); + info = memnew(Label); + info->add_theme_color_override(SceneStringName(font_color), Color(1, 1, 1)); + info->add_theme_color_override("font_shadow_color", Color(0, 0, 0)); + info->add_theme_font_size_override(SceneStringName(font_size), 14 * EDSCALE); + info->add_theme_color_override("font_outline_color", Color(0, 0, 0)); + info->add_theme_constant_override("outline_size", 8 * EDSCALE); + info->set_h_grow_direction(GROW_DIRECTION_BEGIN); info->set_v_grow_direction(GROW_DIRECTION_BEGIN); - info->add_theme_color_override(SceneStringName(font_color), Color(1, 1, 1, 1)); - info->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 0.5)); - info->add_theme_constant_override("shadow_outline_size", 1); - info->add_theme_constant_override("shadow_offset_x", 2); - info->add_theme_constant_override("shadow_offset_y", 2); - add_child(info); + info->set_h_size_flags(Control::SIZE_SHRINK_END); + info->set_v_size_flags(Control::SIZE_SHRINK_END); info->set_anchor(SIDE_RIGHT, 1); info->set_anchor(SIDE_LEFT, 1); info->set_anchor(SIDE_BOTTOM, 1); info->set_anchor(SIDE_TOP, 1); + + add_child(info); } Texture3DEditor::~Texture3DEditor() { @@ -180,7 +240,6 @@ Texture3DEditor::~Texture3DEditor() { } } -// bool EditorInspectorPlugin3DTexture::can_handle(Object *p_object) { return Object::cast_to<Texture3D>(p_object) != nullptr; } diff --git a/editor/plugins/texture_3d_editor_plugin.h b/editor/plugins/texture_3d_editor_plugin.h index 7a33a97a8f..0712ff423a 100644 --- a/editor/plugins/texture_3d_editor_plugin.h +++ b/editor/plugins/texture_3d_editor_plugin.h @@ -52,23 +52,27 @@ class Texture3DEditor : public Control { bool setting = false; void _make_shaders(); - void _update_material(); void _layer_changed(double) { if (!setting) { - _update_material(); + _update_material(false); } } + void _texture_changed(); void _texture_rect_update_area(); void _texture_rect_draw(); + void _update_material(bool p_texture_changed); + void _update_gui(); + protected: void _notification(int p_what); public: void edit(Ref<Texture3D> p_texture); + Texture3DEditor(); ~Texture3DEditor(); }; diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp index e9d7aa9eb8..a3c1405553 100644 --- a/editor/plugins/texture_editor_plugin.cpp +++ b/editor/plugins/texture_editor_plugin.cpp @@ -145,12 +145,13 @@ TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) { p_texture->connect_changed(callable_mp(this, &TexturePreview::_update_metadata_label_text)); // It's okay that these colors are static since the grid color is static too. - metadata_label->add_theme_color_override(SceneStringName(font_color), Color::named("white")); - metadata_label->add_theme_color_override("font_shadow_color", Color::named("black")); + metadata_label->add_theme_color_override(SceneStringName(font_color), Color(1, 1, 1)); + metadata_label->add_theme_color_override("font_shadow_color", Color(0, 0, 0)); metadata_label->add_theme_font_size_override(SceneStringName(font_size), 14 * EDSCALE); - metadata_label->add_theme_color_override("font_outline_color", Color::named("black")); + metadata_label->add_theme_color_override("font_outline_color", Color(0, 0, 0)); metadata_label->add_theme_constant_override("outline_size", 8 * EDSCALE); + metadata_label->set_h_size_flags(Control::SIZE_SHRINK_END); metadata_label->set_v_size_flags(Control::SIZE_SHRINK_END); diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp index 4ec9c91cf9..a8aa89a8c4 100644 --- a/editor/plugins/texture_layered_editor_plugin.cpp +++ b/editor/plugins/texture_layered_editor_plugin.cpp @@ -30,16 +30,64 @@ #include "texture_layered_editor_plugin.h" +#include "editor/editor_string_names.h" +#include "editor/themes/editor_scale.h" #include "scene/gui/label.h" +// Shader sources. + +constexpr const char *array_2d_shader = R"( + // TextureLayeredEditor preview shader (2D array). + + shader_type canvas_item; + + uniform sampler2DArray tex; + uniform float layer; + + void fragment() { + COLOR = textureLod(tex, vec3(UV, layer), 0.0); + } +)"; + +constexpr const char *cubemap_shader = R"( + // TextureLayeredEditor preview shader (cubemap). + + shader_type canvas_item; + + uniform samplerCube tex; + uniform vec3 normal; + uniform mat3 rot; + + void fragment() { + vec3 n = rot * normalize(vec3(normal.xy * (UV * 2.0 - 1.0), normal.z)); + COLOR = textureLod(tex, n, 0.0); + } +)"; + +constexpr const char *cubemap_array_shader = R"( + // TextureLayeredEditor preview shader (cubemap array). + + shader_type canvas_item; + uniform samplerCubeArray tex; + uniform vec3 normal; + uniform mat3 rot; + uniform float layer; + + void fragment() { + vec3 n = rot * normalize(vec3(normal.xy * (UV * 2.0 - 1.0), normal.z)); + COLOR = textureLod(tex, vec4(n, layer), 0.0); + } +)"; + void TextureLayeredEditor::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid() && (mm->get_button_mask().has_flag(MouseButtonMask::LEFT))) { y_rot += -mm->get_relative().x * 0.01; - x_rot += mm->get_relative().y * 0.01; - _update_material(); + x_rot += -mm->get_relative().y * 0.01; + + _update_material(false); } } @@ -47,6 +95,69 @@ void TextureLayeredEditor::_texture_rect_draw() { texture_rect->draw_rect(Rect2(Point2(), texture_rect->get_size()), Color(1, 1, 1, 1)); } +void TextureLayeredEditor::_update_gui() { + if (texture.is_null()) { + return; + } + + _texture_rect_update_area(); + + const String format = Image::get_format_name(texture->get_format()); + String texture_info; + + switch (texture->get_layered_type()) { + case TextureLayered::LAYERED_TYPE_2D_ARRAY: { + layer->set_max(texture->get_layers() - 1); + + texture_info = vformat(String::utf8("%d×%d (×%d) %s\n"), + texture->get_width(), + texture->get_height(), + texture->get_layers(), + format); + + } break; + case TextureLayered::LAYERED_TYPE_CUBEMAP: { + layer->hide(); + + texture_info = vformat(String::utf8("%d×%d %s\n"), + texture->get_width(), + texture->get_height(), + format); + + } break; + case TextureLayered::LAYERED_TYPE_CUBEMAP_ARRAY: { + layer->set_max(texture->get_layers() / 6 - 1); + + texture_info = vformat(String::utf8("%d×%d (×%d) %s\n"), + texture->get_width(), + texture->get_height(), + texture->get_layers() / 6, + format); + + } break; + + default: { + } + } + + if (texture->has_mipmaps()) { + const int mip_count = Image::get_image_required_mipmaps(texture->get_width(), texture->get_height(), texture->get_format()); + const int memory = Image::get_image_data_size(texture->get_width(), texture->get_height(), texture->get_format(), true) * texture->get_layers(); + + texture_info += vformat(TTR("%s Mipmaps") + "\n" + TTR("Memory: %s"), + mip_count, + String::humanize_size(memory)); + + } else { + const int memory = Image::get_image_data_size(texture->get_width(), texture->get_height(), texture->get_format(), false) * texture->get_layers(); + + texture_info += vformat(TTR("No Mipmaps") + "\n" + TTR("Memory: %s"), + String::humanize_size(memory)); + } + + info->set_text(texture_info); +} + void TextureLayeredEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_RESIZED: { @@ -59,6 +170,13 @@ void TextureLayeredEditor::_notification(int p_what) { draw_texture_rect(checkerboard, Rect2(Point2(), size), true); } break; + + case NOTIFICATION_THEME_CHANGED: { + if (info) { + Ref<Font> metadata_label_font = get_theme_font(SNAME("expression"), EditorStringName(EditorFonts)); + info->add_theme_font_override(SceneStringName(font), metadata_label_font); + } + } break; } } @@ -66,13 +184,18 @@ void TextureLayeredEditor::_texture_changed() { if (!is_visible()) { return; } + + setting = true; + _update_gui(); + setting = false; + + _update_material(true); queue_redraw(); } -void TextureLayeredEditor::_update_material() { +void TextureLayeredEditor::_update_material(bool p_texture_changed) { materials[0]->set_shader_parameter("layer", layer->get_value()); materials[2]->set_shader_parameter("layer", layer->get_value()); - materials[texture->get_layered_type()]->set_shader_parameter("tex", texture->get_rid()); Vector3 v(1, 1, 1); v.normalize(); @@ -86,67 +209,20 @@ void TextureLayeredEditor::_update_material() { materials[2]->set_shader_parameter("normal", v); materials[2]->set_shader_parameter("rot", b); - String format = Image::get_format_name(texture->get_format()); - - String text; - if (texture->get_layered_type() == TextureLayered::LAYERED_TYPE_2D_ARRAY) { - text = itos(texture->get_width()) + "x" + itos(texture->get_height()) + " (x " + itos(texture->get_layers()) + ")" + format; - } else if (texture->get_layered_type() == TextureLayered::LAYERED_TYPE_CUBEMAP) { - text = itos(texture->get_width()) + "x" + itos(texture->get_height()) + " " + format; - } else if (texture->get_layered_type() == TextureLayered::LAYERED_TYPE_CUBEMAP_ARRAY) { - text = itos(texture->get_width()) + "x" + itos(texture->get_height()) + " (x " + itos(texture->get_layers() / 6) + ")" + format; + if (p_texture_changed) { + materials[texture->get_layered_type()]->set_shader_parameter("tex", texture->get_rid()); } - - info->set_text(text); } void TextureLayeredEditor::_make_shaders() { shaders[0].instantiate(); - shaders[0]->set_code(R"( -// TextureLayeredEditor preview shader (2D array). - -shader_type canvas_item; - -uniform sampler2DArray tex; -uniform float layer; - -void fragment() { - COLOR = textureLod(tex, vec3(UV, layer), 0.0); -} -)"); + shaders[0]->set_code(array_2d_shader); shaders[1].instantiate(); - shaders[1]->set_code(R"( -// TextureLayeredEditor preview shader (cubemap). - -shader_type canvas_item; - -uniform samplerCube tex; -uniform vec3 normal; -uniform mat3 rot; - -void fragment() { - vec3 n = rot * normalize(vec3(normal.xy * (UV * 2.0 - 1.0), normal.z)); - COLOR = textureLod(tex, n, 0.0); -} -)"); + shaders[1]->set_code(cubemap_shader); shaders[2].instantiate(); - shaders[2]->set_code(R"( -// TextureLayeredEditor preview shader (cubemap array). - -shader_type canvas_item; - -uniform samplerCubeArray tex; -uniform vec3 normal; -uniform mat3 rot; -uniform float layer; - -void fragment() { - vec3 n = rot * normalize(vec3(normal.xy * (UV * 2.0 - 1.0), normal.z)); - COLOR = textureLod(tex, vec4(n, layer), 0.0); -} -)"); + shaders[2]->set_code(cubemap_array_shader); for (int i = 0; i < 3; i++) { materials[i].instantiate(); @@ -192,25 +268,20 @@ void TextureLayeredEditor::edit(Ref<TextureLayered> p_texture) { } texture->connect_changed(callable_mp(this, &TextureLayeredEditor::_texture_changed)); - queue_redraw(); texture_rect->set_material(materials[texture->get_layered_type()]); + setting = true; - if (texture->get_layered_type() == TextureLayered::LAYERED_TYPE_2D_ARRAY) { - layer->set_max(texture->get_layers() - 1); - layer->set_value(0); - layer->show(); - } else if (texture->get_layered_type() == TextureLayered::LAYERED_TYPE_CUBEMAP_ARRAY) { - layer->set_max(texture->get_layers() / 6 - 1); - layer->set_value(0); - layer->show(); - } else { - layer->hide(); - } + layer->set_value(0); + layer->show(); + _update_gui(); + setting = false; + x_rot = 0; y_rot = 0; - _update_material(); - setting = false; - _texture_rect_update_area(); + + _update_material(true); + queue_redraw(); + } else { hide(); } @@ -218,42 +289,48 @@ void TextureLayeredEditor::edit(Ref<TextureLayered> p_texture) { TextureLayeredEditor::TextureLayeredEditor() { set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED); - set_custom_minimum_size(Size2(1, 150)); + set_custom_minimum_size(Size2(0, 256.0) * EDSCALE); texture_rect = memnew(Control); texture_rect->set_mouse_filter(MOUSE_FILTER_IGNORE); - add_child(texture_rect); texture_rect->connect(SceneStringName(draw), callable_mp(this, &TextureLayeredEditor::_texture_rect_draw)); + add_child(texture_rect); + layer = memnew(SpinBox); layer->set_step(1); layer->set_max(100); - layer->set_h_grow_direction(GROW_DIRECTION_BEGIN); + layer->set_modulate(Color(1, 1, 1, 0.8)); - add_child(layer); + layer->set_h_grow_direction(GROW_DIRECTION_BEGIN); layer->set_anchor(SIDE_RIGHT, 1); layer->set_anchor(SIDE_LEFT, 1); layer->connect(SceneStringName(value_changed), callable_mp(this, &TextureLayeredEditor::_layer_changed)); + add_child(layer); + info = memnew(Label); + info->add_theme_color_override(SceneStringName(font_color), Color(1, 1, 1)); + info->add_theme_color_override("font_shadow_color", Color(0, 0, 0)); + info->add_theme_font_size_override(SceneStringName(font_size), 14 * EDSCALE); + info->add_theme_color_override("font_outline_color", Color(0, 0, 0)); + info->add_theme_constant_override("outline_size", 8 * EDSCALE); + info->set_h_grow_direction(GROW_DIRECTION_BEGIN); info->set_v_grow_direction(GROW_DIRECTION_BEGIN); - info->add_theme_color_override(SceneStringName(font_color), Color(1, 1, 1, 1)); - info->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 0.5)); - info->add_theme_constant_override("shadow_outline_size", 1); - info->add_theme_constant_override("shadow_offset_x", 2); - info->add_theme_constant_override("shadow_offset_y", 2); - add_child(info); + info->set_h_size_flags(Control::SIZE_SHRINK_END); + info->set_v_size_flags(Control::SIZE_SHRINK_END); info->set_anchor(SIDE_RIGHT, 1); info->set_anchor(SIDE_LEFT, 1); info->set_anchor(SIDE_BOTTOM, 1); info->set_anchor(SIDE_TOP, 1); + + add_child(info); } TextureLayeredEditor::~TextureLayeredEditor() { } -// bool EditorInspectorPluginLayeredTexture::can_handle(Object *p_object) { return Object::cast_to<TextureLayered>(p_object) != nullptr; } diff --git a/editor/plugins/texture_layered_editor_plugin.h b/editor/plugins/texture_layered_editor_plugin.h index 83729f922e..900ba94c6d 100644 --- a/editor/plugins/texture_layered_editor_plugin.h +++ b/editor/plugins/texture_layered_editor_plugin.h @@ -54,24 +54,28 @@ class TextureLayeredEditor : public Control { bool setting = false; void _make_shaders(); - void _update_material(); + void _update_material(bool p_texture_changed); void _layer_changed(double) { if (!setting) { - _update_material(); + _update_material(false); } } + void _texture_changed(); void _texture_rect_update_area(); void _texture_rect_draw(); + void _update_gui(); + protected: void _notification(int p_what); virtual void gui_input(const Ref<InputEvent> &p_event) override; public: void edit(Ref<TextureLayered> p_texture); + TextureLayeredEditor(); ~TextureLayeredEditor(); }; diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp index 4d98b24ccc..2426cec521 100644 --- a/editor/plugins/theme_editor_preview.cpp +++ b/editor/plugins/theme_editor_preview.cpp @@ -205,7 +205,7 @@ void ThemeEditorPreview::_notification(int p_what) { } break; case NOTIFICATION_READY: { - List<Ref<Theme>> preview_themes; + Vector<Ref<Theme>> preview_themes; preview_themes.push_back(ThemeDB::get_singleton()->get_default_theme()); ThemeDB::get_singleton()->create_theme_context(preview_root, preview_themes); } break; diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp index 3942baed8a..b806d1e042 100644 --- a/editor/plugins/tiles/tile_atlas_view.cpp +++ b/editor/plugins/tiles/tile_atlas_view.cpp @@ -372,7 +372,7 @@ void TileAtlasView::_draw_base_tiles_shape_grid() { for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) { Vector2i tile_id = tile_set_atlas_source->get_tile_id(i); Vector2 in_tile_base_offset = tile_set_atlas_source->get_tile_data(tile_id, 0)->get_texture_origin(); - if (tile_set_atlas_source->is_position_in_tile_texture_region(tile_id, 0, -tile_shape_size / 2) && tile_set_atlas_source->is_position_in_tile_texture_region(tile_id, 0, tile_shape_size / 2 - Vector2(1, 1))) { + if (tile_set_atlas_source->is_rect_in_tile_texture_region(tile_id, 0, Rect2(Vector2(-tile_shape_size) / 2, tile_shape_size))) { for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(tile_id); frame++) { Color color = grid_color; if (frame > 0) { diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index f985bbc629..af52243c41 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -165,10 +165,14 @@ void GenericTilePolygonEditor::_base_control_draw() { base_control->draw_set_transform_matrix(xform); // Draw fill rect under texture region. - Rect2 texture_rect(-background_region.size / 2, background_region.size); + Rect2 texture_rect(Vector2(), background_region.size); if (tile_data) { texture_rect.position -= tile_data->get_texture_origin(); + if (tile_data->get_transpose()) { + texture_rect.size = Size2(texture_rect.size.y, texture_rect.size.x); + } } + texture_rect.position -= texture_rect.size / 2; // Half-size offset must be applied after transposing. base_control->draw_rect(texture_rect, Color(1, 1, 1, 0.3)); // Draw the background. @@ -180,18 +184,14 @@ void GenericTilePolygonEditor::_base_control_draw() { if (tile_data->get_flip_v()) { region_size.y = -region_size.y; } - base_control->draw_texture_rect_region(background_atlas_source->get_texture(), Rect2(-background_region.size / 2 - tile_data->get_texture_origin(), region_size), background_region, tile_data->get_modulate(), tile_data->get_transpose()); + // Destination rect position must account for transposing, size must not. + base_control->draw_texture_rect_region(background_atlas_source->get_texture(), Rect2(texture_rect.position, region_size), background_region, tile_data->get_modulate(), tile_data->get_transpose()); } // Compute and draw the grid area. Rect2 grid_area = Rect2(-base_tile_size / 2, base_tile_size); - if (tile_data) { - grid_area.expand_to(-background_region.get_size() / 2 - tile_data->get_texture_origin()); - grid_area.expand_to(background_region.get_size() / 2 - tile_data->get_texture_origin()); - } else { - grid_area.expand_to(-background_region.get_size() / 2); - grid_area.expand_to(background_region.get_size() / 2); - } + grid_area.expand_to(texture_rect.position); + grid_area.expand_to(texture_rect.get_end()); base_control->draw_rect(grid_area, Color(1, 1, 1, 0.3), false); // Draw grid. @@ -523,6 +523,21 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) xform.set_origin(base_control->get_size() / 2 + panning); xform.set_scale(Vector2(editor_zoom_widget->get_zoom(), editor_zoom_widget->get_zoom())); + Ref<InputEventPanGesture> pan_gesture = p_event; + if (pan_gesture.is_valid()) { + panning += pan_gesture->get_delta() * 8; + drag_last_pos = Vector2(); + button_center_view->set_disabled(panning.is_zero_approx()); + accept_event(); + } + + Ref<InputEventMagnifyGesture> magnify_gesture = p_event; + if (magnify_gesture.is_valid()) { + editor_zoom_widget->set_zoom(editor_zoom_widget->get_zoom() * magnify_gesture->get_factor()); + _zoom_changed(); + accept_event(); + } + Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { if (drag_type == DRAG_TYPE_DRAG_POINT) { @@ -1385,10 +1400,8 @@ void TileDataTextureOriginEditor::draw_over_tile(CanvasItem *p_canvas_item, Tran TileSetSource *source = *(tile_set->get_source(p_cell.source_id)); TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); - if (atlas_source->is_position_in_tile_texture_region(p_cell.get_atlas_coords(), p_cell.alternative_tile, -tile_set_tile_size / 2) && atlas_source->is_position_in_tile_texture_region(p_cell.get_atlas_coords(), p_cell.alternative_tile, tile_set_tile_size / 2 - Vector2(1, 1))) { - Transform2D tile_xform; - tile_xform.set_scale(tile_set_tile_size); - tile_set->draw_tile_shape(p_canvas_item, p_transform * tile_xform, color); + if (atlas_source->is_rect_in_tile_texture_region(p_cell.get_atlas_coords(), p_cell.alternative_tile, Rect2(Vector2(-tile_set_tile_size) / 2, tile_set_tile_size))) { + tile_set->draw_tile_shape(p_canvas_item, p_transform.scaled_local(tile_set_tile_size), color); } if (atlas_source->is_position_in_tile_texture_region(p_cell.get_atlas_coords(), p_cell.alternative_tile, Vector2())) { diff --git a/editor/plugins/tiles/tile_map_layer_editor.cpp b/editor/plugins/tiles/tile_map_layer_editor.cpp index b76e673414..63a54372b5 100644 --- a/editor/plugins/tiles/tile_map_layer_editor.cpp +++ b/editor/plugins/tiles/tile_map_layer_editor.cpp @@ -2368,7 +2368,7 @@ TileMapLayerEditorTilesPlugin::TileMapLayerEditorTilesPlugin() { tiles_bottom_panel->set_name(TTR("Tiles")); missing_source_label = memnew(Label); - missing_source_label->set_text(TTR("This TileMap's TileSet has no source configured. Go to the TileSet bottom panel to add one.")); + missing_source_label->set_text(TTR("This TileMap's TileSet has no Tile Source configured. Go to the TileSet bottom panel to add one.")); missing_source_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); missing_source_label->set_v_size_flags(Control::SIZE_EXPAND_FILL); missing_source_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 7e34a36a6e..224c4e434f 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -2612,7 +2612,6 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { atlas_source_inspector->set_v_size_flags(SIZE_EXPAND_FILL); atlas_source_inspector->set_show_categories(false, true); atlas_source_inspector->set_use_doc_hints(true); - atlas_source_inspector->add_inspector_plugin(memnew(TileSourceInspectorPlugin)); middle_vbox_container->add_child(atlas_source_inspector); // -- Right side -- @@ -2740,9 +2739,8 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { add_child(confirm_auto_create_tiles); // Inspector plugin. - Ref<EditorInspectorPluginTileData> tile_data_inspector_plugin; - tile_data_inspector_plugin.instantiate(); - EditorInspector::add_inspector_plugin(tile_data_inspector_plugin); + EditorInspector::add_inspector_plugin(memnew(EditorInspectorPluginTileData)); + EditorInspector::add_inspector_plugin(memnew(TileSourceInspectorPlugin)); } TileSetAtlasSourceEditor::~TileSetAtlasSourceEditor() { diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp index 263e9cfa3b..7e5336ce06 100644 --- a/editor/plugins/tiles/tile_set_editor.cpp +++ b/editor/plugins/tiles/tile_set_editor.cpp @@ -818,7 +818,7 @@ TileSetEditor::TileSetEditor() { tabs_bar = memnew(TabBar); tabs_bar->set_tab_alignment(TabBar::ALIGNMENT_CENTER); tabs_bar->set_clip_tabs(false); - tabs_bar->add_tab(TTR("Tiles")); + tabs_bar->add_tab(TTR("Tile Sources")); tabs_bar->add_tab(TTR("Patterns")); tabs_bar->connect("tab_changed", callable_mp(this, &TileSetEditor::_tab_changed)); diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp index 22ef779b8d..305407efdb 100644 --- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp @@ -534,7 +534,6 @@ TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() { scenes_collection_source_inspector = memnew(EditorInspector); scenes_collection_source_inspector->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED); scenes_collection_source_inspector->set_use_doc_hints(true); - scenes_collection_source_inspector->add_inspector_plugin(memnew(TileSourceInspectorPlugin)); middle_vbox_container->add_child(scenes_collection_source_inspector); // Tile inspector. @@ -581,6 +580,8 @@ TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() { scene_tile_delete_button->set_disabled(true); scene_tile_delete_button->connect(SceneStringName(pressed), callable_mp(this, &TileSetScenesCollectionSourceEditor::_source_delete_pressed)); scenes_bottom_actions->add_child(scene_tile_delete_button); + + EditorInspector::add_inspector_plugin(memnew(TileSourceInspectorPlugin)); } TileSetScenesCollectionSourceEditor::~TileSetScenesCollectionSourceEditor() { diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 351adc569c..0c541b6046 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -43,6 +43,7 @@ #include "editor/filesystem_dock.h" #include "editor/inspector_dock.h" #include "editor/plugins/curve_editor_plugin.h" +#include "editor/plugins/material_editor_plugin.h" #include "editor/plugins/shader_editor_plugin.h" #include "editor/themes/editor_scale.h" #include "scene/animation/tween.h" @@ -50,12 +51,14 @@ #include "scene/gui/check_box.h" #include "scene/gui/code_edit.h" #include "scene/gui/color_picker.h" +#include "scene/gui/flow_container.h" #include "scene/gui/graph_edit.h" #include "scene/gui/menu_button.h" #include "scene/gui/option_button.h" #include "scene/gui/popup.h" #include "scene/gui/rich_text_label.h" #include "scene/gui/separator.h" +#include "scene/gui/split_container.h" #include "scene/gui/tree.h" #include "scene/gui/view_panner.h" #include "scene/main/window.h" @@ -115,8 +118,8 @@ void VSGraphNode::_draw_port(int p_slot_index, Point2i p_pos, bool p_left, const icon_offset = -port_icon->get_size() * 0.5; // Draw "shadow"/outline in the connection rim color. - draw_texture_rect(port_icon, Rect2(p_pos + icon_offset - Size2(2, 2), port_icon->get_size() + Size2(4, 4)), false, p_rim_color); - draw_texture(port_icon, p_pos + icon_offset, p_color); + draw_texture_rect(port_icon, Rect2(p_pos + (icon_offset - Size2(2, 2)) * EDSCALE, (port_icon->get_size() + Size2(4, 4)) * EDSCALE), false, p_rim_color); + draw_texture_rect(port_icon, Rect2(p_pos + icon_offset * EDSCALE, port_icon->get_size() * EDSCALE), false, p_color); } void VSGraphNode::draw_port(int p_slot_index, Point2i p_pos, bool p_left, const Color &p_color) { @@ -154,7 +157,6 @@ VSRerouteNode::VSRerouteNode() { title_lbl->hide(); const Size2 size = Size2(32, 32) * EDSCALE; - print_line("VSRerouteNode size: " + size); Control *slot_area = memnew(Control); slot_area->set_custom_minimum_size(size); @@ -256,7 +258,7 @@ void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p vbox->add_child(offset); VisualShaderNodePortPreview *port_preview = memnew(VisualShaderNodePortPreview); - port_preview->setup(visual_shader, visual_shader->get_shader_type(), p_node_id, p_port_id, p_is_valid); + port_preview->setup(visual_shader, editor->preview_material, visual_shader->get_shader_type(), p_node_id, p_port_id, p_is_valid); port_preview->set_h_size_flags(Control::SIZE_SHRINK_CENTER); vbox->add_child(port_preview); link.preview_visible = true; @@ -1096,14 +1098,14 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool default_value = vsnode->get_input_port_default_value(j); } - Button *button = memnew(Button); - hb->add_child(button); - register_default_input_button(p_id, j, button); - button->connect(SceneStringName(pressed), callable_mp(editor, &VisualShaderEditor::_edit_port_default_input).bind(button, p_id, j)); + Button *default_input_btn = memnew(Button); + hb->add_child(default_input_btn); + register_default_input_button(p_id, j, default_input_btn); + default_input_btn->connect(SceneStringName(pressed), callable_mp(editor, &VisualShaderEditor::_edit_port_default_input).bind(default_input_btn, p_id, j)); if (default_value.get_type() != Variant::NIL) { // only a label set_input_port_default_value(p_type, p_id, j, default_value); } else { - button->hide(); + default_input_btn->hide(); } if (j == 0 && custom_editor) { @@ -1144,7 +1146,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool Label *label = memnew(Label); label->set_auto_translate_mode(Node::AUTO_TRANSLATE_MODE_DISABLED); // TODO: Implement proper translation switch. label->set_text(name_left); - label->add_theme_style_override(CoreStringName(normal), editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor"))); //more compact + label->add_theme_style_override(CoreStringName(normal), editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor"))); hb->add_child(label); if (vsnode->is_input_port_default(j, mode) && !port_left_used) { @@ -1509,23 +1511,25 @@ Vector2 VisualShaderEditor::selection_center; List<VisualShaderEditor::CopyItem> VisualShaderEditor::copy_items_buffer; List<VisualShader::Connection> VisualShaderEditor::copy_connections_buffer; -void VisualShaderEditor::edit(VisualShader *p_visual_shader) { +void VisualShaderEditor::edit_shader(const Ref<Shader> &p_shader) { bool changed = false; - if (p_visual_shader) { + VisualShader *visual_shader_ptr = Object::cast_to<VisualShader>(p_shader.ptr()); + if (visual_shader_ptr) { if (visual_shader.is_null()) { changed = true; } else { - if (visual_shader.ptr() != p_visual_shader) { + if (visual_shader.ptr() != visual_shader_ptr) { changed = true; } } - visual_shader = Ref<VisualShader>(p_visual_shader); + visual_shader = p_shader; graph_plugin->register_shader(visual_shader.ptr()); visual_shader->connect_changed(callable_mp(this, &VisualShaderEditor::_update_preview)); visual_shader->set_graph_offset(graph->get_scroll_offset() / EDSCALE); _set_mode(visual_shader->get_mode()); + preview_material->set_shader(visual_shader); _update_nodes(); } else { if (visual_shader.is_valid()) { @@ -1546,6 +1550,19 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) { } } +void VisualShaderEditor::apply_shaders() { + // Stub. TODO: Implement apply_shaders in visual shaders for parity with text shaders. +} + +bool VisualShaderEditor::is_unsaved() const { + // Stub. TODO: Implement is_unsaved in visual shaders for parity with text shaders. + return false; +} + +void VisualShaderEditor::save_external_data(const String &p_str) { + ResourceSaver::save(visual_shader, visual_shader->get_path()); +} + void VisualShaderEditor::validate_script() { if (visual_shader.is_valid()) { _update_nodes(); @@ -1573,7 +1590,7 @@ void VisualShaderEditor::clear_custom_types() { } void VisualShaderEditor::add_custom_type(const String &p_name, const String &p_type, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, bool p_highend) { - ERR_FAIL_COND(!p_name.is_valid_identifier()); + ERR_FAIL_COND(!p_name.is_valid_ascii_identifier()); ERR_FAIL_COND(p_type.is_empty() && !p_script.is_valid()); for (int i = 0; i < add_options.size(); i++) { @@ -1936,6 +1953,96 @@ bool VisualShaderEditor::_is_available(int p_mode) { return (p_mode == -1 || (p_mode & current_mode) != 0); } +bool VisualShaderEditor::_update_preview_parameter_tree() { + bool found = false; + bool use_filter = !param_filter_name.is_empty(); + + parameters->clear(); + TreeItem *root = parameters->create_item(); + + for (const KeyValue<String, PropertyInfo> &prop : parameter_props) { + String param_name = prop.value.name; + if (use_filter && !param_name.containsn(param_filter_name)) { + continue; + } + + TreeItem *item = parameters->create_item(root); + item->set_text(0, param_name); + item->set_meta("id", param_name); + + if (param_name == selected_param_id) { + parameters->set_selected(item); + found = true; + } + + if (prop.value.type == Variant::OBJECT) { + item->set_icon(0, get_editor_theme_icon(SNAME("ImageTexture"))); + } else { + item->set_icon(0, get_editor_theme_icon(Variant::get_type_name(prop.value.type))); + } + } + + return found; +} + +void VisualShaderEditor::_clear_preview_param() { + selected_param_id = ""; + current_prop = nullptr; + + if (param_vbox2->get_child_count() > 0) { + param_vbox2->remove_child(param_vbox2->get_child(0)); + } + + param_vbox->hide(); +} + +void VisualShaderEditor::_update_preview_parameter_list() { + material_editor->edit(preview_material.ptr(), env); + + List<PropertyInfo> properties; + RenderingServer::get_singleton()->get_shader_parameter_list(visual_shader->get_rid(), &properties); + + HashSet<String> params_to_remove; + for (const KeyValue<String, PropertyInfo> &E : parameter_props) { + params_to_remove.insert(E.key); + } + parameter_props.clear(); + + for (const PropertyInfo &prop : properties) { + String param_name = prop.name; + + if (visual_shader->_has_preview_shader_parameter(param_name)) { + preview_material->set_shader_parameter(param_name, visual_shader->_get_preview_shader_parameter(param_name)); + } else { + preview_material->set_shader_parameter(param_name, RenderingServer::get_singleton()->shader_get_parameter_default(visual_shader->get_rid(), param_name)); + } + + parameter_props.insert(param_name, prop); + params_to_remove.erase(param_name); + + if (param_name == selected_param_id) { + current_prop->update_property(); + current_prop->update_editor_property_status(); + current_prop->update_cache(); + } + } + + _update_preview_parameter_tree(); + + // Removes invalid parameters. + for (const String ¶m_name : params_to_remove) { + preview_material->set_shader_parameter(param_name, Variant()); + + if (visual_shader->_has_preview_shader_parameter(param_name)) { + visual_shader->_set_preview_shader_parameter(param_name, Variant()); + } + + if (param_name == selected_param_id) { + _clear_preview_param(); + } + } +} + void VisualShaderEditor::_update_nodes() { clear_custom_types(); Dictionary added; @@ -3560,6 +3667,7 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, cons bool is_curve = (Object::cast_to<VisualShaderNodeCurveTexture>(vsnode.ptr()) != nullptr); bool is_curve_xyz = (Object::cast_to<VisualShaderNodeCurveXYZTexture>(vsnode.ptr()) != nullptr); bool is_parameter = (Object::cast_to<VisualShaderNodeParameter>(vsnode.ptr()) != nullptr); + bool is_mesh_emitter = (Object::cast_to<VisualShaderNodeParticleMeshEmitter>(vsnode.ptr()) != nullptr); Point2 position = graph->get_scroll_offset(); @@ -3772,6 +3880,12 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, cons if (is_texture2d_array) { undo_redo->force_fixed_history(); undo_redo->add_do_method(vsnode.ptr(), "set_texture_array", ResourceLoader::load(p_resource_path)); + return; + } + + if (is_mesh_emitter) { + undo_redo->add_do_method(vsnode.ptr(), "set_mesh", ResourceLoader::load(p_resource_path)); + return; } } } @@ -4859,6 +4973,74 @@ void VisualShaderEditor::_sbox_input(const Ref<InputEvent> &p_ie) { } } +void VisualShaderEditor::_param_filter_changed(const String &p_text) { + param_filter_name = p_text; + + if (!_update_preview_parameter_tree()) { + _clear_preview_param(); + } +} + +void VisualShaderEditor::_param_property_changed(const String &p_property, const Variant &p_value, const String &p_field, bool p_changing) { + if (p_changing) { + return; + } + String raw_prop_name = p_property.trim_prefix("shader_parameter/"); + + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + + undo_redo->create_action(vformat(TTR("Edit Preview Parameter: %s"), p_property)); + undo_redo->add_do_method(visual_shader.ptr(), "_set_preview_shader_parameter", raw_prop_name, p_value); + undo_redo->add_undo_method(visual_shader.ptr(), "_set_preview_shader_parameter", raw_prop_name, preview_material->get(p_property)); + undo_redo->add_do_method(this, "_update_current_param"); + undo_redo->add_undo_method(this, "_update_current_param"); + undo_redo->commit_action(); +} + +void VisualShaderEditor::_update_current_param() { + if (current_prop != nullptr) { + String name = current_prop->get_meta("id"); + preview_material->set("shader_parameter/" + name, visual_shader->_get_preview_shader_parameter(name)); + + current_prop->update_property(); + current_prop->update_editor_property_status(); + current_prop->update_cache(); + } +} + +void VisualShaderEditor::_param_selected() { + _clear_preview_param(); + + TreeItem *item = parameters->get_selected(); + selected_param_id = item->get_meta("id"); + + PropertyInfo pi = parameter_props.get(selected_param_id); + EditorProperty *prop = EditorInspector::instantiate_property_editor(preview_material.ptr(), pi.type, pi.name, pi.hint, pi.hint_string, pi.usage); + if (!prop) { + return; + } + prop->connect("property_changed", callable_mp(this, &VisualShaderEditor::_param_property_changed)); + prop->set_h_size_flags(SIZE_EXPAND_FILL); + prop->set_object_and_property(preview_material.ptr(), "shader_parameter/" + pi.name); + + prop->set_label(TTR("Value:")); + prop->update_property(); + prop->update_editor_property_status(); + prop->update_cache(); + + current_prop = prop; + current_prop->set_meta("id", selected_param_id); + + param_vbox2->add_child(prop); + param_vbox->show(); +} + +void VisualShaderEditor::_param_unselected() { + parameters->deselect_all(); + + _clear_preview_param(); +} + void VisualShaderEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_POSTINITIALIZE: { @@ -4902,9 +5084,11 @@ void VisualShaderEditor::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { highend_label->set_modulate(get_theme_color(SNAME("highend_color"), EditorStringName(Editor))); + param_filter->set_right_icon(Control::get_editor_theme_icon(SNAME("Search"))); node_filter->set_right_icon(Control::get_editor_theme_icon(SNAME("Search"))); - preview_shader->set_icon(Control::get_editor_theme_icon(SNAME("Shader"))); + code_preview_button->set_icon(Control::get_editor_theme_icon(SNAME("Shader"))); + shader_preview_button->set_icon(Control::get_editor_theme_icon(SNAME("SubViewport"))); { Color background_color = EDITOR_GET("text_editor/theme/highlighting/background_color"); @@ -4957,7 +5141,7 @@ void VisualShaderEditor::_notification(int p_what) { tools->set_icon(get_editor_theme_icon(SNAME("Tools"))); - if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree()) { + if (is_visible_in_tree()) { _update_graph(); } } break; @@ -5614,7 +5798,7 @@ void VisualShaderEditor::_varying_create() { } void VisualShaderEditor::_varying_name_changed(const String &p_name) { - if (!p_name.is_valid_identifier()) { + if (!p_name.is_valid_ascii_identifier()) { varying_error_label->show(); varying_error_label->set_text(TTR("Invalid name for varying.")); add_varying_dialog->get_ok_button()->set_disabled(true); @@ -5885,6 +6069,11 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE); saved_node_pos_dirty = true; _add_node(cubemap_node_option_idx, {}, arr[i], i); + } else if (type == "Mesh" && visual_shader->get_mode() == Shader::MODE_PARTICLES && + (visual_shader->get_shader_type() == VisualShader::TYPE_START || visual_shader->get_shader_type() == VisualShader::TYPE_START_CUSTOM)) { + saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE); + saved_node_pos_dirty = true; + _add_node(mesh_emitter_option_idx, {}, arr[i], i); } } } @@ -5894,14 +6083,14 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } void VisualShaderEditor::_show_preview_text() { - preview_showed = !preview_showed; - if (preview_showed) { - if (preview_first) { - preview_window->set_size(Size2(400 * EDSCALE, 600 * EDSCALE)); - preview_window->popup_centered(); - preview_first = false; + code_preview_showed = !code_preview_showed; + if (code_preview_showed) { + if (code_preview_first) { + code_preview_window->set_size(Size2(400 * EDSCALE, 600 * EDSCALE)); + code_preview_window->popup_centered(); + code_preview_first = false; } else { - preview_window->popup(); + code_preview_window->popup(); } _preview_size_changed(); @@ -5910,18 +6099,18 @@ void VisualShaderEditor::_show_preview_text() { pending_update_preview = false; } } else { - preview_window->hide(); + code_preview_window->hide(); } } void VisualShaderEditor::_preview_close_requested() { - preview_showed = false; - preview_window->hide(); - preview_shader->set_pressed(false); + code_preview_showed = false; + code_preview_window->hide(); + code_preview_button->set_pressed(false); } void VisualShaderEditor::_preview_size_changed() { - preview_vbox->set_custom_minimum_size(preview_window->get_size()); + code_preview_vbox->set_custom_minimum_size(code_preview_window->get_size()); } static ShaderLanguage::DataType _visual_shader_editor_get_global_shader_uniform_type(const StringName &p_variable) { @@ -5930,7 +6119,7 @@ static ShaderLanguage::DataType _visual_shader_editor_get_global_shader_uniform_ } void VisualShaderEditor::_update_preview() { - if (!preview_showed) { + if (!code_preview_showed) { pending_update_preview = true; return; } @@ -6022,14 +6211,25 @@ void VisualShaderEditor::_get_next_nodes_recursively(VisualShader::Type p_type, void VisualShaderEditor::_visibility_changed() { if (!is_visible()) { - if (preview_window->is_visible()) { - preview_shader->set_pressed(false); - preview_window->hide(); - preview_showed = false; + if (code_preview_window->is_visible()) { + code_preview_button->set_pressed(false); + code_preview_window->hide(); + code_preview_showed = false; } } } +void VisualShaderEditor::_show_shader_preview() { + shader_preview_showed = !shader_preview_showed; + if (shader_preview_showed) { + shader_preview_vbox->show(); + } else { + shader_preview_vbox->hide(); + + _param_unselected(); + } +} + void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_update_nodes", &VisualShaderEditor::_update_nodes); ClassDB::bind_method("_update_graph", &VisualShaderEditor::_update_graph); @@ -6044,6 +6244,7 @@ void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_update_constant", &VisualShaderEditor::_update_constant); ClassDB::bind_method("_update_parameter", &VisualShaderEditor::_update_parameter); ClassDB::bind_method("_update_next_previews", &VisualShaderEditor::_update_next_previews); + ClassDB::bind_method("_update_current_param", &VisualShaderEditor::_update_current_param); } VisualShaderEditor::VisualShaderEditor() { @@ -6052,15 +6253,19 @@ VisualShaderEditor::VisualShaderEditor() { FileSystemDock::get_singleton()->get_script_create_dialog()->connect("script_created", callable_mp(this, &VisualShaderEditor::_script_created)); FileSystemDock::get_singleton()->connect("resource_removed", callable_mp(this, &VisualShaderEditor::_resource_removed)); + HSplitContainer *main_box = memnew(HSplitContainer); + main_box->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); + add_child(main_box); + graph = memnew(GraphEdit); - graph->get_menu_hbox()->set_h_size_flags(SIZE_EXPAND_FILL); graph->set_v_size_flags(SIZE_EXPAND_FILL); graph->set_h_size_flags(SIZE_EXPAND_FILL); + graph->set_custom_minimum_size(Size2(200 * EDSCALE, 0)); graph->set_grid_pattern(GraphEdit::GridPattern::GRID_PATTERN_DOTS); int grid_pattern = EDITOR_GET("editors/visual_editors/grid_pattern"); graph->set_grid_pattern((GraphEdit::GridPattern)grid_pattern); graph->set_show_zoom_label(true); - add_child(graph); + main_box->add_child(graph); SET_DRAG_FORWARDING_GCD(graph, VisualShaderEditor); float graph_minimap_opacity = EDITOR_GET("editors/visual_editors/minimap_opacity"); graph->set_minimap_opacity(graph_minimap_opacity); @@ -6148,9 +6353,30 @@ VisualShaderEditor::VisualShaderEditor() { graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShaderNode::PORT_TYPE_TRANSFORM); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SAMPLER, VisualShaderNode::PORT_TYPE_SAMPLER); + PanelContainer *toolbar_panel = static_cast<PanelContainer *>(graph->get_menu_hbox()->get_parent()); + toolbar_panel->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE, PRESET_MODE_MINSIZE, 10); + toolbar_panel->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); + + HFlowContainer *toolbar = memnew(HFlowContainer); + { + LocalVector<Node *> nodes; + for (int i = 0; i < graph->get_menu_hbox()->get_child_count(); i++) { + Node *child = graph->get_menu_hbox()->get_child(i); + nodes.push_back(child); + } + + for (Node *node : nodes) { + graph->get_menu_hbox()->remove_child(node); + toolbar->add_child(node); + } + + graph->get_menu_hbox()->hide(); + toolbar_panel->add_child(toolbar); + } + VSeparator *vs = memnew(VSeparator); - graph->get_menu_hbox()->add_child(vs); - graph->get_menu_hbox()->move_child(vs, 0); + toolbar->add_child(vs); + toolbar->move_child(vs, 0); custom_mode_box = memnew(CheckBox); custom_mode_box->set_text(TTR("Custom")); @@ -6184,22 +6410,22 @@ VisualShaderEditor::VisualShaderEditor() { edit_type = edit_type_standard; - graph->get_menu_hbox()->add_child(custom_mode_box); - graph->get_menu_hbox()->move_child(custom_mode_box, 0); - graph->get_menu_hbox()->add_child(edit_type_standard); - graph->get_menu_hbox()->move_child(edit_type_standard, 0); - graph->get_menu_hbox()->add_child(edit_type_particles); - graph->get_menu_hbox()->move_child(edit_type_particles, 0); - graph->get_menu_hbox()->add_child(edit_type_sky); - graph->get_menu_hbox()->move_child(edit_type_sky, 0); - graph->get_menu_hbox()->add_child(edit_type_fog); - graph->get_menu_hbox()->move_child(edit_type_fog, 0); + toolbar->add_child(custom_mode_box); + toolbar->move_child(custom_mode_box, 0); + toolbar->add_child(edit_type_standard); + toolbar->move_child(edit_type_standard, 0); + toolbar->add_child(edit_type_particles); + toolbar->move_child(edit_type_particles, 0); + toolbar->add_child(edit_type_sky); + toolbar->move_child(edit_type_sky, 0); + toolbar->add_child(edit_type_fog); + toolbar->move_child(edit_type_fog, 0); add_node = memnew(Button); add_node->set_flat(true); add_node->set_text(TTR("Add Node...")); - graph->get_menu_hbox()->add_child(add_node); - graph->get_menu_hbox()->move_child(add_node, 0); + toolbar->add_child(add_node); + toolbar->move_child(add_node, 0); add_node->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_show_members_dialog).bind(false, VisualShaderNode::PORT_TYPE_MAX, VisualShaderNode::PORT_TYPE_MAX)); graph->connect("graph_elements_linked_to_frame_request", callable_mp(this, &VisualShaderEditor::_nodes_linked_to_frame_request)); @@ -6208,46 +6434,54 @@ VisualShaderEditor::VisualShaderEditor() { varying_button = memnew(MenuButton); varying_button->set_text(TTR("Manage Varyings")); varying_button->set_switch_on_hover(true); - graph->get_menu_hbox()->add_child(varying_button); + toolbar->add_child(varying_button); PopupMenu *varying_menu = varying_button->get_popup(); varying_menu->add_item(TTR("Add Varying"), int(VaryingMenuOptions::ADD)); varying_menu->add_item(TTR("Remove Varying"), int(VaryingMenuOptions::REMOVE)); varying_menu->connect(SceneStringName(id_pressed), callable_mp(this, &VisualShaderEditor::_varying_menu_id_pressed)); - preview_shader = memnew(Button); - preview_shader->set_theme_type_variation("FlatButton"); - preview_shader->set_toggle_mode(true); - preview_shader->set_tooltip_text(TTR("Show generated shader code.")); - graph->get_menu_hbox()->add_child(preview_shader); - preview_shader->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_show_preview_text)); + code_preview_button = memnew(Button); + code_preview_button->set_theme_type_variation("FlatButton"); + code_preview_button->set_toggle_mode(true); + code_preview_button->set_tooltip_text(TTR("Show generated shader code.")); + toolbar->add_child(code_preview_button); + code_preview_button->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_show_preview_text)); + + shader_preview_button = memnew(Button); + shader_preview_button->set_theme_type_variation("FlatButton"); + shader_preview_button->set_toggle_mode(true); + shader_preview_button->set_tooltip_text(TTR("Toggle shader preview.")); + shader_preview_button->set_pressed(true); + toolbar->add_child(shader_preview_button); + shader_preview_button->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_show_shader_preview)); /////////////////////////////////////// - // PREVIEW WINDOW + // CODE PREVIEW /////////////////////////////////////// - preview_window = memnew(Window); - preview_window->set_title(TTR("Generated Shader Code")); - preview_window->set_visible(preview_showed); - preview_window->set_exclusive(true); - preview_window->connect("close_requested", callable_mp(this, &VisualShaderEditor::_preview_close_requested)); - preview_window->connect("size_changed", callable_mp(this, &VisualShaderEditor::_preview_size_changed)); - add_child(preview_window); + code_preview_window = memnew(Window); + code_preview_window->set_title(TTR("Generated Shader Code")); + code_preview_window->set_visible(code_preview_showed); + code_preview_window->set_exclusive(true); + code_preview_window->connect("close_requested", callable_mp(this, &VisualShaderEditor::_preview_close_requested)); + code_preview_window->connect("size_changed", callable_mp(this, &VisualShaderEditor::_preview_size_changed)); + add_child(code_preview_window); - preview_vbox = memnew(VBoxContainer); - preview_window->add_child(preview_vbox); - preview_vbox->add_theme_constant_override("separation", 0); + code_preview_vbox = memnew(VBoxContainer); + code_preview_window->add_child(code_preview_vbox); + code_preview_vbox->add_theme_constant_override("separation", 0); preview_text = memnew(CodeEdit); syntax_highlighter.instantiate(); - preview_vbox->add_child(preview_text); + code_preview_vbox->add_child(preview_text); preview_text->set_v_size_flags(Control::SIZE_EXPAND_FILL); preview_text->set_syntax_highlighter(syntax_highlighter); preview_text->set_draw_line_numbers(true); preview_text->set_editable(false); error_panel = memnew(PanelContainer); - preview_vbox->add_child(error_panel); + code_preview_vbox->add_child(error_panel); error_panel->set_visible(false); error_label = memnew(Label); @@ -6279,6 +6513,70 @@ VisualShaderEditor::VisualShaderEditor() { connection_popup_menu->connect(SceneStringName(id_pressed), callable_mp(this, &VisualShaderEditor::_connection_menu_id_pressed)); /////////////////////////////////////// + // SHADER PREVIEW + /////////////////////////////////////// + + shader_preview_vbox = memnew(VBoxContainer); + shader_preview_vbox->set_custom_minimum_size(Size2(200 * EDSCALE, 0)); + main_box->add_child(shader_preview_vbox); + + VSplitContainer *preview_split = memnew(VSplitContainer); + preview_split->set_v_size_flags(SIZE_EXPAND_FILL); + shader_preview_vbox->add_child(preview_split); + + // Initialize material editor. + { + env.instantiate(); + Ref<Sky> sky = memnew(Sky()); + env->set_sky(sky); + env->set_background(Environment::BG_COLOR); + env->set_ambient_source(Environment::AMBIENT_SOURCE_SKY); + env->set_reflection_source(Environment::REFLECTION_SOURCE_SKY); + + preview_material.instantiate(); + preview_material->connect(CoreStringName(property_list_changed), callable_mp(this, &VisualShaderEditor::_update_preview_parameter_list)); + + material_editor = memnew(MaterialEditor); + preview_split->add_child(material_editor); + } + + VBoxContainer *params_vbox = memnew(VBoxContainer); + preview_split->add_child(params_vbox); + + param_filter = memnew(LineEdit); + param_filter->connect(SceneStringName(text_changed), callable_mp(this, &VisualShaderEditor::_param_filter_changed)); + param_filter->set_h_size_flags(SIZE_EXPAND_FILL); + param_filter->set_placeholder(TTR("Filter Parameters")); + params_vbox->add_child(param_filter); + + ScrollContainer *sc = memnew(ScrollContainer); + sc->set_v_size_flags(SIZE_EXPAND_FILL); + params_vbox->add_child(sc); + + parameters = memnew(Tree); + parameters->set_hide_root(true); + parameters->set_allow_reselect(true); + parameters->set_hide_folding(false); + parameters->set_h_size_flags(SIZE_EXPAND_FILL); + parameters->set_v_size_flags(SIZE_EXPAND_FILL); + parameters->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_param_selected)); + parameters->connect("nothing_selected", callable_mp(this, &VisualShaderEditor::_param_unselected)); + sc->add_child(parameters); + + param_vbox = memnew(VBoxContainer); + param_vbox->set_v_size_flags(SIZE_EXPAND_FILL); + param_vbox->hide(); + params_vbox->add_child(param_vbox); + + ScrollContainer *sc2 = memnew(ScrollContainer); + sc2->set_v_size_flags(SIZE_EXPAND_FILL); + param_vbox->add_child(sc2); + + param_vbox2 = memnew(VBoxContainer); + param_vbox2->set_h_size_flags(SIZE_EXPAND_FILL); + sc2->add_child(param_vbox2); + + /////////////////////////////////////// // SHADER NODES TREE /////////////////////////////////////// @@ -6521,6 +6819,7 @@ VisualShaderEditor::VisualShaderEditor() { // NODE3D-FOR-ALL + add_options.push_back(AddOption("ClipSpaceFar", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "clip_space_far", "CLIP_SPACE_FAR"), { "clip_space_far" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Exposure", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "exposure", "EXPOSURE"), { "exposure" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("InvProjectionMatrix", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "inv_projection_matrix", "INV_PROJECTION_MATRIX"), { "inv_projection_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("InvViewMatrix", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "inv_view_matrix", "INV_VIEW_MATRIX"), { "inv_view_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL)); @@ -6579,14 +6878,20 @@ VisualShaderEditor::VisualShaderEditor() { // NODE3D INPUTS add_options.push_back(AddOption("Binormal", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal", "BINORMAL"), { "binormal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("CameraDirectionWorld", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_direction_world", "CAMERA_DIRECTION_WORLD"), { "camera_direction_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("CameraPositionWorld", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_position_world", "CAMERA_POSITION_WORLD"), { "camera_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("CameraVisibleLayers", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_visible_layers", "CAMERA_VISIBLE_LAYERS"), { "camera_visible_layers" }, VisualShaderNode::PORT_TYPE_SCALAR_UINT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Color", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color", "COLOR"), { "color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Custom0", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom0", "CUSTOM0"), { "custom0" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Custom1", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom1", "CUSTOM1"), { "custom1" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Custom2", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom2", "CUSTOM2"), { "custom2" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Custom3", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom3", "CUSTOM3"), { "custom3" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("InstanceId", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_id", "INSTANCE_ID"), { "instance_id" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("EyeOffset", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "eye_offset", "EYE_OFFSET"), { "eye_offset" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("InstanceCustom", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom", "INSTANCE_CUSTOM"), { "instance_custom" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("InstanceId", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_id", "INSTANCE_ID"), { "instance_id" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("ModelViewMatrix", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "modelview_matrix", "MODELVIEW_MATRIX"), { "modelview_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("NodePositionView", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_view", "NODE_POSITION_VIEW"), { "node_position_view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("NodePositionWorld", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("PointSize", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size", "POINT_SIZE"), { "point_size" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Tangent", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "tangent", "TANGENT"), { "tangent" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Vertex", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex", "VERTEX"), { "vertex" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); @@ -6594,17 +6899,17 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("ViewIndex", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_index", "VIEW_INDEX"), { "view_index" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("ViewMonoLeft", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_mono_left", "VIEW_MONO_LEFT"), { "view_mono_left" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("ViewRight", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_right", "VIEW_RIGHT"), { "view_right" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("EyeOffset", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "eye_offset", "EYE_OFFSET"), { "eye_offset" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("NodePositionWorld", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("CameraPositionWorld", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_position_world", "CAMERA_POSITION_WORLD"), { "camera_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("CameraDirectionWorld", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_direction_world", "CAMERA_DIRECTION_WORLD"), { "camera_direction_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("CameraVisibleLayers", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_visible_layers", "CAMERA_VISIBLE_LAYERS"), { "camera_visible_layers" }, VisualShaderNode::PORT_TYPE_SCALAR_UINT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("NodePositionView", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_view", "NODE_POSITION_VIEW"), { "node_position_view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Binormal", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal", "BINORMAL"), { "binormal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("CameraDirectionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_direction_world", "CAMERA_DIRECTION_WORLD"), { "camera_direction_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("CameraPositionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_position_world", "CAMERA_POSITION_WORLD"), { "camera_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("CameraVisibleLayers", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_visible_layers", "CAMERA_VISIBLE_LAYERS"), { "camera_visible_layers" }, VisualShaderNode::PORT_TYPE_SCALAR_UINT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Color", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color", "COLOR"), { "color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("EyeOffset", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "eye_offset", "EYE_OFFSET"), { "eye_offset" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("FragCoord", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord", "FRAGCOORD"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("FrontFacing", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "front_facing", "FRONT_FACING"), { "front_facing" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("NodePositionView", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_view", "NODE_POSITION_VIEW"), { "node_position_view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("NodePositionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("PointCoord", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "point_coord", "POINT_COORD"), { "point_coord" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("ScreenUV", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Tangent", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "tangent", "TANGENT"), { "tangent" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); @@ -6613,12 +6918,6 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("ViewIndex", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_index", "VIEW_INDEX"), { "view_index" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("ViewMonoLeft", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_mono_left", "VIEW_MONO_LEFT"), { "view_mono_left" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("ViewRight", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_right", "VIEW_RIGHT"), { "view_right" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("EyeOffset", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "eye_offset", "EYE_OFFSET"), { "eye_offset" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("NodePositionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("CameraPositionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_position_world", "CAMERA_POSITION_WORLD"), { "camera_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("CameraDirectionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_direction_world", "CAMERA_DIRECTION_WORLD"), { "camera_direction_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("CameraVisibleLayers", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_visible_layers", "CAMERA_VISIBLE_LAYERS"), { "camera_visible_layers" }, VisualShaderNode::PORT_TYPE_SCALAR_UINT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("NodePositionView", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_view", "NODE_POSITION_VIEW"), { "node_position_view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Albedo", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "albedo", "ALBEDO"), { "albedo" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Attenuation", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "attenuation", "ATTENUATION"), { "attenuation" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); @@ -6661,10 +6960,10 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("FragCoord", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord", "FRAGCOORD"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("Light", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light", "LIGHT"), { "light" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("LightColor", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color", "LIGHT_COLOR"), { "light_color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("LightPosition", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_position", "LIGHT_POSITION"), { "light_position" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("LightDirection", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_direction", "LIGHT_DIRECTION"), { "light_direction" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("LightIsDirectional", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_is_directional", "LIGHT_IS_DIRECTIONAL"), { "light_is_directional" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("LightEnergy", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_energy", "LIGHT_ENERGY"), { "light_energy" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("LightIsDirectional", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_is_directional", "LIGHT_IS_DIRECTIONAL"), { "light_is_directional" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("LightPosition", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_position", "LIGHT_POSITION"), { "light_position" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("LightVertex", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "light_vertex", "LIGHT_VERTEX"), { "light_vertex" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("Normal", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "normal", "NORMAL"), { "normal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("PointCoord", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord", "POINT_COORD"), { "point_coord" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); @@ -6679,6 +6978,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("AtHalfResPass", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_half_res_pass", "AT_HALF_RES_PASS"), { "at_half_res_pass" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY)); add_options.push_back(AddOption("AtQuarterResPass", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_quarter_res_pass", "AT_QUARTER_RES_PASS"), { "at_quarter_res_pass" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY)); add_options.push_back(AddOption("EyeDir", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "eyedir", "EYEDIR"), { "eyedir" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY)); + add_options.push_back(AddOption("FragCoord", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "fragcoord", "FRAGCOORD"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_SKY, Shader::MODE_SKY)); add_options.push_back(AddOption("HalfResColor", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "half_res_color", "HALF_RES_COLOR"), { "half_res_color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_SKY, Shader::MODE_SKY)); add_options.push_back(AddOption("Light0Color", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_color", "LIGHT0_COLOR"), { "light0_color" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY)); add_options.push_back(AddOption("Light0Direction", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_direction", "LIGHT0_DIRECTION"), { "light0_direction" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY)); @@ -6700,19 +7000,17 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("QuarterResColor", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "quarter_res_color", "QUARTER_RES_COLOR"), { "quarter_res_color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_SKY, Shader::MODE_SKY)); add_options.push_back(AddOption("Radiance", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "radiance", "RADIANCE"), { "radiance" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_SKY, Shader::MODE_SKY)); add_options.push_back(AddOption("ScreenUV", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_SKY, Shader::MODE_SKY)); - add_options.push_back(AddOption("FragCoord", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "fragcoord", "FRAGCOORD"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_SKY, Shader::MODE_SKY)); - add_options.push_back(AddOption("SkyCoords", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "sky_coords", "SKY_COORDS"), { "sky_coords" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_SKY, Shader::MODE_SKY)); add_options.push_back(AddOption("Time", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "time", "TIME"), { "time" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY)); // FOG INPUTS - add_options.push_back(AddOption("WorldPosition", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "world_position", "WORLD_POSITION"), { "world_position" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG)); add_options.push_back(AddOption("ObjectPosition", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "object_position", "OBJECT_POSITION"), { "object_position" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG)); - add_options.push_back(AddOption("UVW", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "uvw", "UVW"), { "uvw" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG)); - add_options.push_back(AddOption("Size", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "size", "SIZE"), { "size" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG)); add_options.push_back(AddOption("SDF", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "sdf", "SDF"), { "sdf" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FOG, Shader::MODE_FOG)); + add_options.push_back(AddOption("Size", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "size", "SIZE"), { "size" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG)); add_options.push_back(AddOption("Time", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "time", "TIME"), { "time" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FOG, Shader::MODE_FOG)); + add_options.push_back(AddOption("UVW", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "uvw", "UVW"), { "uvw" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG)); + add_options.push_back(AddOption("WorldPosition", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "world_position", "WORLD_POSITION"), { "world_position" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG)); // PARTICLES INPUTS @@ -6727,7 +7025,10 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("MultiplyByAxisAngle (*)", "Particles/Transform", "VisualShaderNodeParticleMultiplyByAxisAngle", TTR("A node for help to multiply a position input vector by rotation using specific axis. Intended to work with emitters."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES)); add_options.push_back(AddOption("BoxEmitter", "Particles/Emitters", "VisualShaderNodeParticleBoxEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + + mesh_emitter_option_idx = add_options.size(); add_options.push_back(AddOption("MeshEmitter", "Particles/Emitters", "VisualShaderNodeParticleMeshEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("RingEmitter", "Particles/Emitters", "VisualShaderNodeParticleRingEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); add_options.push_back(AddOption("SphereEmitter", "Particles/Emitters", "VisualShaderNodeParticleSphereEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); @@ -7562,7 +7863,7 @@ void EditorPropertyVisualShaderMode::_option_selected(int p_which) { if (!shader_editor) { return; } - VisualShaderEditor *editor = shader_editor->get_visual_shader_editor(visual_shader); + VisualShaderEditor *editor = Object::cast_to<VisualShaderEditor>(shader_editor->get_shader_editor(visual_shader)); if (!editor) { return; } @@ -7653,9 +7954,6 @@ void EditorPropertyVisualShaderMode::set_option_button_clip(bool p_enable) { options->set_clip_text(p_enable); } -void EditorPropertyVisualShaderMode::_bind_methods() { -} - EditorPropertyVisualShaderMode::EditorPropertyVisualShaderMode() { options = memnew(OptionButton); options->set_clip_text(true); @@ -7696,7 +7994,7 @@ void VisualShaderNodePortPreview::_shader_changed() { preview_shader->set_code(shader_code); for (int i = 0; i < default_textures.size(); i++) { int j = 0; - for (List<Ref<Texture2D>>::ConstIterator itr = default_textures[i].params.begin(); itr != default_textures[i].params.end(); ++itr, ++j) { + for (List<Ref<Texture>>::ConstIterator itr = default_textures[i].params.begin(); itr != default_textures[i].params.end(); ++itr, ++j) { preview_shader->set_default_texture_parameter(default_textures[i].name, *itr, j); } } @@ -7705,36 +8003,21 @@ void VisualShaderNodePortPreview::_shader_changed() { mat.instantiate(); mat->set_shader(preview_shader); - //find if a material is also being edited and copy parameters to this one - - for (int i = EditorNode::get_singleton()->get_editor_selection_history()->get_path_size() - 1; i >= 0; i--) { - Object *object = ObjectDB::get_instance(EditorNode::get_singleton()->get_editor_selection_history()->get_path_object(i)); - ShaderMaterial *src_mat; - if (!object) { - continue; - } - if (object->has_method("get_material_override")) { // trying getting material from MeshInstance - src_mat = Object::cast_to<ShaderMaterial>(object->call("get_material_override")); - } else if (object->has_method("get_material")) { // from CanvasItem/Node2D - src_mat = Object::cast_to<ShaderMaterial>(object->call("get_material")); - } else { - src_mat = Object::cast_to<ShaderMaterial>(object); - } - if (src_mat && src_mat->get_shader().is_valid()) { - List<PropertyInfo> params; - src_mat->get_shader()->get_shader_uniform_list(¶ms); - for (const PropertyInfo &E : params) { - mat->set_shader_parameter(E.name, src_mat->get_shader_parameter(E.name)); - } + if (preview_mat.is_valid() && preview_mat->get_shader().is_valid()) { + List<PropertyInfo> params; + preview_mat->get_shader()->get_shader_uniform_list(¶ms); + for (const PropertyInfo &E : params) { + mat->set_shader_parameter(E.name, preview_mat->get_shader_parameter(E.name)); } } set_material(mat); } -void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, VisualShader::Type p_type, int p_node, int p_port, bool p_is_valid) { +void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, Ref<ShaderMaterial> &p_preview_material, VisualShader::Type p_type, int p_node, int p_port, bool p_is_valid) { shader = p_shader; shader->connect_changed(callable_mp(this, &VisualShaderNodePortPreview::_shader_changed), CONNECT_DEFERRED); + preview_mat = p_preview_material; type = p_type; port = p_port; node = p_node; @@ -7787,9 +8070,6 @@ void VisualShaderNodePortPreview::_notification(int p_what) { } } -void VisualShaderNodePortPreview::_bind_methods() { -} - ////////////////////////////////// String VisualShaderConversionPlugin::converts_to() const { diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index a9826fd617..69b2f30c40 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -34,6 +34,7 @@ #include "editor/editor_properties.h" #include "editor/plugins/editor_plugin.h" #include "editor/plugins/editor_resource_conversion_plugin.h" +#include "editor/plugins/shader/shader_editor.h" #include "scene/gui/graph_edit.h" #include "scene/resources/syntax_highlighter.h" #include "scene/resources/visual_shader.h" @@ -49,6 +50,7 @@ class RichTextLabel; class Tree; class VisualShaderEditor; +class MaterialEditor; class VisualShaderNodePlugin : public RefCounted { GDCLASS(VisualShaderNodePlugin, RefCounted); @@ -195,8 +197,8 @@ public: VisualShaderEditedProperty() {} }; -class VisualShaderEditor : public VBoxContainer { - GDCLASS(VisualShaderEditor, VBoxContainer); +class VisualShaderEditor : public ShaderEditor { + GDCLASS(VisualShaderEditor, ShaderEditor); friend class VisualShaderGraphPlugin; PopupPanel *property_editor_popup = nullptr; @@ -205,11 +207,18 @@ class VisualShaderEditor : public VBoxContainer { int editing_port = -1; Ref<VisualShaderEditedProperty> edited_property_holder; + MaterialEditor *material_editor = nullptr; Ref<VisualShader> visual_shader; + Ref<ShaderMaterial> preview_material; + Ref<Environment> env; + String param_filter_name; + EditorProperty *current_prop = nullptr; + VBoxContainer *shader_preview_vbox = nullptr; GraphEdit *graph = nullptr; Button *add_node = nullptr; MenuButton *varying_button = nullptr; - Button *preview_shader = nullptr; + Button *code_preview_button = nullptr; + Button *shader_preview_button = nullptr; OptionButton *edit_type = nullptr; OptionButton *edit_type_standard = nullptr; @@ -221,8 +230,8 @@ class VisualShaderEditor : public VBoxContainer { bool pending_update_preview = false; bool shader_error = false; - Window *preview_window = nullptr; - VBoxContainer *preview_vbox = nullptr; + Window *code_preview_window = nullptr; + VBoxContainer *code_preview_vbox = nullptr; CodeEdit *preview_text = nullptr; Ref<CodeHighlighter> syntax_highlighter = nullptr; PanelContainer *error_panel = nullptr; @@ -260,8 +269,17 @@ class VisualShaderEditor : public VBoxContainer { PopupPanel *frame_tint_color_pick_popup = nullptr; ColorPicker *frame_tint_color_picker = nullptr; - bool preview_first = true; - bool preview_showed = false; + bool code_preview_first = true; + bool code_preview_showed = false; + + bool shader_preview_showed = true; + + LineEdit *param_filter = nullptr; + String selected_param_id; + Tree *parameters = nullptr; + HashMap<String, PropertyInfo> parameter_props; + VBoxContainer *param_vbox = nullptr; + VBoxContainer *param_vbox2 = nullptr; enum ShaderModeFlags { MODE_FLAGS_SPATIAL_CANVASITEM = 1, @@ -348,6 +366,10 @@ class VisualShaderEditor : public VBoxContainer { void _show_add_varying_dialog(); void _show_remove_varying_dialog(); + void _clear_preview_param(); + void _update_preview_parameter_list(); + bool _update_preview_parameter_tree(); + void _update_nodes(); void _update_graph(); @@ -392,6 +414,7 @@ class VisualShaderEditor : public VBoxContainer { int custom_node_option_idx; int curve_node_option_idx; int curve_xyz_node_option_idx; + int mesh_emitter_option_idx; List<String> keyword_list; List<VisualShaderNodeParameterRef> uniform_refs; @@ -413,6 +436,8 @@ class VisualShaderEditor : public VBoxContainer { void _get_next_nodes_recursively(VisualShader::Type p_type, int p_node_id, LocalVector<int> &r_nodes) const; String _get_description(int p_idx); + void _show_shader_preview(); + Vector<int> nodes_link_to_frame_buffer; // Contains the nodes that are requested to be linked to a frame. This is used to perform one Undo/Redo operation for dragging nodes. int frame_node_id_to_link_to = -1; @@ -591,11 +616,23 @@ class VisualShaderEditor : public VBoxContainer { void _resource_removed(const Ref<Resource> &p_resource); void _resources_removed(); + void _param_property_changed(const String &p_property, const Variant &p_value, const String &p_field = "", bool p_changing = false); + void _update_current_param(); + void _param_filter_changed(const String &p_text); + void _param_selected(); + void _param_unselected(); + protected: void _notification(int p_what); static void _bind_methods(); public: + virtual void edit_shader(const Ref<Shader> &p_shader) override; + virtual void apply_shaders() override; + virtual bool is_unsaved() const override; + virtual void save_external_data(const String &p_str = "") override; + virtual void validate_script() override; + void add_plugin(const Ref<VisualShaderNodePlugin> &p_plugin); void remove_plugin(const Ref<VisualShaderNodePlugin> &p_plugin); @@ -609,11 +646,8 @@ public: virtual Size2 get_minimum_size() const override; - void edit(VisualShader *p_visual_shader); Ref<VisualShader> get_visual_shader() const { return visual_shader; } - void validate_script(); - VisualShaderEditor(); }; @@ -630,9 +664,6 @@ class EditorPropertyVisualShaderMode : public EditorProperty { void _option_selected(int p_which); -protected: - static void _bind_methods(); - public: void setup(const Vector<String> &p_options); virtual void update_property() override; @@ -651,6 +682,7 @@ public: class VisualShaderNodePortPreview : public Control { GDCLASS(VisualShaderNodePortPreview, Control); Ref<VisualShader> shader; + Ref<ShaderMaterial> preview_mat; VisualShader::Type type = VisualShader::Type::TYPE_MAX; int node = 0; int port = 0; @@ -658,11 +690,10 @@ class VisualShaderNodePortPreview : public Control { void _shader_changed(); //must regen protected: void _notification(int p_what); - static void _bind_methods(); public: virtual Size2 get_minimum_size() const override; - void setup(const Ref<VisualShader> &p_shader, VisualShader::Type p_type, int p_node, int p_port, bool p_is_valid); + void setup(const Ref<VisualShader> &p_shader, Ref<ShaderMaterial> &p_preview_material, VisualShader::Type p_type, int p_node, int p_port, bool p_is_valid); }; class VisualShaderConversionPlugin : public EditorResourceConversionPlugin { diff --git a/editor/plugins/voxel_gi_editor_plugin.cpp b/editor/plugins/voxel_gi_editor_plugin.cpp index e7b2435567..3e835d5cb6 100644 --- a/editor/plugins/voxel_gi_editor_plugin.cpp +++ b/editor/plugins/voxel_gi_editor_plugin.cpp @@ -177,9 +177,6 @@ void VoxelGIEditorPlugin::_voxel_gi_save_path_and_bake(const String &p_path) { } } -void VoxelGIEditorPlugin::_bind_methods() { -} - VoxelGIEditorPlugin::VoxelGIEditorPlugin() { bake_hb = memnew(HBoxContainer); bake_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); diff --git a/editor/plugins/voxel_gi_editor_plugin.h b/editor/plugins/voxel_gi_editor_plugin.h index 58ef22ddc6..d09822dda6 100644 --- a/editor/plugins/voxel_gi_editor_plugin.h +++ b/editor/plugins/voxel_gi_editor_plugin.h @@ -58,7 +58,6 @@ class VoxelGIEditorPlugin : public EditorPlugin { void _voxel_gi_save_path_and_bake(const String &p_path); protected: - static void _bind_methods(); void _notification(int p_what); public: |