diff --git a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp index 81b0ebcdc25..4b8fd261816 100644 --- a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp @@ -115,7 +115,7 @@ String CollisionShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_g } if (Object::cast_to(*s)) { - return p_id == 0 ? "Radius" : "Height"; + return helper->capsule_get_handle_name(p_id); } if (Object::cast_to(*s)) { @@ -154,7 +154,7 @@ Variant CollisionShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p if (Object::cast_to(*s)) { Ref cs2 = s; - return p_id == 0 ? cs2->get_radius() : cs2->get_height(); + return Vector2(cs2->get_radius(), cs2->get_height()); } if (Object::cast_to(*s)) { @@ -222,26 +222,15 @@ void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i } if (Object::cast_to(*s)) { - Vector3 axis; - axis[p_id == 0 ? 0 : 1] = 1.0; Ref cs2 = s; - Vector3 ra, rb; - Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); - float d = axis.dot(ra); - if (Node3DEditor::get_singleton()->is_snap_enabled()) { - d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); - } - - if (d < 0.001) { - d = 0.001; - } - - if (p_id == 0) { - cs2->set_radius(d); - } else if (p_id == 1) { - cs2->set_height(d * 2.0); - } + real_t height = cs2->get_height(); + real_t radius = cs2->get_radius(); + Vector3 position; + helper->capsule_set_handle(sg, p_id, height, radius, position); + cs2->set_height(height); + cs2->set_radius(radius); + cs->set_global_position(position); } if (Object::cast_to(*s)) { @@ -285,26 +274,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo if (Object::cast_to(*s)) { Ref ss = s; - Vector2 values = p_restore; - - if (p_cancel) { - ss->set_radius(values[0]); - ss->set_height(values[1]); - return; - } - - EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); - if (p_id == 0) { - ur->create_action(TTR("Change Capsule Shape Radius")); - ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); - } else { - ur->create_action(TTR("Change Capsule Shape Height")); - ur->add_do_method(ss.ptr(), "set_height", ss->get_height()); - } - ur->add_undo_method(ss.ptr(), "set_radius", values[0]); - ur->add_undo_method(ss.ptr(), "set_height", values[1]); - - ur->commit_action(); + helper->cylinder_commit_handle(p_id, TTR("Change Capsule Shape Radius"), TTR("Change Capsule Shape Height"), p_cancel, cs, *ss, *ss); } if (Object::cast_to(*s)) { @@ -547,10 +517,7 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { p_gizmo->add_lines(points, material, false, collision_color); p_gizmo->add_collision_segments(points); - Vector handles = { - Vector3(cs2->get_radius(), 0, 0), - Vector3(0, cs2->get_height() * 0.5, 0) - }; + Vector handles = helper->capsule_get_handles(cs2->get_height(), cs2->get_radius()); p_gizmo->add_handles(handles, handles_material); } diff --git a/editor/plugins/gizmos/gizmo_3d_helper.cpp b/editor/plugins/gizmos/gizmo_3d_helper.cpp index ff1b67aa4a6..220ddea206d 100644 --- a/editor/plugins/gizmos/gizmo_3d_helper.cpp +++ b/editor/plugins/gizmos/gizmo_3d_helper.cpp @@ -156,7 +156,10 @@ String Gizmo3DHelper::cylinder_get_handle_name(int p_id) const { } } -void Gizmo3DHelper::cylinder_set_handle(const Vector3 p_segment[2], int p_id, real_t &r_height, real_t &r_radius, Vector3 &r_cylinder_position) { +void Gizmo3DHelper::_cylinder_or_capsule_set_handle(const Vector3 p_segment[2], int p_id, real_t &r_height, real_t &r_radius, Vector3 &r_cylinder_position, bool p_is_capsule) { + real_t initial_radius = initial_value.operator Vector2().x; + real_t initial_height = initial_value.operator Vector2().y; + int sign = p_id == 2 ? -1 : 1; int axis = p_id == 0 ? 0 : 1; @@ -178,9 +181,13 @@ void Gizmo3DHelper::cylinder_set_handle(const Vector3 p_segment[2], int p_id, re } r_radius = d; r_cylinder_position = initial_transform.get_origin(); - } else if (p_id == 1 || p_id == 2) { - real_t initial_height = initial_value; + if (p_is_capsule) { + r_height = MAX(initial_height, r_radius * 2.0); + } else { + r_height = initial_height; + } + } else if (p_id == 1 || p_id == 2) { // Adjust height. if (Input::get_singleton()->is_key_pressed(Key::ALT)) { r_height = d * 2.0; @@ -200,6 +207,12 @@ void Gizmo3DHelper::cylinder_set_handle(const Vector3 p_segment[2], int p_id, re offset[axis] = (r_height - initial_height) * 0.5 * sign; r_cylinder_position = initial_transform.xform(offset); } + + if (p_is_capsule) { + r_radius = MIN(initial_radius, r_height / 2.0); + } else { + r_radius = initial_radius; + } } } @@ -212,25 +225,19 @@ void Gizmo3DHelper::cylinder_commit_handle(int p_id, const String &p_radius_acti } if (p_cancel) { - if (p_id == 0) { - p_radius_object->set(p_radius_property, initial_value); - } else { - p_height_object->set(p_height_property, initial_value); - } + p_radius_object->set(p_radius_property, initial_value.operator Vector2().x); + p_height_object->set(p_height_property, initial_value.operator Vector2().y); p_position_object->set(p_position_property, initial_transform.get_origin()); return; } EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(p_id == 0 ? p_radius_action_name : p_height_action_name); - if (p_id == 0) { - ur->add_do_property(p_radius_object, p_radius_property, p_radius_object->get(p_radius_property)); - ur->add_undo_property(p_radius_object, p_radius_property, initial_value); - } else { - ur->add_do_property(p_height_object, p_height_property, p_height_object->get(p_height_property)); - ur->add_do_property(p_position_object, p_position_property, p_position_object->get(p_position_property)); - ur->add_undo_property(p_height_object, p_height_property, initial_value); - ur->add_undo_property(p_position_object, p_position_property, initial_transform.get_origin()); - } + ur->add_do_property(p_radius_object, p_radius_property, p_radius_object->get(p_radius_property)); + ur->add_undo_property(p_radius_object, p_radius_property, initial_value.operator Vector2().x); + ur->add_do_property(p_height_object, p_height_property, p_height_object->get(p_height_property)); + ur->add_undo_property(p_height_object, p_height_property, initial_value.operator Vector2().y); + ur->add_do_property(p_position_object, p_position_property, p_position_object->get(p_position_property)); + ur->add_undo_property(p_position_object, p_position_property, initial_transform.get_origin()); ur->commit_action(); } diff --git a/editor/plugins/gizmos/gizmo_3d_helper.h b/editor/plugins/gizmos/gizmo_3d_helper.h index 7eb73d2438a..21d3747da08 100644 --- a/editor/plugins/gizmos/gizmo_3d_helper.h +++ b/editor/plugins/gizmos/gizmo_3d_helper.h @@ -41,17 +41,44 @@ class Gizmo3DHelper : public RefCounted { Variant initial_value; Transform3D initial_transform; +private: + void _cylinder_or_capsule_set_handle(const Vector3 p_segment[2], int p_id, real_t &r_height, real_t &r_radius, Vector3 &r_cylinder_position, bool p_is_capsule); + public: + /** + * Initializes a new action involving a handle. + * + * Depending on the type of gizmo that will be used, different formats for the `p_initial_value` are required: + * Box: The size of the box as `Vector3` + * Cylinder or Capsule: A `Vector2` of the form `Vector2(radius, height)` + */ void initialize_handle_action(const Variant &p_initial_value, const Transform3D &p_initial_transform); void get_segment(Camera3D *p_camera, const Point2 &p_point, Vector3 *r_segment); + // Box + Vector box_get_handles(const Vector3 &p_box_size); String box_get_handle_name(int p_id) const; void box_set_handle(const Vector3 p_segment[2], int p_id, Vector3 &r_box_size, Vector3 &r_box_position); void box_commit_handle(const String &p_action_name, bool p_cancel, Object *p_position_object, Object *p_size_object = nullptr, const StringName &p_position_property = "global_position", const StringName &p_size_property = "size"); + // Cylinder + Vector cylinder_get_handles(real_t p_height, real_t p_radius); String cylinder_get_handle_name(int p_id) const; - void cylinder_set_handle(const Vector3 p_segment[2], int p_id, real_t &r_height, real_t &r_radius, Vector3 &r_cylinder_position); + _FORCE_INLINE_ void cylinder_set_handle(const Vector3 p_segment[2], int p_id, real_t &r_height, real_t &r_radius, Vector3 &r_cylinder_position) { + _cylinder_or_capsule_set_handle(p_segment, p_id, r_height, r_radius, r_cylinder_position, false); + } void cylinder_commit_handle(int p_id, const String &p_radius_action_name, const String &p_height_action_name, bool p_cancel, Object *p_position_object, Object *p_height_object = nullptr, Object *p_radius_object = nullptr, const StringName &p_position_property = "global_position", const StringName &p_height_property = "height", const StringName &p_radius_property = "radius"); + + // Capsule + + _FORCE_INLINE_ Vector capsule_get_handles(real_t p_height, real_t p_radius) { return cylinder_get_handles(p_height, p_radius); } + _FORCE_INLINE_ String capsule_get_handle_name(int p_id) { return cylinder_get_handle_name(p_id); } + _FORCE_INLINE_ void capsule_set_handle(const Vector3 p_segment[2], int p_id, real_t &r_height, real_t &r_radius, Vector3 &r_capsule_position) { + _cylinder_or_capsule_set_handle(p_segment, p_id, r_height, r_radius, r_capsule_position, true); + } + _FORCE_INLINE_ void capsule_commit_handle(int p_id, const String &p_radius_action_name, const String &p_height_action_name, bool p_cancel, Object *p_position_object, Object *p_height_object = nullptr, Object *p_radius_object = nullptr, const StringName &p_position_property = "global_position", const StringName &p_height_property = "height", const StringName &p_radius_property = "radius") { + cylinder_commit_handle(p_id, p_radius_action_name, p_height_action_name, p_cancel, p_position_object, p_height_object, p_radius_object, p_position_property, p_height_property, p_radius_property); + } }; diff --git a/modules/csg/editor/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp index 59ccd4293e8..ed21d13b925 100644 --- a/modules/csg/editor/csg_gizmos.cpp +++ b/modules/csg/editor/csg_gizmos.cpp @@ -222,7 +222,7 @@ Variant CSGShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo if (Object::cast_to(cs)) { CSGCylinder3D *s = Object::cast_to(cs); - return p_id == 0 ? s->get_radius() : s->get_height(); + return Vector2(s->get_radius(), s->get_height()); } if (Object::cast_to(cs)) {