Curves: Add edit mode tilt control

Adds support for the tilt transform operator and a "Clear Tilt"
operator to mirror the functionality from the legacy curve type.
This commit is contained in:
Hans Goudey 2023-12-16 12:08:28 -05:00
parent 3ddba82716
commit 0e8c874166
5 changed files with 83 additions and 6 deletions

View File

@ -6084,6 +6084,10 @@ def km_edit_curves(params):
("curves.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
*_template_items_proportional_editing(
params, connected=True, toggle_data_path='tool_settings.use_proportional_edit'),
("curves.tilt_clear", {"type": 'T', "value": 'PRESS', "alt": True}, None),
op_tool_optional(
("transform.tilt", {"type": 'T', "value": 'PRESS', "ctrl": True}, None),
(op_tool_cycle, "builtin.tilt"), params),
("transform.transform", {"type": 'S', "value": 'PRESS', "alt": True},
{"properties": [("mode", 'CURVE_SHRINKFATTEN')]}),
])

View File

@ -3026,8 +3026,10 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
'EDIT_CURVES': [
*_tools_default,
None,
_defs_edit_curve.curve_radius,
_defs_edit_curves.draw,
None,
_defs_edit_curve.curve_radius,
_defs_edit_curve.tilt,
],
'EDIT_SURFACE': [
*_tools_default,

View File

@ -1282,6 +1282,46 @@ static void CURVES_OT_duplicate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
namespace clear_tilt {
static int exec(bContext *C, wmOperator * /*op*/)
{
for (Curves *curves_id : get_unique_editable_curves(*C)) {
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
IndexMaskMemory memory;
const IndexMask selection = retrieve_selected_points(*curves_id, memory);
if (selection.is_empty()) {
continue;
}
if (selection.size() == curves.points_num()) {
curves.attributes_for_write().remove("tilt");
}
else {
index_mask::masked_fill(curves.tilt_for_write(), 0.0f, selection);
}
curves.tag_normals_changed();
DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
}
return OPERATOR_FINISHED;
}
} // namespace clear_tilt
static void CURVES_OT_tilt_clear(wmOperatorType *ot)
{
ot->name = "Clear Tilt";
ot->idname = __func__;
ot->description = "Clear the tilt of selected control points";
ot->exec = clear_tilt::exec;
ot->poll = editable_curves_in_edit_mode_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
} // namespace blender::ed::curves
void ED_operatortypes_curves()
@ -1302,6 +1342,7 @@ void ED_operatortypes_curves()
WM_operatortype_append(CURVES_OT_surface_set);
WM_operatortype_append(CURVES_OT_delete);
WM_operatortype_append(CURVES_OT_duplicate);
WM_operatortype_append(CURVES_OT_tilt_clear);
}
void ED_operatormacros_curves()

View File

@ -105,7 +105,11 @@ static void createTransCurvesVerts(bContext * /*C*/, TransInfo *t)
"radius",
ATTR_DOMAIN_POINT,
bke::AttributeInitVArray(VArray<float>::ForSingle(0.01f, curves.points_num())));
value_attribute = attribute_writer.span;
}
else if (t->mode == TFM_TILT) {
bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
attribute_writer = attributes.lookup_or_add_for_write_span<float>("tilt", ATTR_DOMAIN_POINT);
value_attribute = attribute_writer.span;
}
@ -117,6 +121,8 @@ static void createTransCurvesVerts(bContext * /*C*/, TransInfo *t)
curves.curves_range(),
use_connected_only,
0 /* No data offset for curves. */);
/* TODO: This is wrong. The attribute writer should live at least as long as the span. */
attribute_writer.finish();
}
}
@ -127,9 +133,16 @@ static void recalcData_curves(TransInfo *t)
for (const TransDataContainer &tc : trans_data_contrainers) {
Curves *curves_id = static_cast<Curves *>(tc.obedit->data);
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
curves.calculate_bezier_auto_handles();
curves.tag_positions_changed();
if (t->mode == TFM_CURVE_SHRINKFATTEN) {
/* No cache to update currently. */
}
else if (t->mode == TFM_TILT) {
curves.tag_normals_changed();
}
else {
curves.tag_positions_changed();
curves.calculate_bezier_auto_handles();
}
DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
}
}

View File

@ -8,6 +8,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@ -960,6 +961,22 @@ static void TRANSFORM_OT_rotate(wmOperatorType *ot)
P_GEO_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
static bool tilt_poll(bContext *C)
{
Object *obedit = CTX_data_edit_object(C);
if (!obedit) {
return false;
}
if (obedit->type == OB_CURVES_LEGACY) {
Curve *cu = (Curve *)obedit->data;
return (cu->flag & CU_3D) && (nullptr != cu->editnurb);
}
if (obedit->type == OB_CURVES) {
return true;
}
return true;
}
static void TRANSFORM_OT_tilt(wmOperatorType *ot)
{
/* identifiers */
@ -976,7 +993,7 @@ static void TRANSFORM_OT_tilt(wmOperatorType *ot)
ot->exec = transform_exec;
ot->modal = transform_modal;
ot->cancel = transform_cancel;
ot->poll = ED_operator_editcurve_3d;
ot->poll = tilt_poll;
ot->poll_property = transform_poll_property;
RNA_def_float_rotation(