summaryrefslogtreecommitdiff
path: root/editor/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'editor/plugins')
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp41
-rw-r--r--editor/plugins/editor_preview_plugins.cpp6
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp1091
-rw-r--r--editor/plugins/node_3d_editor_plugin.h93
-rw-r--r--editor/plugins/packed_scene_translation_parser_plugin.cpp9
-rw-r--r--editor/plugins/packed_scene_translation_parser_plugin.h4
-rw-r--r--editor/plugins/replication_editor_plugin.cpp4
-rw-r--r--editor/plugins/script_editor_plugin.cpp4
-rw-r--r--editor/plugins/script_text_editor.cpp15
-rw-r--r--editor/plugins/text_control_editor_plugin.cpp156
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp10
12 files changed, 829 insertions, 606 deletions
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index b000ff8eee..40d6bc48e7 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -300,7 +300,7 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
base_name = add_options[p_idx].name;
} else {
ERR_FAIL_COND(add_options[p_idx].script.is_null());
- String base_type = add_options[p_idx].script->get_instance_base_type();
+ StringName base_type = add_options[p_idx].script->get_instance_base_type();
AnimationNode *an = Object::cast_to<AnimationNode>(ClassDB::instantiate(base_type));
ERR_FAIL_COND(!an);
anode = Ref<AnimationNode>(an);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 8d2e6a13b4..aa8ad55ff3 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -5804,7 +5804,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &
}
// make visible for certain node type
- if (ClassDB::is_parent_class(child->get_class(), "Control")) {
+ if (Object::cast_to<Control>(child)) {
Size2 texture_size = texture->get_size();
editor_data->get_undo_redo().add_do_property(child, "rect_size", texture_size);
} else if (Object::cast_to<Polygon2D>(child)) {
@@ -5935,29 +5935,32 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian
if (String(d["type"]) == "files") {
Vector<String> files = d["files"];
bool can_instantiate = false;
- for (int i = 0; i < files.size(); i++) { // check if dragged files contain resource or scene can be created at least once
- RES res = ResourceLoader::load(files[i]);
- if (res.is_null()) {
- continue;
- }
- String type = res->get_class();
- if (type == "PackedScene") {
- Ref<PackedScene> sdata = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
- Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
- if (!instantiated_scene) {
+
+ List<String> scene_extensions;
+ ResourceLoader::get_recognized_extensions_for_type("PackedScene", &scene_extensions);
+ List<String> texture_extensions;
+ ResourceLoader::get_recognized_extensions_for_type("Texture2D", &texture_extensions);
+
+ for (int i = 0; i < files.size(); i++) {
+ // Check if dragged files with texture or scene extension can be created at least once.
+ if (texture_extensions.find(files[i].get_extension()) || scene_extensions.find(files[i].get_extension())) {
+ RES res = ResourceLoader::load(files[i]);
+ if (res.is_null()) {
continue;
}
- memdelete(instantiated_scene);
- } else if (ClassDB::is_parent_class(type, "Texture2D")) {
- Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(*res));
- if (!texture.is_valid()) {
+ Ref<PackedScene> scn = res;
+ if (scn.is_valid()) {
+ Node *instantiated_scene = scn->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
+ if (!instantiated_scene) {
+ continue;
+ }
+ memdelete(instantiated_scene);
+ } else {
continue;
}
- } else {
- continue;
+ can_instantiate = true;
+ break;
}
- can_instantiate = true;
- break;
}
if (can_instantiate) {
if (!preview_node->get_parent()) { // create preview only once
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 7e0019faac..d23b52014e 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -188,7 +188,7 @@ bool EditorImagePreviewPlugin::generate_small_preview_automatically() const {
}
////////////////////////////////////////////////////////////////////////////
-/////////////////////////////////////////////////
+
bool EditorBitmapPreviewPlugin::handles(const String &p_type) const {
return ClassDB::is_parent_class(p_type, "BitMap");
}
@@ -308,7 +308,7 @@ void EditorMaterialPreviewPlugin::_preview_done() {
}
bool EditorMaterialPreviewPlugin::handles(const String &p_type) const {
- return ClassDB::is_parent_class(p_type, "Material"); //any material
+ return ClassDB::is_parent_class(p_type, "Material"); // Any material.
}
bool EditorMaterialPreviewPlugin::generate_small_preview_automatically() const {
@@ -699,7 +699,7 @@ void EditorMeshPreviewPlugin::_preview_done() {
}
bool EditorMeshPreviewPlugin::handles(const String &p_type) const {
- return ClassDB::is_parent_class(p_type, "Mesh"); //any Mesh
+ return ClassDB::is_parent_class(p_type, "Mesh"); // Any mesh.
}
Ref<Texture2D> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 0c0188e8d1..f79b5027cb 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -384,6 +384,28 @@ int Node3DEditorViewport::get_selected_count() const {
return count;
}
+void Node3DEditorViewport::cancel_transform() {
+ _edit.mode = TRANSFORM_NONE;
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+ Node3D *sp = Object::cast_to<Node3D>(E->get());
+ if (!sp) {
+ continue;
+ }
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se) {
+ continue;
+ }
+
+ sp->set_global_transform(se->original);
+ }
+ surface->update();
+ set_message(TTR("Transform Aborted."), 3);
+}
+
float Node3DEditorViewport::get_znear() const {
return CLAMP(spatial_editor->get_znear(), MIN_Z, MAX_Z);
}
@@ -864,12 +886,15 @@ void Node3DEditorViewport::_update_name() {
view_menu->reset_size();
}
-void Node3DEditorViewport::_compute_edit(const Point2 &p_point) {
+void Node3DEditorViewport::_compute_edit(const Point2 &p_point, const bool p_auto_center) {
+ _edit.original_local = spatial_editor->are_local_coords_enabled();
_edit.click_ray = _get_ray(p_point);
_edit.click_ray_pos = _get_ray_pos(p_point);
_edit.plane = TRANSFORM_VIEW;
+ if (p_auto_center) {
+ _edit.center = spatial_editor->get_gizmo_transform().origin;
+ }
spatial_editor->update_transform_gizmo();
- _edit.center = spatial_editor->get_gizmo_transform().origin;
Node3D *selected = spatial_editor->get_single_selected_node();
Node3DEditorSelectedItem *se = selected ? editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(selected) : nullptr;
@@ -1018,24 +1043,40 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) {
int col_axis = -1;
- float col_d = 1e20;
- for (int i = 0; i < 3; i++) {
- Plane plane(gt.basis.get_axis(i).normalized(), gt.origin);
- Vector3 r;
- if (!plane.intersects_ray(ray_pos, ray, &r)) {
- continue;
+ Vector3 hit_position;
+ Vector3 hit_normal;
+ real_t ray_length = gt.origin.distance_to(ray_pos) + (GIZMO_CIRCLE_SIZE * gizmo_scale) * 4.0f;
+ if (Geometry3D::segment_intersects_sphere(ray_pos, ray_pos + ray * ray_length, gt.origin, gizmo_scale * (GIZMO_CIRCLE_SIZE), &hit_position, &hit_normal)) {
+ if (hit_normal.dot(_get_camera_normal()) < 0.05) {
+ hit_position = gt.xform_inv(hit_position).abs();
+ int min_axis = hit_position.min_axis_index();
+ if (hit_position[min_axis] < gizmo_scale * GIZMO_RING_HALF_WIDTH) {
+ col_axis = min_axis;
+ }
}
+ }
+
+ if (col_axis == -1) {
+ float col_d = 1e20;
- const real_t dist = r.distance_to(gt.origin);
- const Vector3 r_dir = (r - gt.origin).normalized();
+ for (int i = 0; i < 3; i++) {
+ Plane plane(gt.basis.get_axis(i).normalized(), gt.origin);
+ Vector3 r;
+ if (!plane.intersects_ray(ray_pos, ray, &r)) {
+ continue;
+ }
+
+ const real_t dist = r.distance_to(gt.origin);
+ const Vector3 r_dir = (r - gt.origin).normalized();
- if (_get_camera_normal().dot(r_dir) <= 0.005) {
- if (dist > gizmo_scale * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && dist < gizmo_scale * (GIZMO_CIRCLE_SIZE + GIZMO_RING_HALF_WIDTH)) {
- const real_t d = ray_pos.distance_to(r);
- if (d < col_d) {
- col_d = d;
- col_axis = i;
+ if (_get_camera_normal().dot(r_dir) <= 0.005) {
+ if (dist > gizmo_scale * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && dist < gizmo_scale * (GIZMO_CIRCLE_SIZE + GIZMO_RING_HALF_WIDTH)) {
+ const real_t d = ray_pos.distance_to(r);
+ if (d < col_d) {
+ col_d = d;
+ col_axis = i;
+ }
}
}
}
@@ -1325,6 +1366,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
}
+ _edit.center = spatial_editor->get_gizmo_target_center();
Ref<InputEventMouseButton> b = p_event;
if (b.is_valid()) {
@@ -1375,39 +1417,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
if (_edit.mode != TRANSFORM_NONE && b->is_pressed()) {
- //cancel motion
- _edit.mode = TRANSFORM_NONE;
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- for (Node *E : selection) {
- Node3D *sp = Object::cast_to<Node3D>(E);
- if (!sp) {
- continue;
- }
-
- Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
- if (!se) {
- continue;
- }
-
- if (se->gizmo.is_valid()) {
- Vector<int> ids;
- Vector<Transform3D> restore;
-
- for (const KeyValue<int, Transform3D> &GE : se->subgizmos) {
- ids.push_back(GE.key);
- restore.push_back(GE.value);
- }
-
- se->gizmo->commit_subgizmos(ids, restore, true);
- spatial_editor->update_transform_gizmo();
- } else {
- sp->set_global_transform(se->original);
- }
- }
- surface->update();
- set_message(TTR("Transform Aborted."), 3);
+ cancel_transform();
}
if (b->is_pressed()) {
@@ -1461,6 +1471,10 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
} break;
case MouseButton::LEFT: {
if (b->is_pressed()) {
+ if (_edit.mode != TRANSFORM_NONE && _edit.instant) {
+ commit_transform();
+ break; // just commit the edit, stop processing the event so we don't deselect the object
+ }
NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
if ((nav_scheme == NAVIGATION_MAYA || nav_scheme == NAVIGATION_MODO) && b->is_alt_pressed()) {
break;
@@ -1567,33 +1581,17 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
clicked = ObjectID();
if ((spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT && b->is_command_pressed()) || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) {
- /* HANDLE ROTATION */
- if (get_selected_count() == 0) {
- break; //bye
- }
- //handle rotate
- _edit.mode = TRANSFORM_ROTATE;
- _compute_edit(b->get_position());
+ begin_transform(TRANSFORM_ROTATE, false);
break;
}
if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) {
- if (get_selected_count() == 0) {
- break; //bye
- }
- //handle translate
- _edit.mode = TRANSFORM_TRANSLATE;
- _compute_edit(b->get_position());
+ begin_transform(TRANSFORM_TRANSLATE, false);
break;
}
if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE) {
- if (get_selected_count() == 0) {
- break; //bye
- }
- //handle scale
- _edit.mode = TRANSFORM_SCALE;
- _compute_edit(b->get_position());
+ begin_transform(TRANSFORM_SCALE, false);
break;
}
@@ -1648,32 +1646,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
se->gizmo->commit_subgizmos(ids, restore, false);
spatial_editor->update_transform_gizmo();
} else {
- static const char *_transform_name[4] = {
- TTRC("None"),
- TTRC("Rotate"),
- // TRANSLATORS: This refers to the movement that changes the position of an object.
- TTRC("Translate"),
- TTRC("Scale"),
- };
- undo_redo->create_action(TTRGET(_transform_name[_edit.mode]));
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
- Node3D *sp = Object::cast_to<Node3D>(E->get());
- if (!sp) {
- continue;
- }
-
- Node3DEditorSelectedItem *sel_item = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
- if (!sel_item) {
- continue;
- }
-
- undo_redo->add_do_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
- undo_redo->add_undo_method(sp, "set_global_transform", sel_item->original);
- }
- undo_redo->commit_action();
+ commit_transform();
}
_edit.mode = TRANSFORM_NONE;
set_message("");
@@ -1739,7 +1712,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
String n = _edit.gizmo->get_handle_name(_edit.gizmo_handle, _edit.gizmo_handle_secondary);
set_message(n + ": " + String(v));
- } else if ((m->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
+ } else if ((m->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE || _edit.instant) {
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()) {
@@ -1767,324 +1740,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
return;
}
- Vector3 ray_pos = _get_ray_pos(m->get_position());
- Vector3 ray = _get_ray(m->get_position());
- double snap = EDITOR_GET("interface/inspector/default_float_step");
- int snap_step_decimals = Math::range_step_decimals(snap);
-
- switch (_edit.mode) {
- case TRANSFORM_SCALE: {
- Vector3 motion_mask;
- Plane plane;
- bool plane_mv = false;
-
- switch (_edit.plane) {
- case TRANSFORM_VIEW:
- motion_mask = Vector3(0, 0, 0);
- plane = Plane(_get_camera_normal(), _edit.center);
- break;
- case TRANSFORM_X_AXIS:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized();
- plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
- break;
- case TRANSFORM_Y_AXIS:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized();
- plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
- break;
- case TRANSFORM_Z_AXIS:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized();
- plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
- break;
- case TRANSFORM_YZ:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized() + spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized();
- plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized(), _edit.center);
- plane_mv = true;
- break;
- case TRANSFORM_XZ:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized() + spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized();
- plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized(), _edit.center);
- plane_mv = true;
- break;
- case TRANSFORM_XY:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized() + spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized();
- plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized(), _edit.center);
- plane_mv = true;
- break;
- }
-
- Vector3 intersection;
- if (!plane.intersects_ray(ray_pos, ray, &intersection)) {
- break;
- }
-
- Vector3 click;
- if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) {
- break;
- }
-
- Vector3 motion = intersection - click;
- if (_edit.plane != TRANSFORM_VIEW) {
- if (!plane_mv) {
- motion = motion_mask.dot(motion) * motion_mask;
-
- } else {
- // Alternative planar scaling mode
- if (_get_key_modifier(m) != Key::SHIFT) {
- motion = motion_mask.dot(motion) * motion_mask;
- }
- }
-
- } else {
- const real_t center_click_dist = click.distance_to(_edit.center);
- const real_t center_inters_dist = intersection.distance_to(_edit.center);
- if (center_click_dist == 0) {
- break;
- }
-
- const real_t scale = center_inters_dist - center_click_dist;
- motion = Vector3(scale, scale, scale);
- }
-
- motion /= click.distance_to(_edit.center);
-
- // Disable local transformation for TRANSFORM_VIEW
- bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
-
- if (_edit.snap || spatial_editor->is_snap_enabled()) {
- snap = spatial_editor->get_scale_snap() / 100;
- }
- Vector3 motion_snapped = motion;
- motion_snapped.snap(Vector3(snap, snap, snap));
- // This might not be necessary anymore after issue #288 is solved (in 4.0?).
- set_message(TTR("Scaling: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
- String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
- motion = _edit.original.basis.inverse().xform(motion);
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
- for (Node *E : selection) {
- Node3D *sp = Object::cast_to<Node3D>(E);
- if (!sp) {
- continue;
- }
-
- Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
- if (!se) {
- continue;
- }
-
- if (sp->has_meta("_edit_lock_")) {
- continue;
- }
-
- if (se->gizmo.is_valid()) {
- for (KeyValue<int, Transform3D> &GE : se->subgizmos) {
- Transform3D xform = GE.value;
- Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original * xform, xform, motion, snap, local_coords, true); // Force orthogonal with subgizmo.
- if (!local_coords) {
- new_xform = se->original.affine_inverse() * new_xform;
- }
- se->gizmo->set_subgizmo_transform(GE.key, new_xform);
- }
- } else {
- Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original, se->original_local, motion, snap, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS);
- _transform_gizmo_apply(se->sp, new_xform, local_coords);
- }
- }
-
- spatial_editor->update_transform_gizmo();
- surface->update();
-
- } break;
-
- case TRANSFORM_TRANSLATE: {
- Vector3 motion_mask;
- Plane plane;
- bool plane_mv = false;
-
- switch (_edit.plane) {
- case TRANSFORM_VIEW:
- plane = Plane(_get_camera_normal(), _edit.center);
- break;
- case TRANSFORM_X_AXIS:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized();
- plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
- break;
- case TRANSFORM_Y_AXIS:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized();
- plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
- break;
- case TRANSFORM_Z_AXIS:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized();
- plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
- break;
- case TRANSFORM_YZ:
- plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized(), _edit.center);
- plane_mv = true;
- break;
- case TRANSFORM_XZ:
- plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized(), _edit.center);
- plane_mv = true;
- break;
- case TRANSFORM_XY:
- plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized(), _edit.center);
- plane_mv = true;
- break;
- }
-
- Vector3 intersection;
- if (!plane.intersects_ray(ray_pos, ray, &intersection)) {
- break;
- }
-
- Vector3 click;
- if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) {
- break;
- }
-
- Vector3 motion = intersection - click;
- if (_edit.plane != TRANSFORM_VIEW) {
- if (!plane_mv) {
- motion = motion_mask.dot(motion) * motion_mask;
- }
- }
-
- // Disable local transformation for TRANSFORM_VIEW
- bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
-
- if (_edit.snap || spatial_editor->is_snap_enabled()) {
- snap = spatial_editor->get_translate_snap();
- }
- Vector3 motion_snapped = motion;
- motion_snapped.snap(Vector3(snap, snap, snap));
- set_message(TTR("Translating: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
- String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
- motion = spatial_editor->get_gizmo_transform().basis.inverse().xform(motion);
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
- for (Node *E : selection) {
- Node3D *sp = Object::cast_to<Node3D>(E);
- if (!sp) {
- continue;
- }
-
- Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
- if (!se) {
- continue;
- }
-
- if (sp->has_meta("_edit_lock_")) {
- continue;
- }
-
- if (se->gizmo.is_valid()) {
- for (KeyValue<int, Transform3D> &GE : se->subgizmos) {
- Transform3D xform = GE.value;
- Transform3D new_xform = _compute_transform(TRANSFORM_TRANSLATE, se->original * xform, xform, motion, snap, local_coords, true); // Force orthogonal with subgizmo.
- new_xform = se->original.affine_inverse() * new_xform;
- se->gizmo->set_subgizmo_transform(GE.key, new_xform);
- }
- } else {
- Transform3D new_xform = _compute_transform(TRANSFORM_TRANSLATE, se->original, se->original_local, motion, snap, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS);
- _transform_gizmo_apply(se->sp, new_xform, false);
- }
- }
-
- spatial_editor->update_transform_gizmo();
- surface->update();
-
- } break;
-
- case TRANSFORM_ROTATE: {
- Plane plane;
- Vector3 axis;
-
- switch (_edit.plane) {
- case TRANSFORM_VIEW:
- plane = Plane(_get_camera_normal(), _edit.center);
- break;
- case TRANSFORM_X_AXIS:
- plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized(), _edit.center);
- axis = Vector3(1, 0, 0);
- break;
- case TRANSFORM_Y_AXIS:
- plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized(), _edit.center);
- axis = Vector3(0, 1, 0);
- break;
- case TRANSFORM_Z_AXIS:
- plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized(), _edit.center);
- axis = Vector3(0, 0, 1);
- break;
- case TRANSFORM_YZ:
- case TRANSFORM_XZ:
- case TRANSFORM_XY:
- break;
- }
-
- Vector3 intersection;
- if (!plane.intersects_ray(ray_pos, ray, &intersection)) {
- break;
- }
-
- Vector3 click;
- if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) {
- break;
- }
-
- Vector3 y_axis = (click - _edit.center).normalized();
- Vector3 x_axis = plane.normal.cross(y_axis).normalized();
-
- double angle = Math::atan2(x_axis.dot(intersection - _edit.center), y_axis.dot(intersection - _edit.center));
-
- if (_edit.snap || spatial_editor->is_snap_enabled()) {
- snap = spatial_editor->get_rotate_snap();
- }
- angle = Math::rad2deg(angle) + snap * 0.5; //else it won't reach +180
- angle -= Math::fmod(angle, snap);
- set_message(vformat(TTR("Rotating %s degrees."), String::num(angle, snap_step_decimals)));
- angle = Math::deg2rad(angle);
-
- bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
- for (Node *E : selection) {
- Node3D *sp = Object::cast_to<Node3D>(E);
- if (!sp) {
- continue;
- }
-
- Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
- if (!se) {
- continue;
- }
-
- if (sp->has_meta("_edit_lock_")) {
- continue;
- }
-
- Vector3 compute_axis = local_coords ? axis : plane.normal;
- if (se->gizmo.is_valid()) {
- for (KeyValue<int, Transform3D> &GE : se->subgizmos) {
- Transform3D xform = GE.value;
-
- Transform3D new_xform = _compute_transform(TRANSFORM_ROTATE, se->original * xform, xform, compute_axis, angle, local_coords, true); // Force orthogonal with subgizmo.
- if (!local_coords) {
- new_xform = se->original.affine_inverse() * new_xform;
- }
- se->gizmo->set_subgizmo_transform(GE.key, new_xform);
- }
- } else {
- Transform3D new_xform = _compute_transform(TRANSFORM_ROTATE, se->original, se->original_local, compute_axis, angle, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS);
- _transform_gizmo_apply(se->sp, new_xform, local_coords);
- }
- }
-
- spatial_editor->update_transform_gizmo();
- surface->update();
-
- } break;
- default: {
- }
- }
+ update_transform(m->get_position(), _get_key_modifier(m) == Key::SHIFT);
}
} else if ((m->get_button_mask() & MouseButton::MASK_RIGHT) != MouseButton::NONE || freelook_active) {
if (nav_scheme == NAVIGATION_MAYA && m->is_alt_pressed()) {
@@ -2225,6 +1881,51 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
}
+ if (_edit.mode != TRANSFORM_NONE) {
+ // We're actively transforming, handle keys specially
+ TransformPlane new_plane = TRANSFORM_VIEW;
+ String new_message;
+ if (ED_IS_SHORTCUT("spatial_editor/lock_transform_x", p_event)) {
+ new_plane = TRANSFORM_X_AXIS;
+ new_message = TTR("X-Axis Transform.");
+ } else if (ED_IS_SHORTCUT("spatial_editor/lock_transform_y", p_event)) {
+ new_plane = TRANSFORM_Y_AXIS;
+ new_message = TTR("Y-Axis Transform.");
+ } else if (ED_IS_SHORTCUT("spatial_editor/lock_transform_z", p_event)) {
+ new_plane = TRANSFORM_Z_AXIS;
+ new_message = TTR("Z-Axis Transform.");
+ } else if (_edit.mode != TRANSFORM_ROTATE) { // rotating on a plane doesn't make sense
+ if (ED_IS_SHORTCUT("spatial_editor/lock_transform_yz", p_event)) {
+ new_plane = TRANSFORM_YZ;
+ new_message = TTR("YZ-Plane Transform.");
+ } else if (ED_IS_SHORTCUT("spatial_editor/lock_transform_xz", p_event)) {
+ new_plane = TRANSFORM_XZ;
+ new_message = TTR("XZ-Plane Transform.");
+ } else if (ED_IS_SHORTCUT("spatial_editor/lock_transform_xy", p_event)) {
+ new_plane = TRANSFORM_XY;
+ new_message = TTR("XY-Plane Transform.");
+ }
+ }
+
+ if (new_plane != TRANSFORM_VIEW) {
+ if (new_plane != _edit.plane) {
+ // lock me once and get a global constraint
+ _edit.plane = new_plane;
+ spatial_editor->set_local_coords_enabled(false);
+ } else if (!spatial_editor->are_local_coords_enabled()) {
+ // lock me twice and get a local constraint
+ spatial_editor->set_local_coords_enabled(true);
+ } else {
+ // lock me thrice and we're back where we started
+ _edit.plane = TRANSFORM_VIEW;
+ spatial_editor->set_local_coords_enabled(false);
+ }
+ update_transform(_edit.mouse_pos, Input::get_singleton()->is_key_pressed(Key::SHIFT));
+ set_message(new_message, 2);
+ accept_event();
+ return;
+ }
+ }
if (ED_IS_SHORTCUT("spatial_editor/snap", p_event)) {
if (_edit.mode != TRANSFORM_NONE) {
_edit.snap = !_edit.snap;
@@ -2315,6 +2016,18 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
set_message(TTR("Animation Key Inserted."));
}
+ if (ED_IS_SHORTCUT("spatial_editor/cancel_transform", p_event) && _edit.mode != TRANSFORM_NONE) {
+ cancel_transform();
+ }
+ if (ED_IS_SHORTCUT("spatial_editor/instant_translate", p_event)) {
+ begin_transform(TRANSFORM_TRANSLATE, true);
+ }
+ if (ED_IS_SHORTCUT("spatial_editor/instant_rotate", p_event)) {
+ begin_transform(TRANSFORM_ROTATE, true);
+ }
+ if (ED_IS_SHORTCUT("spatial_editor/instant_scale", p_event)) {
+ begin_transform(TRANSFORM_SCALE, true);
+ }
// Freelook doesn't work in orthogonal mode.
if (!orthogonal && ED_IS_SHORTCUT("spatial_editor/freelook_toggle", p_event)) {
@@ -3036,7 +2749,7 @@ void Node3DEditorViewport::_draw() {
font->draw_string(ci, msgpos, message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(1, 1, 1, 1));
}
- if (_edit.mode == TRANSFORM_ROTATE) {
+ if (_edit.mode == TRANSFORM_ROTATE && _edit.show_rotation_line) {
Point2 center = _point_to_screen(_edit.center);
Color handle_color;
@@ -3544,6 +3257,13 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_plane_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(scale_plane_gizmo_instance[i], layer);
RS::get_singleton()->instance_geometry_set_flag(scale_plane_gizmo_instance[i], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
+
+ axis_gizmo_instance[i] = RS::get_singleton()->instance_create();
+ RS::get_singleton()->instance_set_base(axis_gizmo_instance[i], spatial_editor->get_axis_gizmo(i)->get_rid());
+ RS::get_singleton()->instance_set_scenario(axis_gizmo_instance[i], get_tree()->get_root()->get_world_3d()->get_scenario());
+ RS::get_singleton()->instance_set_visible(axis_gizmo_instance[i], true);
+ RS::get_singleton()->instance_geometry_set_cast_shadows_setting(axis_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
+ RS::get_singleton()->instance_set_layer_mask(axis_gizmo_instance[i], layer);
}
// Rotation white outline
@@ -3563,6 +3283,7 @@ void Node3DEditorViewport::_finish_gizmo_instances() {
RS::get_singleton()->free(rotate_gizmo_instance[i]);
RS::get_singleton()->free(scale_gizmo_instance[i]);
RS::get_singleton()->free(scale_plane_gizmo_instance[i]);
+ RS::get_singleton()->free(axis_gizmo_instance[i]);
}
// Rotation white outline
RS::get_singleton()->free(rotate_gizmo_instance[3]);
@@ -3646,7 +3367,7 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
Transform3D xform = spatial_editor->get_gizmo_transform();
- Transform3D camera_xform = camera->get_transform();
+ const Transform3D camera_xform = camera->get_transform();
if (xform.origin.is_equal_approx(camera_xform.origin)) {
for (int i = 0; i < 3; i++) {
@@ -3655,6 +3376,7 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], false);
RenderingServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false);
RenderingServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false);
+ RenderingServer::get_singleton()->instance_set_visible(axis_gizmo_instance[i], false);
}
// Rotation white outline
RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], false);
@@ -3664,11 +3386,63 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
const Vector3 camz = -camera_xform.get_basis().get_axis(2).normalized();
const Vector3 camy = -camera_xform.get_basis().get_axis(1).normalized();
const Plane p = Plane(camz, camera_xform.origin);
- const real_t gizmo_d = MAX(Math::abs(p.distance_to(xform.origin)), CMP_EPSILON);
+ const real_t gizmo_d = CLAMP(Math::abs(p.distance_to(xform.origin)), camera->get_near() * 2, camera->get_far() / 2);
const real_t d0 = camera->unproject_position(camera_xform.origin + camz * gizmo_d).y;
const real_t d1 = camera->unproject_position(camera_xform.origin + camz * gizmo_d + camy).y;
const real_t dd = MAX(Math::abs(d0 - d1), CMP_EPSILON);
+ // This code ensures the gizmo stays on the screen. This includes if
+ // the gizmo would otherwise be behind the camera, to the sides of
+ // the camera, too close to the edge of the screen, too close to
+ // the camera, or too far away from the camera. First we calculate
+ // where the gizmo would go on screen, then we put it there.
+ const Vector3 object_position = spatial_editor->get_gizmo_target_center();
+ Vector2 gizmo_screen_position = camera->unproject_position(object_position);
+ const Vector2 viewport_size = viewport->get_size();
+ // We would use "camera.is_position_behind(parent_translation)" instead of dot,
+ // except that it also accounts for the near clip plane, which we don't want.
+ const bool is_in_front = camera_xform.basis.get_column(2).dot(object_position - camera_xform.origin) < 0;
+ const bool is_in_viewport = is_in_front && Rect2(Vector2(0, 0), viewport_size).has_point(gizmo_screen_position);
+ if (spatial_editor->is_keep_gizmo_onscreen_enabled()) {
+ if (!spatial_editor->is_gizmo_visible() || is_in_viewport) {
+ // In this case, the gizmo is either not visible, or in the viewport
+ // already, so we should hide the offscreen line.
+ gizmo_offscreen_line->hide();
+ } else {
+ // In this case, the point is not "normally" on screen, and
+ // it should be placed in the center.
+ const Vector2 half_viewport_size = viewport_size / 2;
+ gizmo_screen_position = half_viewport_size;
+ // The rest of this is for drawing the offscreen line.
+ // One point goes in the center of the viewport.
+ // Calculate where to put the other point of the line.
+ Vector2 unprojected_position = camera->unproject_position(object_position);
+ if (!is_in_front) {
+ // When the object is behind, we need to flip and grow the line.
+ unprojected_position -= half_viewport_size;
+ unprojected_position = unprojected_position.normalized() * -half_viewport_size.length_squared();
+ unprojected_position += half_viewport_size;
+ }
+ gizmo_offscreen_line->point1 = half_viewport_size;
+ gizmo_offscreen_line->point2 = unprojected_position;
+ gizmo_offscreen_line->update();
+ gizmo_offscreen_line->show();
+ }
+ // Update the gizmo's position using what we calculated.
+ xform.origin = camera->project_position(gizmo_screen_position, gizmo_d);
+ } else {
+ // In this case, the user does not want the gizmo to be
+ // kept on screen, so we should hide the offscreen line,
+ // and just use the gizmo's unmodified position.
+ gizmo_offscreen_line->hide();
+ if (is_in_viewport) {
+ xform.origin = camera->project_position(gizmo_screen_position, gizmo_d);
+ } else {
+ xform.origin = object_position;
+ }
+ }
+ spatial_editor->set_gizmo_transform(xform);
+
const real_t gizmo_size = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_size");
// At low viewport heights, multiply the gizmo scale based on the viewport height.
// This prevents the gizmo from growing very large and going outside the viewport.
@@ -3677,7 +3451,6 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
(gizmo_size / Math::abs(dd)) * MAX(1, EDSCALE) *
MIN(viewport_base_height, subviewport_container->get_size().height) / viewport_base_height /
subviewport_container->get_stretch_shrink();
- Vector3 scale = Vector3(1, 1, 1) * gizmo_scale;
// if the determinant is zero, we should disable the gizmo from being rendered
// this prevents supplying bad values to the renderer and then having to filter it out again
@@ -3699,7 +3472,7 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
if (xform.basis.get_axis(i).normalized().dot(xform.basis.get_axis((i + 1) % 3).normalized()) < 1.0) {
axis_angle = axis_angle.looking_at(xform.basis.get_axis(i).normalized(), xform.basis.get_axis((i + 1) % 3).normalized());
}
- axis_angle.basis.scale(scale);
+ axis_angle.basis *= gizmo_scale;
axis_angle.origin = xform.origin;
RenderingServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], axis_angle);
RenderingServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE));
@@ -3711,10 +3484,18 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
RenderingServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE));
RenderingServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], axis_angle);
RenderingServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE));
+ RenderingServer::get_singleton()->instance_set_transform(axis_gizmo_instance[i], xform);
}
+
+ bool show_axes = spatial_editor->is_gizmo_visible() && _edit.mode != TRANSFORM_NONE;
+ RenderingServer *rs = RenderingServer::get_singleton();
+ rs->instance_set_visible(axis_gizmo_instance[0], show_axes && (_edit.plane == TRANSFORM_X_AXIS || _edit.plane == TRANSFORM_XY || _edit.plane == TRANSFORM_XZ));
+ rs->instance_set_visible(axis_gizmo_instance[1], show_axes && (_edit.plane == TRANSFORM_Y_AXIS || _edit.plane == TRANSFORM_XY || _edit.plane == TRANSFORM_YZ));
+ rs->instance_set_visible(axis_gizmo_instance[2], show_axes && (_edit.plane == TRANSFORM_Z_AXIS || _edit.plane == TRANSFORM_XZ || _edit.plane == TRANSFORM_YZ));
+
// Rotation white outline
xform.orthonormalize();
- xform.basis.scale(scale);
+ xform.basis *= gizmo_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));
}
@@ -3978,7 +3759,7 @@ AABB Node3DEditorViewport::_calculate_spatial_bounds(const Node3D *p_parent, boo
if (child) {
AABB child_bounds = _calculate_spatial_bounds(child, false);
- if (bounds.size == Vector3() && p_parent->get_class_name() == StringName("Node3D")) {
+ if (bounds.size == Vector3() && Object::cast_to<Node3D>(p_parent)) {
bounds = child_bounds;
} else {
bounds.merge_with(child_bounds);
@@ -3986,7 +3767,7 @@ AABB Node3DEditorViewport::_calculate_spatial_bounds(const Node3D *p_parent, boo
}
}
- if (bounds.size == Vector3() && p_parent->get_class_name() != StringName("Node3D")) {
+ if (bounds.size == Vector3() && !Object::cast_to<Node3D>(p_parent)) {
bounds = AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4));
}
@@ -4213,25 +3994,19 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
ResourceLoader::get_recognized_extensions_for_type("Mesh", &mesh_extensions);
for (int i = 0; i < files.size(); i++) {
+ // Check if dragged files with mesh or scene extension can be created at least once.
if (mesh_extensions.find(files[i].get_extension()) || scene_extensions.find(files[i].get_extension())) {
RES res = ResourceLoader::load(files[i]);
if (res.is_null()) {
continue;
}
-
- String type = res->get_class();
- if (type == "PackedScene") {
- Ref<PackedScene> sdata = ResourceLoader::load(files[i]);
- Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
+ Ref<PackedScene> scn = res;
+ if (scn.is_valid()) {
+ Node *instantiated_scene = scn->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
if (!instantiated_scene) {
continue;
}
memdelete(instantiated_scene);
- } else if (ClassDB::is_parent_class(type, "Mesh")) {
- Ref<Mesh> mesh = ResourceLoader::load(files[i]);
- if (!mesh.is_valid()) {
- continue;
- }
} else {
continue;
}
@@ -4299,6 +4074,387 @@ void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_
_perform_drop_data();
}
+void Node3DEditorViewport::begin_transform(TransformMode p_mode, bool instant) {
+ if (get_selected_count() > 0) {
+ _edit.mode = p_mode;
+ _compute_edit(_edit.mouse_pos, false);
+ _edit.instant = instant;
+ _edit.snap = spatial_editor->is_snap_enabled();
+ }
+}
+
+void Node3DEditorViewport::commit_transform() {
+ ERR_FAIL_COND(_edit.mode == TRANSFORM_NONE);
+ static const char *_transform_name[4] = {
+ TTRC("None"),
+ TTRC("Rotate"),
+ // TRANSLATORS: This refers to the movement that changes the position of an object.
+ TTRC("Translate"),
+ TTRC("Scale"),
+ };
+ undo_redo->create_action(_transform_name[_edit.mode]);
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+ Node3D *sp = Object::cast_to<Node3D>(E->get());
+ if (!sp) {
+ continue;
+ }
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se) {
+ continue;
+ }
+
+ undo_redo->add_do_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
+ undo_redo->add_undo_method(sp, "set_global_transform", se->original);
+ }
+ undo_redo->commit_action();
+ _edit.mode = TRANSFORM_NONE;
+ _edit.instant = false;
+ spatial_editor->set_local_coords_enabled(_edit.original_local);
+ set_message("");
+ spatial_editor->update_transform_gizmo();
+ surface->update();
+}
+
+void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
+ Vector3 ray_pos = _get_ray_pos(p_mousepos);
+ Vector3 ray = _get_ray(p_mousepos);
+ double snap = EDITOR_GET("interface/inspector/default_float_step");
+ int snap_step_decimals = Math::range_step_decimals(snap);
+
+ switch (_edit.mode) {
+ case TRANSFORM_SCALE: {
+ Vector3 motion_mask;
+ Plane plane;
+ bool plane_mv = false;
+
+ switch (_edit.plane) {
+ case TRANSFORM_VIEW:
+ motion_mask = Vector3(0, 0, 0);
+ plane = Plane(_get_camera_normal(), _edit.center);
+ break;
+ case TRANSFORM_X_AXIS:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized();
+ plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
+ break;
+ case TRANSFORM_Y_AXIS:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized();
+ plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
+ break;
+ case TRANSFORM_Z_AXIS:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized();
+ plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
+ break;
+ case TRANSFORM_YZ:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized() + spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized();
+ plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized(), _edit.center);
+ plane_mv = true;
+ break;
+ case TRANSFORM_XZ:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized() + spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized();
+ plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized(), _edit.center);
+ plane_mv = true;
+ break;
+ case TRANSFORM_XY:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized() + spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized();
+ plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized(), _edit.center);
+ plane_mv = true;
+ break;
+ }
+
+ Vector3 intersection;
+ if (!plane.intersects_ray(ray_pos, ray, &intersection)) {
+ break;
+ }
+
+ Vector3 click;
+ if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) {
+ break;
+ }
+
+ Vector3 motion = intersection - click;
+ if (_edit.plane != TRANSFORM_VIEW) {
+ if (!plane_mv) {
+ motion = motion_mask.dot(motion) * motion_mask;
+
+ } else {
+ // Alternative planar scaling mode
+ if (p_shift) {
+ motion = motion_mask.dot(motion) * motion_mask;
+ }
+ }
+
+ } else {
+ const real_t center_click_dist = click.distance_to(_edit.center);
+ const real_t center_inters_dist = intersection.distance_to(_edit.center);
+ if (center_click_dist == 0) {
+ break;
+ }
+
+ const real_t scale = center_inters_dist - center_click_dist;
+ motion = Vector3(scale, scale, scale);
+ }
+
+ motion /= click.distance_to(_edit.center);
+
+ // Disable local transformation for TRANSFORM_VIEW
+ bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
+
+ if (_edit.snap || spatial_editor->is_snap_enabled()) {
+ snap = spatial_editor->get_scale_snap() / 100;
+ }
+ Vector3 motion_snapped = motion;
+ motion_snapped.snap(Vector3(snap, snap, snap));
+ // This might not be necessary anymore after issue #288 is solved (in 4.0?).
+ set_message(TTR("Scaling: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
+ String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
+ motion = _edit.original.basis.inverse().xform(motion);
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+ for (Node *E : selection) {
+ Node3D *sp = Object::cast_to<Node3D>(E);
+ if (!sp) {
+ continue;
+ }
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se) {
+ continue;
+ }
+
+ if (sp->has_meta("_edit_lock_")) {
+ continue;
+ }
+
+ if (se->gizmo.is_valid()) {
+ for (KeyValue<int, Transform3D> &GE : se->subgizmos) {
+ Transform3D xform = GE.value;
+ Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original * xform, xform, motion, snap, local_coords, true); // Force orthogonal with subgizmo.
+ if (!local_coords) {
+ new_xform = se->original.affine_inverse() * new_xform;
+ }
+ se->gizmo->set_subgizmo_transform(GE.key, new_xform);
+ }
+ } else {
+ Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original, se->original_local, motion, snap, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS);
+ _transform_gizmo_apply(se->sp, new_xform, local_coords);
+ }
+ }
+
+ spatial_editor->update_transform_gizmo();
+ surface->update();
+
+ } break;
+
+ case TRANSFORM_TRANSLATE: {
+ Vector3 motion_mask;
+ Plane plane;
+ bool plane_mv = false;
+
+ switch (_edit.plane) {
+ case TRANSFORM_VIEW:
+ plane = Plane(_get_camera_normal(), _edit.center);
+ break;
+ case TRANSFORM_X_AXIS:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized();
+ plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
+ break;
+ case TRANSFORM_Y_AXIS:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized();
+ plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
+ break;
+ case TRANSFORM_Z_AXIS:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized();
+ plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
+ break;
+ case TRANSFORM_YZ:
+ plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized(), _edit.center);
+ plane_mv = true;
+ break;
+ case TRANSFORM_XZ:
+ plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized(), _edit.center);
+ plane_mv = true;
+ break;
+ case TRANSFORM_XY:
+ plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized(), _edit.center);
+ plane_mv = true;
+ break;
+ }
+
+ Vector3 intersection;
+ if (!plane.intersects_ray(ray_pos, ray, &intersection)) {
+ break;
+ }
+
+ Vector3 click;
+ if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) {
+ break;
+ }
+
+ Vector3 motion = intersection - click;
+ if (_edit.plane != TRANSFORM_VIEW) {
+ if (!plane_mv) {
+ motion = motion_mask.dot(motion) * motion_mask;
+ }
+ }
+
+ // Disable local transformation for TRANSFORM_VIEW
+ bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
+
+ if (_edit.snap || spatial_editor->is_snap_enabled()) {
+ snap = spatial_editor->get_translate_snap();
+ }
+ Vector3 motion_snapped = motion;
+ motion_snapped.snap(Vector3(snap, snap, snap));
+ set_message(TTR("Translating: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
+ String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
+ motion = spatial_editor->get_gizmo_transform().basis.inverse().xform(motion);
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+ for (Node *E : selection) {
+ Node3D *sp = Object::cast_to<Node3D>(E);
+ if (!sp) {
+ continue;
+ }
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se) {
+ continue;
+ }
+
+ if (sp->has_meta("_edit_lock_")) {
+ continue;
+ }
+
+ if (se->gizmo.is_valid()) {
+ for (KeyValue<int, Transform3D> &GE : se->subgizmos) {
+ Transform3D xform = GE.value;
+ Transform3D new_xform = _compute_transform(TRANSFORM_TRANSLATE, se->original * xform, xform, motion, snap, local_coords, true); // Force orthogonal with subgizmo.
+ new_xform = se->original.affine_inverse() * new_xform;
+ se->gizmo->set_subgizmo_transform(GE.key, new_xform);
+ }
+ } else {
+ Transform3D new_xform = _compute_transform(TRANSFORM_TRANSLATE, se->original, se->original_local, motion, snap, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS);
+ _transform_gizmo_apply(se->sp, new_xform, false);
+ }
+ }
+
+ spatial_editor->update_transform_gizmo();
+ surface->update();
+
+ } break;
+
+ case TRANSFORM_ROTATE: {
+ Plane 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();
+ break;
+ case TRANSFORM_X_AXIS:
+ local_axis = Vector3(1, 0, 0);
+ break;
+ case TRANSFORM_Y_AXIS:
+ local_axis = Vector3(0, 1, 0);
+ break;
+ case TRANSFORM_Z_AXIS:
+ local_axis = Vector3(0, 0, 1);
+ break;
+ case TRANSFORM_YZ:
+ case TRANSFORM_XZ:
+ case TRANSFORM_XY:
+ break;
+ }
+
+ if (_edit.plane != TRANSFORM_VIEW) {
+ global_axis = spatial_editor->get_gizmo_transform().basis.xform(local_axis).normalized();
+ }
+
+ Vector3 intersection;
+ if (!plane.intersects_ray(ray_pos, ray, &intersection)) {
+ break;
+ }
+
+ Vector3 click;
+ if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) {
+ break;
+ }
+
+ static const float orthogonal_threshold = Math::cos(Math::deg2rad(87.0f));
+ bool axis_is_orthogonal = ABS(plane.normal.dot(global_axis)) < orthogonal_threshold;
+
+ double angle = 0.0f;
+ if (axis_is_orthogonal) {
+ _edit.show_rotation_line = false;
+ Vector3 projection_axis = plane.normal.cross(global_axis);
+ Vector3 delta = intersection - click;
+ float projection = delta.dot(projection_axis);
+ angle = (projection * (Math_PI / 2.0f)) / (gizmo_scale * GIZMO_CIRCLE_SIZE);
+ } else {
+ _edit.show_rotation_line = true;
+ Vector3 click_axis = (click - _edit.center).normalized();
+ Vector3 current_axis = (intersection - _edit.center).normalized();
+ angle = click_axis.signed_angle_to(current_axis, global_axis);
+ }
+
+ if (_edit.snap || spatial_editor->is_snap_enabled()) {
+ snap = spatial_editor->get_rotate_snap();
+ }
+ angle = Math::rad2deg(angle) + snap * 0.5; //else it won't reach +180
+ angle -= Math::fmod(angle, snap);
+ set_message(vformat(TTR("Rotating %s degrees."), String::num(angle, snap_step_decimals)));
+ angle = Math::deg2rad(angle);
+
+ bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+ for (Node *E : selection) {
+ Node3D *sp = Object::cast_to<Node3D>(E);
+ if (!sp) {
+ continue;
+ }
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se) {
+ continue;
+ }
+
+ if (sp->has_meta("_edit_lock_")) {
+ continue;
+ }
+
+ Vector3 compute_axis = local_coords ? local_axis : global_axis;
+ if (se->gizmo.is_valid()) {
+ for (KeyValue<int, Transform3D> &GE : se->subgizmos) {
+ Transform3D xform = GE.value;
+
+ Transform3D new_xform = _compute_transform(TRANSFORM_ROTATE, se->original * xform, xform, compute_axis, angle, local_coords, true); // Force orthogonal with subgizmo.
+ if (!local_coords) {
+ new_xform = se->original.affine_inverse() * new_xform;
+ }
+ se->gizmo->set_subgizmo_transform(GE.key, new_xform);
+ }
+ } else {
+ Transform3D new_xform = _compute_transform(TRANSFORM_ROTATE, se->original, se->original_local, compute_axis, angle, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS);
+ _transform_gizmo_apply(se->sp, new_xform, local_coords);
+ }
+ }
+
+ spatial_editor->update_transform_gizmo();
+ surface->update();
+
+ } break;
+ default: {
+ }
+ }
+}
+
Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, EditorNode *p_editor, int p_index) {
cpu_time_history_index = 0;
gpu_time_history_index = 0;
@@ -4306,6 +4462,8 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
_edit.mode = TRANSFORM_NONE;
_edit.plane = TRANSFORM_VIEW;
_edit.snap = true;
+ _edit.show_rotation_line = true;
+ _edit.instant = false;
_edit.gizmo_handle = -1;
_edit.gizmo_handle_secondary = false;
@@ -4322,15 +4480,14 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
zoom_indicator_delay = 0.0;
spatial_editor = p_spatial_editor;
- SubViewportContainer *c = memnew(SubViewportContainer);
- subviewport_container = c;
- c->set_stretch(true);
- add_child(c);
- c->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ subviewport_container = memnew(SubViewportContainer);
+ subviewport_container->set_stretch(true);
+ add_child(subviewport_container);
+ subviewport_container->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
viewport = memnew(SubViewport);
viewport->set_disable_input(true);
- c->add_child(viewport);
+ subviewport_container->add_child(viewport);
surface = memnew(Control);
surface->set_drag_forwarding(this);
add_child(surface);
@@ -4343,6 +4500,9 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
camera->make_current();
surface->set_focus_mode(FOCUS_ALL);
+ gizmo_offscreen_line = memnew(GizmoOffScreenLine);
+ subviewport_container->add_child(gizmo_offscreen_line);
+
VBoxContainer *vbox = memnew(VBoxContainer);
surface->add_child(vbox);
vbox->set_offset(SIDE_LEFT, 10 * EDSCALE);
@@ -4383,7 +4543,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
display_submenu->add_radio_check_item(TTR("Normal Buffer"), VIEW_DISPLAY_NORMAL_BUFFER);
display_submenu->add_separator();
display_submenu->add_radio_check_item(TTR("Shadow Atlas"), VIEW_DISPLAY_DEBUG_SHADOW_ATLAS);
- display_submenu->add_radio_check_item(TTR("Directional Shadow"), VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS);
+ display_submenu->add_radio_check_item(TTR("Directional Shadow Map"), VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS);
display_submenu->add_separator();
display_submenu->add_radio_check_item(TTR("Decal Atlas"), VIEW_DISPLAY_DEBUG_DECAL_ATLAS);
display_submenu->add_separator();
@@ -4399,14 +4559,14 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
display_submenu->add_radio_check_item(TTR("SSAO"), VIEW_DISPLAY_DEBUG_SSAO);
display_submenu->add_radio_check_item(TTR("SSIL"), VIEW_DISPLAY_DEBUG_SSIL);
display_submenu->add_separator();
- display_submenu->add_radio_check_item(TTR("GI Buffer"), VIEW_DISPLAY_DEBUG_GI_BUFFER);
+ display_submenu->add_radio_check_item(TTR("VoxelGI/SDFGI Buffer"), VIEW_DISPLAY_DEBUG_GI_BUFFER);
display_submenu->add_separator();
- display_submenu->add_radio_check_item(TTR("Disable LOD"), VIEW_DISPLAY_DEBUG_DISABLE_LOD);
+ display_submenu->add_radio_check_item(TTR("Disable Mesh LOD"), VIEW_DISPLAY_DEBUG_DISABLE_LOD);
display_submenu->add_separator();
- display_submenu->add_radio_check_item(TTR("Omni Light Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_OMNI_LIGHTS);
- display_submenu->add_radio_check_item(TTR("Spot Light Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_SPOT_LIGHTS);
+ display_submenu->add_radio_check_item(TTR("OmniLight3D Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_OMNI_LIGHTS);
+ display_submenu->add_radio_check_item(TTR("SpotLight3D Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_SPOT_LIGHTS);
display_submenu->add_radio_check_item(TTR("Decal Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_DECALS);
- display_submenu->add_radio_check_item(TTR("Reflection Probe Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_REFLECTION_PROBES);
+ display_submenu->add_radio_check_item(TTR("ReflectionProbe Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_REFLECTION_PROBES);
display_submenu->add_radio_check_item(TTR("Occlusion Culling Buffer"), VIEW_DISPLAY_DEBUG_OCCLUDERS);
display_submenu->set_name("display_advanced");
@@ -4465,6 +4625,16 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
ED_SHORTCUT("spatial_editor/freelook_down", TTR("Freelook Down"), Key::Q);
ED_SHORTCUT("spatial_editor/freelook_speed_modifier", TTR("Freelook Speed Modifier"), Key::SHIFT);
ED_SHORTCUT("spatial_editor/freelook_slow_modifier", TTR("Freelook Slow Modifier"), Key::ALT);
+ ED_SHORTCUT("spatial_editor/lock_transform_x", TTR("Lock Transformation to X axis"), Key::X);
+ ED_SHORTCUT("spatial_editor/lock_transform_y", TTR("Lock Transformation to Y axis"), Key::Y);
+ ED_SHORTCUT("spatial_editor/lock_transform_z", TTR("Lock Transformation to Z axis"), Key::Z);
+ ED_SHORTCUT("spatial_editor/lock_transform_yz", TTR("Lock Transformation to YZ plane"), KeyModifierMask::SHIFT | Key::X);
+ ED_SHORTCUT("spatial_editor/lock_transform_xz", TTR("Lock Transformation to XZ plane"), KeyModifierMask::SHIFT | Key::Y);
+ ED_SHORTCUT("spatial_editor/lock_transform_xy", TTR("Lock Transformation to XY plane"), KeyModifierMask::SHIFT | Key::Z);
+ ED_SHORTCUT("spatial_editor/cancel_transform", TTR("Cancel Transformation"), Key::ESCAPE);
+ ED_SHORTCUT("spatial_editor/instant_translate", TTR("Begin Translate Transformation"));
+ ED_SHORTCUT("spatial_editor/instant_rotate", TTR("Begin Rotate Transformation"));
+ ED_SHORTCUT("spatial_editor/instant_scale", TTR("Begin Scale Transformation"));
preview_camera = memnew(CheckBox);
preview_camera->set_text(TTR("Preview"));
@@ -4957,6 +5127,7 @@ void Node3DEditor::update_transform_gizmo() {
gizmo.visible = count > 0;
gizmo.transform.origin = (count > 0) ? gizmo_center / count : Vector3();
gizmo.transform.basis = (count == 1) ? gizmo_basis : Basis();
+ gizmo.target_center = gizmo_center / count;
for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
viewports[i]->update_transform_gizmo_view();
@@ -5109,6 +5280,7 @@ Dictionary Node3DEditor::get_state() const {
d["show_grid"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID));
d["show_origin"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN));
+ d["keep_gizmo_onscreen"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_KEEP_GIZMO_ONSCREEN));
d["fov"] = get_fov();
d["znear"] = get_znear();
d["zfar"] = get_zfar();
@@ -5233,6 +5405,13 @@ void Node3DEditor::set_state(const Dictionary &p_state) {
RenderingServer::get_singleton()->instance_set_visible(origin_instance, use);
}
}
+ if (d.has("keep_gizmo_onscreen")) {
+ bool use = d["keep_gizmo_onscreen"];
+
+ if (use != view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_KEEP_GIZMO_ONSCREEN))) {
+ _menu_item_pressed(MENU_KEEP_GIZMO_ONSCREEN);
+ }
+ }
if (d.has("gizmos_status")) {
Dictionary gizmos_status = d["gizmos_status"];
@@ -5586,7 +5765,13 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
_init_grid();
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), grid_enabled);
-
+ } break;
+ case MENU_KEEP_GIZMO_ONSCREEN: {
+ keep_gizmo_onscreen = !view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option));
+ for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
+ get_editor_viewport(i)->update_transform_gizmo_view();
+ }
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), keep_gizmo_onscreen);
} break;
case MENU_VIEW_CAMERA_SETTINGS: {
settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size() + Size2(50, 50));
@@ -5854,6 +6039,7 @@ void fragment() {
rotate_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
scale_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
scale_plane_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
+ axis_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D);
mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
@@ -6175,6 +6361,21 @@ void fragment() {
plane_mat_hl->set_albedo(col.from_hsv(col.get_h(), 0.25, 1.0, 1));
plane_gizmo_color_hl[i] = plane_mat_hl; // needed, so we can draw planes from both sides
}
+
+ // Lines to visualize transforms locked to an axis/plane
+ {
+ Ref<SurfaceTool> surftool = memnew(SurfaceTool);
+ surftool->begin(Mesh::PRIMITIVE_LINES);
+
+ Vector3 vec;
+ vec[i] = 1;
+
+ // line extending through infinity(ish)
+ surftool->add_vertex(vec * -99999);
+ surftool->add_vertex(vec * 99999);
+ surftool->set_material(mat_hl);
+ surftool->commit(axis_gizmo[i]);
+ }
}
}
@@ -7555,12 +7756,14 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
p->add_separator();
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTR("View Origin")), MENU_VIEW_ORIGIN);
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid"), Key::NUMBERSIGN), MENU_VIEW_GRID);
+ p->add_check_shortcut(ED_SHORTCUT("spatial_editor/keep_gizmo_onscreen", TTR("Keep Gizmo On Screen"), KeyModifierMask::CMD + KeyModifierMask::ALT + Key::G), MENU_KEEP_GIZMO_ONSCREEN);
p->add_separator();
p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings...")), MENU_VIEW_CAMERA_SETTINGS);
p->set_item_checked(p->get_item_index(MENU_VIEW_ORIGIN), true);
p->set_item_checked(p->get_item_index(MENU_VIEW_GRID), true);
+ p->set_item_checked(p->get_item_index(MENU_KEEP_GIZMO_ONSCREEN), true);
p->connect("id_pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed));
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 20a782c8a8..f14f8b90b9 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -87,6 +87,19 @@ public:
void set_viewport(Node3DEditorViewport *p_viewport);
};
+class GizmoOffScreenLine : public Control {
+ GDCLASS(GizmoOffScreenLine, Control);
+
+public:
+ Vector2 point1;
+ Vector2 point2;
+ void _notification(int p_what) {
+ if (p_what == NOTIFICATION_DRAW && is_visible()) {
+ draw_line(point1, point2, Color(0.0f, 0.75f, 0.75f), 2);
+ }
+ }
+};
+
class Node3DEditorViewport : public Control {
GDCLASS(Node3DEditorViewport, Control);
friend class Node3DEditor;
@@ -201,6 +214,7 @@ private:
CheckBox *preview_camera;
SubViewportContainer *subviewport_container;
+ GizmoOffScreenLine *gizmo_offscreen_line;
MenuButton *view_menu;
PopupMenu *display_submenu;
@@ -237,7 +251,7 @@ private:
};
void _update_name();
- void _compute_edit(const Point2 &p_point);
+ void _compute_edit(const Point2 &p_point, const bool p_auto_center = true);
void _clear_selected();
void _select_clicked(bool p_allow_locked);
ObjectID _select_ray(const Point2 &p_pos);
@@ -247,6 +261,7 @@ private:
Point2 _point_to_screen(const Vector3 &p_point);
Transform3D _get_camera_transform() const;
int get_selected_count() const;
+ void cancel_transform();
Vector3 _get_camera_position() const;
Vector3 _get_camera_normal() const;
@@ -310,10 +325,13 @@ private:
Point2 mouse_pos;
Point2 original_mouse_pos;
bool snap = false;
+ bool show_rotation_line = false;
Ref<EditorNode3DGizmo> gizmo;
int gizmo_handle = 0;
bool gizmo_handle_secondary = false;
Variant gizmo_initial_value;
+ bool original_local;
+ bool instant;
} _edit;
struct Cursor {
@@ -347,7 +365,7 @@ private:
real_t zoom_indicator_delay;
int zoom_failed_attempts_count = 0;
- RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[4], scale_gizmo_instance[3], scale_plane_gizmo_instance[3];
+ RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[4], scale_gizmo_instance[3], scale_plane_gizmo_instance[3], axis_gizmo_instance[3];
String last_message;
String message;
@@ -402,6 +420,10 @@ private:
Transform3D _compute_transform(TransformMode p_mode, const Transform3D &p_original, const Transform3D &p_original_local, Vector3 p_motion, double p_extra, bool p_local, bool p_orthogonal);
+ void begin_transform(TransformMode p_mode, bool instant);
+ void commit_transform();
+ void update_transform(Point2 p_mousepos, bool p_shift);
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -499,6 +521,35 @@ class Node3DEditor : public VBoxContainer {
public:
static const unsigned int VIEWPORTS_COUNT = 4;
+ enum MenuOption {
+ MENU_GROUP_SELECTED,
+ MENU_KEEP_GIZMO_ONSCREEN,
+ MENU_LOCK_SELECTED,
+ MENU_SNAP_TO_FLOOR,
+ MENU_TOOL_LIST_SELECT,
+ MENU_TOOL_LOCAL_COORDS,
+ MENU_TOOL_MOVE,
+ MENU_TOOL_OVERRIDE_CAMERA,
+ MENU_TOOL_ROTATE,
+ MENU_TOOL_SCALE,
+ MENU_TOOL_SELECT,
+ MENU_TOOL_USE_SNAP,
+ MENU_TRANSFORM_CONFIGURE_SNAP,
+ MENU_TRANSFORM_DIALOG,
+ MENU_UNGROUP_SELECTED,
+ MENU_UNLOCK_SELECTED,
+ MENU_VIEW_CAMERA_SETTINGS,
+ MENU_VIEW_GIZMOS_3D_ICONS,
+ MENU_VIEW_GRID,
+ MENU_VIEW_ORIGIN,
+ MENU_VIEW_USE_1_VIEWPORT,
+ MENU_VIEW_USE_2_VIEWPORTS,
+ MENU_VIEW_USE_2_VIEWPORTS_ALT,
+ MENU_VIEW_USE_3_VIEWPORTS,
+ MENU_VIEW_USE_3_VIEWPORTS_ALT,
+ MENU_VIEW_USE_4_VIEWPORTS,
+ };
+
enum ToolMode {
TOOL_MODE_SELECT,
TOOL_MODE_MOVE,
@@ -517,7 +568,6 @@ public:
TOOL_OPT_USE_SNAP,
TOOL_OPT_OVERRIDE_CAMERA,
TOOL_OPT_MAX
-
};
private:
@@ -546,7 +596,8 @@ private:
Camera3D::Projection grid_camera_last_update_perspective = Camera3D::PROJECTION_PERSPECTIVE;
Vector3 grid_camera_last_update_position = Vector3();
- Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[4], scale_gizmo[3], scale_plane_gizmo[3];
+ bool keep_gizmo_onscreen = true;
+ Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[4], scale_gizmo[3], scale_plane_gizmo[3], axis_gizmo[3];
Ref<StandardMaterial3D> gizmo_color[3];
Ref<StandardMaterial3D> plane_gizmo_color[3];
Ref<ShaderMaterial> rotate_gizmo_color[3];
@@ -579,37 +630,10 @@ private:
struct Gizmo {
bool visible = false;
real_t scale = 0;
+ Vector3 target_center;
Transform3D transform;
} gizmo;
- enum MenuOption {
- MENU_TOOL_SELECT,
- MENU_TOOL_MOVE,
- MENU_TOOL_ROTATE,
- MENU_TOOL_SCALE,
- MENU_TOOL_LIST_SELECT,
- MENU_TOOL_LOCAL_COORDS,
- MENU_TOOL_USE_SNAP,
- MENU_TOOL_OVERRIDE_CAMERA,
- MENU_TRANSFORM_CONFIGURE_SNAP,
- MENU_TRANSFORM_DIALOG,
- MENU_VIEW_USE_1_VIEWPORT,
- MENU_VIEW_USE_2_VIEWPORTS,
- MENU_VIEW_USE_2_VIEWPORTS_ALT,
- MENU_VIEW_USE_3_VIEWPORTS,
- MENU_VIEW_USE_3_VIEWPORTS_ALT,
- MENU_VIEW_USE_4_VIEWPORTS,
- MENU_VIEW_ORIGIN,
- MENU_VIEW_GRID,
- MENU_VIEW_GIZMOS_3D_ICONS,
- MENU_VIEW_CAMERA_SETTINGS,
- MENU_LOCK_SELECTED,
- MENU_UNLOCK_SELECTED,
- MENU_GROUP_SELECTED,
- MENU_UNGROUP_SELECTED,
- MENU_SNAP_TO_FLOOR
- };
-
Button *tool_button[TOOL_MAX];
Button *tool_option_button[TOOL_OPT_MAX];
@@ -768,17 +792,22 @@ public:
float get_zfar() const { return settings_zfar->get_value(); }
float get_fov() const { return settings_fov->get_value(); }
+ Vector3 get_gizmo_target_center() const { return gizmo.target_center; }
Transform3D get_gizmo_transform() const { return gizmo.transform; }
+ void set_gizmo_transform(const Transform3D &p_transform) { gizmo.transform = p_transform; }
+ bool is_keep_gizmo_onscreen_enabled() const { return keep_gizmo_onscreen; }
bool is_gizmo_visible() const;
ToolMode get_tool_mode() const { return tool_mode; }
bool are_local_coords_enabled() const { return tool_option_button[Node3DEditor::TOOL_OPT_LOCAL_COORDS]->is_pressed(); }
+ void set_local_coords_enabled(bool on) const { tool_option_button[Node3DEditor::TOOL_OPT_LOCAL_COORDS]->set_pressed(on); }
bool is_snap_enabled() const { return snap_enabled ^ snap_key_enabled; }
double get_translate_snap() const;
double get_rotate_snap() const;
double get_scale_snap() const;
Ref<ArrayMesh> get_move_gizmo(int idx) const { return move_gizmo[idx]; }
+ Ref<ArrayMesh> get_axis_gizmo(int idx) const { return axis_gizmo[idx]; }
Ref<ArrayMesh> get_move_plane_gizmo(int idx) const { return move_plane_gizmo[idx]; }
Ref<ArrayMesh> get_rotate_gizmo(int idx) const { return rotate_gizmo[idx]; }
Ref<ArrayMesh> get_scale_gizmo(int idx) const { return scale_gizmo[idx]; }
diff --git a/editor/plugins/packed_scene_translation_parser_plugin.cpp b/editor/plugins/packed_scene_translation_parser_plugin.cpp
index b492c27f41..9a8584f4a2 100644
--- a/editor/plugins/packed_scene_translation_parser_plugin.cpp
+++ b/editor/plugins/packed_scene_translation_parser_plugin.cpp
@@ -132,10 +132,7 @@ PackedSceneEditorTranslationParserPlugin::PackedSceneEditorTranslationParserPlug
lookup_properties.insert("script");
// Exception list (to prevent false positives).
- exception_list.insert("LineEdit", Vector<StringName>());
- exception_list["LineEdit"].append("text");
- exception_list.insert("TextEdit", Vector<StringName>());
- exception_list["TextEdit"].append("text");
- exception_list.insert("CodeEdit", Vector<StringName>());
- exception_list["CodeEdit"].append("text");
+ exception_list.insert("LineEdit", { "text" });
+ exception_list.insert("TextEdit", { "text" });
+ exception_list.insert("CodeEdit", { "text" });
}
diff --git a/editor/plugins/packed_scene_translation_parser_plugin.h b/editor/plugins/packed_scene_translation_parser_plugin.h
index fc19496eb6..ecd090b31b 100644
--- a/editor/plugins/packed_scene_translation_parser_plugin.h
+++ b/editor/plugins/packed_scene_translation_parser_plugin.h
@@ -37,9 +37,9 @@ class PackedSceneEditorTranslationParserPlugin : public EditorTranslationParserP
GDCLASS(PackedSceneEditorTranslationParserPlugin, EditorTranslationParserPlugin);
// Scene Node's properties that contain translation strings.
- Set<StringName> lookup_properties;
+ Set<String> lookup_properties;
// Properties from specific Nodes that should be ignored.
- Map<StringName, Vector<StringName>> exception_list;
+ Map<String, Vector<String>> exception_list;
public:
virtual Error parse_file(const String &p_path, Vector<String> *r_ids, Vector<Vector<String>> *r_ids_ctx_plural) override;
diff --git a/editor/plugins/replication_editor_plugin.cpp b/editor/plugins/replication_editor_plugin.cpp
index 93f4a853f3..fd4fc8f59c 100644
--- a/editor/plugins/replication_editor_plugin.cpp
+++ b/editor/plugins/replication_editor_plugin.cpp
@@ -258,7 +258,7 @@ void ReplicationEditor::edit(MultiplayerSynchronizer *p_sync) {
Ref<Texture2D> ReplicationEditor::_get_class_icon(const Node *p_node) {
if (!p_node || !has_theme_icon(p_node->get_class(), "EditorIcons")) {
- return get_theme_icon("ImportFail", "EditorIcons");
+ return get_theme_icon(SNAME("ImportFail"), SNAME("EditorIcons"));
}
return get_theme_icon(p_node->get_class(), "EditorIcons");
}
@@ -285,7 +285,7 @@ void ReplicationEditor::_add_property(const NodePath &p_property, bool p_spawn,
icon = _get_class_icon(node);
}
item->set_icon(0, icon);
- item->add_button(3, get_theme_icon("Remove", "EditorIcons"));
+ item->add_button(3, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
item->set_text_alignment(1, HORIZONTAL_ALIGNMENT_CENTER);
item->set_cell_mode(1, TreeItem::CELL_MODE_CHECK);
item->set_checked(1, p_spawn);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 26227fa5bb..17de3ba026 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -2265,7 +2265,7 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
if (use_external_editor &&
(EditorDebuggerNode::get_singleton()->get_dump_stack_script() != p_resource || EditorDebuggerNode::get_singleton()->get_debug_with_external_editor()) &&
p_resource->get_path().is_resource_file() &&
- p_resource->get_class_name() != StringName("VisualScript")) {
+ !Ref<VisualScript>(p_resource).is_valid()) {
String path = EditorSettings::get_singleton()->get("text_editor/external/exec_path");
String flags = EditorSettings::get_singleton()->get("text_editor/external/exec_flags");
@@ -2364,7 +2364,7 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
se->set_edited_resource(p_resource);
- if (p_resource->get_class_name() != StringName("VisualScript")) {
+ if (!Ref<VisualScript>(p_resource).is_valid()) {
bool highlighter_set = false;
for (int i = 0; i < syntax_highlighters.size(); i++) {
Ref<EditorSyntaxHighlighter> highlighter = syntax_highlighters[i]->_create();
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 7b4ebbc6d8..c3d61dfd58 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -930,21 +930,22 @@ void ScriptTextEditor::_update_connected_methods() {
continue;
}
- if (methods_found.has(connection.callable.get_method())) {
+ const StringName method = connection.callable.get_method();
+ if (methods_found.has(method)) {
continue;
}
- if (!ClassDB::has_method(script->get_instance_base_type(), connection.callable.get_method())) {
+ if (!ClassDB::has_method(script->get_instance_base_type(), method)) {
int line = -1;
for (int j = 0; j < functions.size(); j++) {
String name = functions[j].get_slice(":", 0);
- if (name == connection.callable.get_method()) {
+ if (name == method) {
line = functions[j].get_slice(":", 1).to_int() - 1;
- text_edit->set_line_gutter_metadata(line, connection_gutter, connection.callable.get_method());
+ text_edit->set_line_gutter_metadata(line, connection_gutter, method);
text_edit->set_line_gutter_icon(line, connection_gutter, get_parent_control()->get_theme_icon(SNAME("Slot"), SNAME("EditorIcons")));
text_edit->set_line_gutter_clickable(line, connection_gutter, true);
- methods_found.insert(connection.callable.get_method());
+ methods_found.insert(method);
break;
}
}
@@ -957,7 +958,7 @@ void ScriptTextEditor::_update_connected_methods() {
bool found_inherited_function = false;
Ref<Script> inherited_script = script->get_base_script();
while (!inherited_script.is_null()) {
- if (inherited_script->has_method(connection.callable.get_method())) {
+ if (inherited_script->has_method(method)) {
found_inherited_function = true;
break;
}
@@ -1373,7 +1374,7 @@ void ScriptTextEditor::reload(bool p_soft) {
return;
}
scr->set_source_code(te->get_text());
- bool soft = p_soft || scr->get_instance_base_type() == "EditorPlugin"; //always soft-reload editor plugins
+ bool soft = p_soft || scr->get_instance_base_type() == "EditorPlugin"; // Always soft-reload editor plugins.
scr->get_language()->reload_tool_script(scr, soft);
}
diff --git a/editor/plugins/text_control_editor_plugin.cpp b/editor/plugins/text_control_editor_plugin.cpp
index 87eff9c3e9..4ce94176e5 100644
--- a/editor/plugins/text_control_editor_plugin.cpp
+++ b/editor/plugins/text_control_editor_plugin.cpp
@@ -110,7 +110,7 @@ void TextControlEditor::_update_styles_menu() {
for (Map<String, String>::Element *E = fonts[name].front(); E; E = E->next()) {
font_style_list->add_item(E->key());
}
- } else {
+ } else if (font_list->get_selected() >= 0) {
font_style_list->add_item("Default");
}
@@ -123,9 +123,9 @@ void TextControlEditor::_update_styles_menu() {
void TextControlEditor::_update_control() {
if (!edited_controls.is_empty()) {
- int font_selected = 0;
+ String font_selected;
bool same_font = true;
- int style_selected = 0;
+ String style_selected;
bool same_style = true;
int font_size = 0;
bool same_font_size = true;
@@ -136,26 +136,23 @@ void TextControlEditor::_update_control() {
Color outline_color = Color{ 1.0f, 1.0f, 1.0f };
bool same_outline_color = true;
- _update_fonts_menu();
- _update_styles_menu();
-
int count = edited_controls.size();
for (int i = 0; i < count; ++i) {
Control *edited_control = edited_controls[i];
- String edited_color;
- String edited_font;
- String edited_font_size;
+ StringName edited_color;
+ StringName edited_font;
+ StringName edited_font_size;
// Get override names.
- if (edited_control->is_class("RichTextLabel")) {
- edited_color = "default_color";
- edited_font = "normal_font";
- edited_font_size = "normal_font_size";
+ if (Object::cast_to<RichTextLabel>(edited_control)) {
+ edited_color = SNAME("default_color");
+ edited_font = SNAME("normal_font");
+ edited_font_size = SNAME("normal_font_size");
} else {
- edited_color = "font_color";
- edited_font = "font";
- edited_font_size = "font_size";
+ edited_color = SNAME("font_color");
+ edited_font = SNAME("font");
+ edited_font_size = SNAME("font_size");
}
// Get font override.
@@ -166,63 +163,46 @@ void TextControlEditor::_update_control() {
if (font.is_valid()) {
if (font->get_data_count() != 1) {
- custom_font = font;
if (i > 0) {
- same_font = same_font && (font_selected == FONT_INFO_USER_CUSTOM);
- same_style = same_style && (style_selected == 0);
+ same_font = same_font && (custom_font == font);
}
+ custom_font = font;
- font_selected = FONT_INFO_USER_CUSTOM;
- style_selected = 0;
+ font_selected = TTR("[Custom Font]");
+ same_style = false;
} else {
String name = font->get_data(0)->get_font_name();
String style = font->get_data(0)->get_font_style_name();
if (fonts.has(name) && fonts[name].has(style)) {
- for (int j = 0; j < font_list->get_item_count(); j++) {
- if (font_list->get_item_text(j) == name) {
- if (i > 0) {
- same_font = same_font && (j == font_selected);
- }
-
- font_selected = j;
- break;
- }
- }
- for (int j = 0; j < font_style_list->get_item_count(); j++) {
- if (font_style_list->get_item_text(j) == style) {
- if (i > 0) {
- same_style = same_style && (j == style_selected);
- }
-
- style_selected = j;
- break;
- }
+ if (i > 0) {
+ same_font = same_font && (name == font_selected);
+ same_style = same_style && (style == style_selected);
}
+ font_selected = name;
+ style_selected = style;
} else {
- custom_font = font;
if (i > 0) {
- same_font = same_font && (font_selected == FONT_INFO_USER_CUSTOM);
- same_style = same_style && (style_selected == 0);
+ same_font = same_font && (custom_font == font);
}
+ custom_font = font;
- font_selected = FONT_INFO_USER_CUSTOM;
- style_selected = 0;
+ font_selected = TTR("[Custom Font]");
+ same_style = false;
}
}
} else {
if (i > 0) {
- same_font = same_font && (font_selected == FONT_INFO_THEME_DEFAULT);
- same_style = same_style && (style_selected == 0);
+ same_font = same_font && (font_selected == TTR("[Theme Default]"));
}
- font_selected = FONT_INFO_THEME_DEFAULT;
- style_selected = 0;
+ font_selected = TTR("[Theme Default]");
+ same_style = false;
}
int current_font_size = edited_control->get_theme_font_size(edited_font_size);
- int current_outline_size = edited_control->get_theme_constant("outline_size");
+ int current_outline_size = edited_control->get_theme_constant(SNAME("outline_size"));
Color current_font_color = edited_control->get_theme_color(edited_color);
- Color current_outline_color = edited_control->get_theme_color("font_outline_color");
+ Color current_outline_color = edited_control->get_theme_color(SNAME("font_outline_color"));
if (i > 0) {
same_font_size = same_font_size && (font_size == current_font_size);
same_outline_size = same_outline_size && (outline_size == current_outline_size);
@@ -235,19 +215,29 @@ void TextControlEditor::_update_control() {
font_color = current_font_color;
outline_color = current_outline_color;
}
-
_update_fonts_menu();
if (same_font) {
- font_list->select(font_selected);
+ for (int j = 0; j < font_list->get_item_count(); j++) {
+ if (font_list->get_item_text(j) == font_selected) {
+ font_list->select(j);
+ break;
+ }
+ }
} else {
+ custom_font = Ref<Font>();
font_list->select(-1);
}
_update_styles_menu();
if (same_style) {
- font_style_list->select(style_selected);
+ for (int j = 0; j < font_style_list->get_item_count(); j++) {
+ if (font_style_list->get_item_text(j) == style_selected) {
+ font_style_list->select(j);
+ break;
+ }
+ }
} else {
- font_list->select(-1);
+ font_style_list->select(-1);
}
// Get other theme overrides.
@@ -282,6 +272,7 @@ void TextControlEditor::_update_control() {
}
void TextControlEditor::_font_selected(int p_id) {
+ _update_styles_menu();
_set_font();
}
@@ -301,11 +292,11 @@ void TextControlEditor::_set_font() {
for (int i = 0; i < count; ++i) {
Control *edited_control = edited_controls[i];
- String edited_font;
- if (edited_control->is_class("RichTextLabel")) {
- edited_font = "normal_font";
+ StringName edited_font;
+ if (Object::cast_to<RichTextLabel>(edited_control)) {
+ edited_font = SNAME("normal_font");
} else {
- edited_font = "font";
+ edited_font = SNAME("font");
}
if (font_list->get_selected_id() == FONT_INFO_THEME_DEFAULT) {
@@ -314,14 +305,13 @@ void TextControlEditor::_set_font() {
} else if (font_list->get_selected_id() == FONT_INFO_USER_CUSTOM) {
// Restore "custom_font".
ur->add_do_method(edited_control, "add_theme_font_override", edited_font, custom_font);
- } else {
+ } else if (font_list->get_selected() >= 0) {
// Load new font resource using selected name and style.
String name = font_list->get_item_text(font_list->get_selected());
String style = font_style_list->get_item_text(font_style_list->get_selected());
if (style.is_empty()) {
style = "Default";
}
-
if (fonts.has(name)) {
Ref<FontData> fd = ResourceLoader::load(fonts[name][style]);
if (fd.is_valid()) {
@@ -358,11 +348,11 @@ void TextControlEditor::_font_size_selected(double p_size) {
for (int i = 0; i < count; ++i) {
Control *edited_control = edited_controls[i];
- String edited_font_size;
- if (edited_control->is_class("RichTextLabel")) {
- edited_font_size = "normal_font_size";
+ StringName edited_font_size;
+ if (Object::cast_to<RichTextLabel>(edited_control)) {
+ edited_font_size = SNAME("normal_font_size");
} else {
- edited_font_size = "font_size";
+ edited_font_size = SNAME("font_size");
}
ur->add_do_method(edited_control, "add_theme_font_size_override", edited_font_size, p_size);
@@ -393,7 +383,7 @@ void TextControlEditor::_outline_size_selected(double p_size) {
ur->add_do_method(edited_control, "add_theme_constant_override", "outline_size", p_size);
if (edited_control->has_theme_constant_override("outline_size")) {
- ur->add_undo_method(edited_control, "add_theme_constant_override", "outline_size", edited_control->get_theme_constant("outline_size"));
+ ur->add_undo_method(edited_control, "add_theme_constant_override", "outline_size", edited_control->get_theme_constant(SNAME("outline_size")));
} else {
ur->add_undo_method(edited_control, "remove_theme_constant_override", "outline_size");
}
@@ -417,11 +407,11 @@ void TextControlEditor::_font_color_changed(const Color &p_color) {
for (int i = 0; i < count; ++i) {
Control *edited_control = edited_controls[i];
- String edited_color;
- if (edited_control->is_class("RichTextLabel")) {
- edited_color = "default_color";
+ StringName edited_color;
+ if (Object::cast_to<RichTextLabel>(edited_control)) {
+ edited_color = SNAME("default_color");
} else {
- edited_color = "font_color";
+ edited_color = SNAME("font_color");
}
ur->add_do_method(edited_control, "add_theme_color_override", edited_color, p_color);
@@ -452,7 +442,7 @@ void TextControlEditor::_outline_color_changed(const Color &p_color) {
ur->add_do_method(edited_control, "add_theme_color_override", "font_outline_color", p_color);
if (edited_control->has_theme_color_override("font_outline_color")) {
- ur->add_undo_method(edited_control, "add_theme_color_override", "font_outline_color", edited_control->get_theme_color("font_outline_color"));
+ ur->add_undo_method(edited_control, "add_theme_color_override", "font_outline_color", edited_control->get_theme_color(SNAME("font_outline_color")));
} else {
ur->add_undo_method(edited_control, "remove_theme_color_override", "font_outline_color");
}
@@ -476,19 +466,19 @@ void TextControlEditor::_clear_formatting() {
for (int i = 0; i < count; ++i) {
Control *edited_control = edited_controls[i];
- String edited_color;
- String edited_font;
- String edited_font_size;
+ StringName edited_color;
+ StringName edited_font;
+ StringName edited_font_size;
// Get override names.
- if (edited_control->is_class("RichTextLabel")) {
- edited_color = "default_color";
- edited_font = "normal_font";
- edited_font_size = "normal_font_size";
+ if (Object::cast_to<RichTextLabel>(edited_control)) {
+ edited_color = SNAME("default_color");
+ edited_font = SNAME("normal_font");
+ edited_font_size = SNAME("normal_font_size");
} else {
- edited_color = "font_color";
- edited_font = "font";
- edited_font_size = "font_size";
+ edited_color = SNAME("font_color");
+ edited_font = SNAME("font");
+ edited_font_size = SNAME("font_size");
}
ur->add_do_method(edited_control, "begin_bulk_theme_override");
@@ -511,12 +501,12 @@ void TextControlEditor::_clear_formatting() {
ur->add_do_method(edited_control, "remove_theme_color_override", "font_outline_color");
if (edited_control->has_theme_color_override("font_outline_color")) {
- ur->add_undo_method(edited_control, "add_theme_color_override", "font_outline_color", edited_control->get_theme_color("font_outline_color"));
+ ur->add_undo_method(edited_control, "add_theme_color_override", "font_outline_color", edited_control->get_theme_color(SNAME("font_outline_color")));
}
ur->add_do_method(edited_control, "remove_theme_constant_override", "outline_size");
if (edited_control->has_theme_constant_override("outline_size")) {
- ur->add_undo_method(edited_control, "add_theme_constant_override", "outline_size", edited_control->get_theme_constant("outline_size"));
+ ur->add_undo_method(edited_control, "add_theme_constant_override", "outline_size", edited_control->get_theme_constant(SNAME("outline_size")));
}
ur->add_do_method(edited_control, "end_bulk_theme_override");
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index d1797e7400..dd19f3d781 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -2584,7 +2584,7 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
vsnode = Ref<VisualShaderNode>(vsn);
} else {
ERR_FAIL_COND(add_options[p_idx].script.is_null());
- String base_type = add_options[p_idx].script->get_instance_base_type();
+ StringName base_type = add_options[p_idx].script->get_instance_base_type();
VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(base_type));
ERR_FAIL_COND(!vsn);
vsnode = Ref<VisualShaderNode>(vsn);
@@ -4783,11 +4783,11 @@ VisualShaderEditor::VisualShaderEditor() {
// SDF
{
- add_options.push_back(AddOption("ScreenUVToSDF", "SDF", "", "VisualShaderNodeScreenUVToSDF", TTR("Converts screen UV to a SDF."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("ScreenUVToSDF", "SDF", "", "VisualShaderNodeScreenUVToSDF", TTR("Converts screen UV to a SDF."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("SDFRaymarch", "SDF", "", "VisualShaderNodeSDFRaymarch", TTR("Casts a ray against the screen SDF and returns the distance travelled."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("SDFToScreenUV", "SDF", "", "VisualShaderNodeSDFToScreenUV", TTR("Converts a SDF to screen UV."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("SDFToScreenUV", "SDF", "", "VisualShaderNodeSDFToScreenUV", TTR("Converts a SDF to screen UV."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("TextureSDF", "SDF", "", "VisualShaderNodeTextureSDF", TTR("Performs a SDF texture lookup."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("TextureSDFNormal", "SDF", "", "VisualShaderNodeTextureSDFNormal", TTR("Performs a SDF normal texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("TextureSDFNormal", "SDF", "", "VisualShaderNodeTextureSDFNormal", TTR("Performs a SDF normal texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
}
// TEXTURES
@@ -4971,8 +4971,8 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Subtract", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Subtracts 3D vector from 3D vector."), { VisualShaderNodeVectorOp::OP_SUB, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("Vector2Constant", "Vector", "Variables", "VisualShaderNodeVec2Constant", TTR("2D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
- add_options.push_back(AddOption("Vector3Constant", "Vector", "Variables", "VisualShaderNodeVec3Constant", TTR("3D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("Vector2Uniform", "Vector", "Variables", "VisualShaderNodeVec2Uniform", TTR("2D vector uniform."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Vector3Constant", "Vector", "Variables", "VisualShaderNodeVec3Constant", TTR("3D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("Vector3Uniform", "Vector", "Variables", "VisualShaderNodeVec3Uniform", TTR("3D vector uniform."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
// SPECIAL