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:
parent
3ddba82716
commit
0e8c874166
|
@ -6084,6 +6084,10 @@ def km_edit_curves(params):
|
||||||
("curves.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
|
("curves.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
|
||||||
*_template_items_proportional_editing(
|
*_template_items_proportional_editing(
|
||||||
params, connected=True, toggle_data_path='tool_settings.use_proportional_edit'),
|
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},
|
("transform.transform", {"type": 'S', "value": 'PRESS', "alt": True},
|
||||||
{"properties": [("mode", 'CURVE_SHRINKFATTEN')]}),
|
{"properties": [("mode", 'CURVE_SHRINKFATTEN')]}),
|
||||||
])
|
])
|
||||||
|
|
|
@ -3026,8 +3026,10 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
|
||||||
'EDIT_CURVES': [
|
'EDIT_CURVES': [
|
||||||
*_tools_default,
|
*_tools_default,
|
||||||
None,
|
None,
|
||||||
_defs_edit_curve.curve_radius,
|
|
||||||
_defs_edit_curves.draw,
|
_defs_edit_curves.draw,
|
||||||
|
None,
|
||||||
|
_defs_edit_curve.curve_radius,
|
||||||
|
_defs_edit_curve.tilt,
|
||||||
],
|
],
|
||||||
'EDIT_SURFACE': [
|
'EDIT_SURFACE': [
|
||||||
*_tools_default,
|
*_tools_default,
|
||||||
|
|
|
@ -1282,6 +1282,46 @@ static void CURVES_OT_duplicate(wmOperatorType *ot)
|
||||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
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
|
} // namespace blender::ed::curves
|
||||||
|
|
||||||
void ED_operatortypes_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_surface_set);
|
||||||
WM_operatortype_append(CURVES_OT_delete);
|
WM_operatortype_append(CURVES_OT_delete);
|
||||||
WM_operatortype_append(CURVES_OT_duplicate);
|
WM_operatortype_append(CURVES_OT_duplicate);
|
||||||
|
WM_operatortype_append(CURVES_OT_tilt_clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ED_operatormacros_curves()
|
void ED_operatormacros_curves()
|
||||||
|
|
|
@ -105,7 +105,11 @@ static void createTransCurvesVerts(bContext * /*C*/, TransInfo *t)
|
||||||
"radius",
|
"radius",
|
||||||
ATTR_DOMAIN_POINT,
|
ATTR_DOMAIN_POINT,
|
||||||
bke::AttributeInitVArray(VArray<float>::ForSingle(0.01f, curves.points_num())));
|
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;
|
value_attribute = attribute_writer.span;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +121,8 @@ static void createTransCurvesVerts(bContext * /*C*/, TransInfo *t)
|
||||||
curves.curves_range(),
|
curves.curves_range(),
|
||||||
use_connected_only,
|
use_connected_only,
|
||||||
0 /* No data offset for curves. */);
|
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();
|
attribute_writer.finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,9 +133,16 @@ static void recalcData_curves(TransInfo *t)
|
||||||
for (const TransDataContainer &tc : trans_data_contrainers) {
|
for (const TransDataContainer &tc : trans_data_contrainers) {
|
||||||
Curves *curves_id = static_cast<Curves *>(tc.obedit->data);
|
Curves *curves_id = static_cast<Curves *>(tc.obedit->data);
|
||||||
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
||||||
|
if (t->mode == TFM_CURVE_SHRINKFATTEN) {
|
||||||
curves.calculate_bezier_auto_handles();
|
/* No cache to update currently. */
|
||||||
curves.tag_positions_changed();
|
}
|
||||||
|
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);
|
DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "MEM_guardedalloc.h"
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
|
#include "DNA_curve_types.h"
|
||||||
#include "DNA_object_types.h"
|
#include "DNA_object_types.h"
|
||||||
#include "DNA_scene_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);
|
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)
|
static void TRANSFORM_OT_tilt(wmOperatorType *ot)
|
||||||
{
|
{
|
||||||
/* identifiers */
|
/* identifiers */
|
||||||
|
@ -976,7 +993,7 @@ static void TRANSFORM_OT_tilt(wmOperatorType *ot)
|
||||||
ot->exec = transform_exec;
|
ot->exec = transform_exec;
|
||||||
ot->modal = transform_modal;
|
ot->modal = transform_modal;
|
||||||
ot->cancel = transform_cancel;
|
ot->cancel = transform_cancel;
|
||||||
ot->poll = ED_operator_editcurve_3d;
|
ot->poll = tilt_poll;
|
||||||
ot->poll_property = transform_poll_property;
|
ot->poll_property = transform_poll_property;
|
||||||
|
|
||||||
RNA_def_float_rotation(
|
RNA_def_float_rotation(
|
||||||
|
|
Loading…
Reference in New Issue