diff --git a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp index 79f46f7bf70c..b967cb7ccd60 100644 --- a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp @@ -134,6 +134,11 @@ Variant CollisionShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p return Variant(); } +void CollisionShape3DGizmoPlugin::begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) { + initial_transform = p_gizmo->get_node_3d()->get_global_transform(); + initial_value = get_handle_value(p_gizmo, p_id, p_secondary); +} + void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { CollisionShape3D *cs = Object::cast_to(p_gizmo->get_node_3d()); @@ -142,7 +147,7 @@ void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i return; } - Transform3D gt = cs->get_global_transform(); + Transform3D gt = initial_transform; Transform3D gi = gt.affine_inverse(); Vector3 ray_from = p_camera->project_ray_origin(p_point); @@ -184,22 +189,37 @@ void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i if (Object::cast_to(*s)) { Vector3 axis; - axis[p_id] = 1.0; + axis[p_id / 2] = 1.0; Ref bs = s; Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); - float d = ra[p_id] * 2; - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } + int sign = p_id % 2 * -2 + 1; + Vector3 initial_size = initial_value; - if (d < 0.001) { - d = 0.001; + Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096 * sign, sg[0], sg[1], ra, rb); + if (ra[p_id / 2] == 0) { + // Point before half of the shape. Needs to be calculated in opposite direction. + Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096 * -sign, sg[0], sg[1], ra, rb); } + float d = ra[p_id / 2] * sign; + Vector3 he = bs->get_size(); - he[p_id] = d; - bs->set_size(he); + he[p_id / 2] = d * 2; + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + he[p_id / 2] = Math::snapped(he[p_id / 2], Node3DEditor::get_singleton()->get_translate_snap()); + } + + if (Input::get_singleton()->is_key_pressed(Key::ALT)) { + he[p_id / 2] = MAX(he[p_id / 2], 0.001); + bs->set_size(he); + cs->set_global_position(initial_transform.get_origin()); + } else { + he[p_id / 2] = MAX(he[p_id / 2], -initial_size[p_id / 2] + 0.002); + bs->set_size((initial_size + (he - initial_size) * 0.5).abs()); + Vector3 pos = initial_transform.affine_inverse().xform(initial_transform.get_origin()); + pos += (bs->get_size() - initial_size) * 0.5 * sign; + cs->set_global_position(initial_transform.xform(pos)); + } } if (Object::cast_to(*s)) { @@ -273,6 +293,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo if (Object::cast_to(*s)) { Ref ss = s; if (p_cancel) { + cs->set_global_position(initial_transform.get_origin()); ss->set_size(p_restore); return; } @@ -280,7 +301,9 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Change Box Shape Size")); ur->add_do_method(ss.ptr(), "set_size", ss->get_size()); + ur->add_do_method(cs, "set_position", cs->get_global_position()); ur->add_undo_method(ss.ptr(), "set_size", p_restore); + ur->add_undo_method(cs, "set_global_position", initial_transform.get_origin()); ur->commit_action(); } @@ -429,6 +452,7 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { Vector3 ax; ax[i] = bs->get_size()[i] / 2; handles.push_back(ax); + handles.push_back(-ax); } p_gizmo->add_lines(lines, material); diff --git a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h index 520295a522c1..6b7740de2f53 100644 --- a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h +++ b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h @@ -36,6 +36,9 @@ class CollisionShape3DGizmoPlugin : public EditorNode3DGizmoPlugin { GDCLASS(CollisionShape3DGizmoPlugin, EditorNode3DGizmoPlugin); + Transform3D initial_transform; + Variant initial_value; + public: bool has_gizmo(Node3D *p_spatial) override; String get_gizmo_name() const override; @@ -44,6 +47,7 @@ class CollisionShape3DGizmoPlugin : public EditorNode3DGizmoPlugin { String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override; + void begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) override; void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override; void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override; diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index 0da6fd3c4136..2a91d9f10890 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -115,6 +115,15 @@ Variant EditorNode3DGizmo::get_handle_value(int p_id, bool p_secondary) const { return gizmo_plugin->get_handle_value(this, p_id, p_secondary); } +void EditorNode3DGizmo::begin_handle_action(int p_id, bool p_secondary) { + if (GDVIRTUAL_CALL(_begin_handle_action, p_id, p_secondary)) { + return; + } + + ERR_FAIL_COND(!gizmo_plugin); + gizmo_plugin->begin_handle_action(this, p_id, p_secondary); +} + void EditorNode3DGizmo::set_handle(int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { if (GDVIRTUAL_CALL(_set_handle, p_id, p_secondary, p_camera, p_point)) { return; @@ -1095,6 +1104,10 @@ Variant EditorNode3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_giz return ret; } +void EditorNode3DGizmoPlugin::begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) { + GDVIRTUAL_CALL(_begin_handle_action, Ref(p_gizmo), p_id, p_secondary); +} + void EditorNode3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { GDVIRTUAL_CALL(_set_handle, Ref(p_gizmo), p_id, p_secondary, p_camera, p_point); } diff --git a/editor/plugins/node_3d_editor_gizmos.h b/editor/plugins/node_3d_editor_gizmos.h index ae2214de9881..d7c368d5d017 100644 --- a/editor/plugins/node_3d_editor_gizmos.h +++ b/editor/plugins/node_3d_editor_gizmos.h @@ -83,6 +83,7 @@ class EditorNode3DGizmo : public Node3DGizmo { GDVIRTUAL2RC(String, _get_handle_name, int, bool) GDVIRTUAL2RC(bool, _is_handle_highlighted, int, bool) GDVIRTUAL2RC(Variant, _get_handle_value, int, bool) + GDVIRTUAL2(_begin_handle_action, int, bool) GDVIRTUAL4(_set_handle, int, bool, const Camera3D *, Vector2) GDVIRTUAL4(_commit_handle, int, bool, Variant, bool) @@ -104,6 +105,7 @@ class EditorNode3DGizmo : public Node3DGizmo { virtual bool is_handle_highlighted(int p_id, bool p_secondary) const; virtual String get_handle_name(int p_id, bool p_secondary) const; virtual Variant get_handle_value(int p_id, bool p_secondary) const; + virtual void begin_handle_action(int p_id, bool p_secondary); virtual void set_handle(int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point); virtual void commit_handle(int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false); @@ -170,6 +172,7 @@ class EditorNode3DGizmoPlugin : public Resource { GDVIRTUAL3RC(bool, _is_handle_highlighted, Ref, int, bool) GDVIRTUAL3RC(Variant, _get_handle_value, Ref, int, bool) + GDVIRTUAL3(_begin_handle_action, Ref, int, bool) GDVIRTUAL5(_set_handle, Ref, int, bool, const Camera3D *, Vector2) GDVIRTUAL5(_commit_handle, Ref, int, bool, Variant, bool) @@ -196,6 +199,7 @@ class EditorNode3DGizmoPlugin : public Resource { virtual bool is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const; virtual String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const; virtual Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const; + virtual void begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary); virtual void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point); virtual void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 68d3661d10a6..78805324c9dd 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -1775,6 +1775,7 @@ void Node3DEditorViewport::_sinput(const Ref &p_event) { seg->handles_intersect_ray(camera, _edit.mouse_pos, b->is_shift_pressed(), gizmo_handle, gizmo_secondary); if (gizmo_handle != -1) { _edit.gizmo = seg; + seg->begin_handle_action(gizmo_handle, gizmo_secondary); _edit.gizmo_handle = gizmo_handle; _edit.gizmo_handle_secondary = gizmo_secondary; _edit.gizmo_initial_value = seg->get_handle_value(gizmo_handle, gizmo_secondary); @@ -2152,7 +2153,7 @@ void Node3DEditorViewport::_sinput(const Ref &p_event) { } if (_edit.mode == TRANSFORM_NONE) { - if (_edit.gizmo.is_valid()) { + 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); _edit.gizmo = Ref();