diff --git a/scripts/presets/keyconfig/keymap_data/blender_default.py b/scripts/presets/keyconfig/keymap_data/blender_default.py index 2aaff955292..5c0eedbeccc 100644 --- a/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -4610,6 +4610,18 @@ def km_grease_pencil_edit(params): {"properties": [("type", "ALL_FRAMES")]}), # Keyframe Menu op_menu("VIEW3D_MT_edit_greasepencil_animation", {"type": 'I', "value": 'PRESS'}), + + # Transform Actions. + *_template_items_transform_actions(params, use_bend=True, use_mirror=True, use_tosphere=True, use_shear=True), + ("transform.transform", {"type": 'S', "value": 'PRESS', "alt": True}, + {"properties": [("mode", 'CURVE_SHRINKFATTEN')]}), + ("transform.transform", {"type": 'F', "value": 'PRESS', "shift": True}, + {"properties": [("mode", 'GPENCIL_OPACITY')]}), + + # Proportional editing. + *_template_items_proportional_editing( + params, connected=True, toggle_data_path='tool_settings.use_proportional_edit'), + # Cyclical set ("grease_pencil.cyclical_set", {"type": 'F', "value": 'PRESS'}, {"properties": [("type", "CLOSE")]}), ("grease_pencil.cyclical_set", {"type": 'C', "value": 'PRESS', @@ -7265,6 +7277,16 @@ def km_3d_view_tool_shear(params): ]}, ) +def km_3d_view_tool_bend(params): + return ( + "3D View Tool: Bend", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": [ + # No need for `tool_modifier` since this takes all input. + ("transform.bend", params.tool_maybe_tweak_event, + {"properties": [("release_confirm", True)]}), + ]}, + ) def km_3d_view_tool_measure(params): return ( @@ -8567,6 +8589,7 @@ def generate_keymaps(params=None): km_3d_view_tool_rotate(params), km_3d_view_tool_scale(params), km_3d_view_tool_shear(params), + km_3d_view_tool_bend(params), km_3d_view_tool_measure(params), km_3d_view_tool_interactive_add(params), km_3d_view_tool_pose_breakdowner(params), diff --git a/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/scripts/startup/bl_ui/space_toolsystem_toolbar.py index 82c279bc2e5..1cbede60f72 100644 --- a/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -366,6 +366,16 @@ class _defs_transform: draw_settings=draw_settings, ) + @ToolDef.from_fn + def bend(): + return dict( + idname="builtin.bend", + label="Bend", + icon="ops.gpencil.edit_bend", + widget=None, + keymap="3D View Tool: Bend", + ) + @ToolDef.from_fn def transform(): def draw_settings(context, layout, tool): @@ -3012,6 +3022,18 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): ], 'EDIT_GREASE_PENCIL': [ *_tools_select, + _defs_view3d_generic.cursor, + None, + *_tools_transform, + None, + _defs_edit_curve.curve_radius, + _defs_transform.bend, + ( + _defs_transform.shear, + _defs_edit_mesh.tosphere, + ), + None, + *_tools_annotate, ], 'PARTICLE': [ *_tools_select, diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index 2e03ab9c91d..76c7e4ed918 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -1237,10 +1237,10 @@ class VIEW3D_MT_transform(VIEW3D_MT_transform_base, Menu): if context.mode == 'EDIT_MESH': layout.operator("transform.shrink_fatten", text="Shrink/Fatten").alt_navigation = alt_navigation layout.operator("transform.skin_resize") - elif context.mode == 'EDIT_CURVE': + elif context.mode in ['EDIT_CURVE', 'EDIT_GREASE_PENCIL']: layout.operator("transform.transform", text="Radius").mode = 'CURVE_SHRINKFATTEN' - if context.mode != 'EDIT_CURVES': + if context.mode != 'EDIT_CURVES' and context.mode != 'EDIT_GREASE_PENCIL': layout.separator() props = layout.operator("transform.translate", text="Move Texture Space") props.texture_space = True @@ -5805,6 +5805,11 @@ class VIEW3D_MT_edit_greasepencil(Menu): def draw(self, _context): layout = self.layout + layout.menu("VIEW3D_MT_transform") + layout.menu("VIEW3D_MT_mirror") + + layout.separator() + layout.menu("VIEW3D_MT_edit_greasepencil_delete") diff --git a/source/blender/blenkernel/BKE_crazyspace.hh b/source/blender/blenkernel/BKE_crazyspace.hh index b1df5f94c1c..f158af024eb 100644 --- a/source/blender/blenkernel/BKE_crazyspace.hh +++ b/source/blender/blenkernel/BKE_crazyspace.hh @@ -53,6 +53,9 @@ GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph, const Object &ob_orig); GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object *ob_eval, const Object &ob_orig, - int drawing_index); + int layer_index); +GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Depsgraph &depsgraph, + const Object &ob_orig, + int layer_index); } // namespace blender::bke::crazyspace diff --git a/source/blender/blenkernel/intern/crazyspace.cc b/source/blender/blenkernel/intern/crazyspace.cc index 60577e09b3a..f5212ed0af0 100644 --- a/source/blender/blenkernel/intern/crazyspace.cc +++ b/source/blender/blenkernel/intern/crazyspace.cc @@ -740,4 +740,12 @@ GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object return deformation; } +GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Depsgraph &depsgraph, + const Object &ob_orig, + const int layer_index) +{ + const Object *ob_eval = DEG_get_evaluated_object(&depsgraph, const_cast(&ob_orig)); + return get_evaluated_grease_pencil_drawing_deformation(ob_eval, ob_orig, layer_index); +} + } // namespace blender::bke::crazyspace diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index 814407a735b..1498ecd147b 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -32,6 +32,7 @@ set(SRC transform_convert_curves.cc transform_convert_gpencil_legacy.cc transform_convert_graph.cc + transform_convert_grease_pencil.cc transform_convert_lattice.cc transform_convert_mask.cc transform_convert_mball.cc diff --git a/source/blender/editors/transform/transform.cc b/source/blender/editors/transform/transform.cc index f5c7e6fdd39..d8256eb6332 100644 --- a/source/blender/editors/transform/transform.cc +++ b/source/blender/editors/transform/transform.cc @@ -426,11 +426,16 @@ void removeAspectRatio(TransInfo *t, float vec[2]) static void viewRedrawForce(const bContext *C, TransInfo *t) { if (t->options & CTX_GPENCIL_STROKES) { - bGPdata *gpd = ED_gpencil_data_get_active(C); - if (gpd) { - DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY); + if (t->obedit_type == OB_GREASE_PENCIL) { + WM_event_add_notifier(C, NC_GEOM | ND_DATA, nullptr); + } + else if (t->obedit_type == OB_GPENCIL_LEGACY) { + bGPdata *gpd = ED_gpencil_data_get_active(C); + if (gpd) { + DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY); + } + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, nullptr); } - WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, nullptr); } else if (t->spacetype == SPACE_VIEW3D) { if (t->options & CTX_PAINT_CURVE) { diff --git a/source/blender/editors/transform/transform_convert.cc b/source/blender/editors/transform/transform_convert.cc index 59b4d9f2d5e..f8ec1db29f2 100644 --- a/source/blender/editors/transform/transform_convert.cc +++ b/source/blender/editors/transform/transform_convert.cc @@ -718,23 +718,25 @@ static int countAndCleanTransDataContainer(TransInfo *t) static void init_proportional_edit(TransInfo *t) { /* NOTE: Proportional editing is not usable in pose mode yet #32444. */ - if (!ELEM(t->data_type, - &TransConvertType_Action, - &TransConvertType_Curve, - &TransConvertType_Curves, - &TransConvertType_Graph, - &TransConvertType_GPencil, - &TransConvertType_Lattice, - &TransConvertType_Mask, - &TransConvertType_MBall, - &TransConvertType_Mesh, - &TransConvertType_MeshEdge, - &TransConvertType_MeshSkin, - &TransConvertType_MeshUV, - &TransConvertType_MeshVertCData, - &TransConvertType_Node, - &TransConvertType_Object, - &TransConvertType_Particle)) + /* NOTE: This `ELEM` uses more than 16 elements and so has been split. */ + if (!(ELEM(t->data_type, + &TransConvertType_Action, + &TransConvertType_Curve, + &TransConvertType_Curves, + &TransConvertType_Graph, + &TransConvertType_GPencil, + &TransConvertType_GreasePencil, + &TransConvertType_Lattice, + &TransConvertType_Mask, + &TransConvertType_MBall, + &TransConvertType_Mesh, + &TransConvertType_MeshEdge, + &TransConvertType_MeshSkin, + &TransConvertType_MeshUV, + &TransConvertType_MeshVertCData, + &TransConvertType_Node, + &TransConvertType_Object) || + ELEM(t->data_type, &TransConvertType_Particle))) { /* Disable proportional editing */ t->options |= CTX_NO_PET; @@ -797,6 +799,7 @@ static void init_TransDataContainers(TransInfo *t, &TransConvertType_Curve, &TransConvertType_Curves, &TransConvertType_GPencil, + &TransConvertType_GreasePencil, &TransConvertType_Lattice, &TransConvertType_MBall, &TransConvertType_Mesh, @@ -813,6 +816,7 @@ static void init_TransDataContainers(TransInfo *t, const short object_type = obact ? obact->type : -1; if ((object_mode & OB_MODE_EDIT) || (t->data_type == &TransConvertType_GPencil) || + (t->data_type == &TransConvertType_GreasePencil) || ((object_mode & OB_MODE_POSE) && (object_type == OB_ARMATURE))) { if (t->data_container) { @@ -860,6 +864,9 @@ static void init_TransDataContainers(TransInfo *t, else if (t->data_type == &TransConvertType_GPencil) { tc->use_local_mat = true; } + else if (t->data_type == &TransConvertType_GreasePencil) { + tc->use_local_mat = true; + } if (tc->use_local_mat) { BLI_assert((t->flag & T_2D_EDIT) == 0); @@ -910,7 +917,13 @@ static TransConvertTypeInfo *convert_type_get(const TransInfo *t, Object **r_obj return &TransConvertType_MeshEdge; } if (t->options & CTX_GPENCIL_STROKES) { - return &TransConvertType_GPencil; + if (t->obedit_type == OB_GREASE_PENCIL) { + return &TransConvertType_GreasePencil; + } + else if (t->obedit_type == OB_GPENCIL_LEGACY) { + return &TransConvertType_GPencil; + } + return nullptr; } if (t->spacetype == SPACE_IMAGE) { if (t->options & CTX_MASK) { diff --git a/source/blender/editors/transform/transform_convert.hh b/source/blender/editors/transform/transform_convert.hh index b9da5d40c53..c735ec53841 100644 --- a/source/blender/editors/transform/transform_convert.hh +++ b/source/blender/editors/transform/transform_convert.hh @@ -11,6 +11,10 @@ #include "RE_engine.h" +#include "BKE_curves.hh" + +#include "BLI_index_mask.hh" + struct BMEditMesh; struct BMesh; struct BezTriple; @@ -106,6 +110,19 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc); */ void animrecord_check_state(TransInfo *t, ID *id); +/* `transform_convert_curves.cc` */ + +/** + * Used for both curves and grease pencil objects. + */ +void curve_populate_trans_data_structs(TransDataContainer &tc, + blender::bke::CurvesGeometry &curves, + std::optional> value_attribute, + const blender::IndexMask &selected_indices, + bool use_proportional_edit, + bool use_connected_only, + int trans_data_offset); + /* `transform_convert_action.cc` */ extern TransConvertTypeInfo TransConvertType_Action; @@ -131,7 +148,7 @@ extern TransConvertTypeInfo TransConvertType_Cursor3D; extern TransConvertTypeInfo TransConvertType_Curve; -/* transform_convert_curves.cc */ +/* `transform_convert_curves.cc` */ extern TransConvertTypeInfo TransConvertType_Curves; @@ -143,6 +160,10 @@ extern TransConvertTypeInfo TransConvertType_Graph; extern TransConvertTypeInfo TransConvertType_GPencil; +/* `transform_convert_greasepencil.cc` */ + +extern TransConvertTypeInfo TransConvertType_GreasePencil; + /* `transform_convert_lattice.cc` */ extern TransConvertTypeInfo TransConvertType_Lattice; diff --git a/source/blender/editors/transform/transform_convert_curves.cc b/source/blender/editors/transform/transform_convert_curves.cc index a40dd42041c..54c117733cf 100644 --- a/source/blender/editors/transform/transform_convert_curves.cc +++ b/source/blender/editors/transform/transform_convert_curves.cc @@ -6,6 +6,8 @@ * \ingroup edtransform */ +#include + #include "BLI_array.hh" #include "BLI_inplace_priority_queue.hh" #include "BLI_math_matrix.h" @@ -95,82 +97,14 @@ static void createTransCurvesVerts(bContext * /*C*/, TransInfo *t) Curves *curves_id = static_cast(tc.obedit->data); bke::CurvesGeometry &curves = curves_id->geometry.wrap(); - float mtx[3][3], smtx[3][3]; - copy_m3_m4(mtx, tc.obedit->object_to_world); - pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); - - MutableSpan positions = curves.positions_for_write(); - if (use_proportional_edit) { - const OffsetIndices points_by_curve = curves.points_by_curve(); - const VArray selection = *curves.attributes().lookup_or_default( - ".selection", ATTR_DOMAIN_POINT, true); - threading::parallel_for(curves.curves_range(), 512, [&](const IndexRange range) { - Vector closest_distances; - for (const int curve_i : range) { - const IndexRange points = points_by_curve[curve_i]; - const bool has_any_selected = ed::curves::has_anything_selected(selection, points); - if (!has_any_selected && use_connected_only) { - for (const int point_i : points) { - TransData &td = tc.data[point_i]; - td.flag |= TD_SKIP; - } - continue; - } - - closest_distances.reinitialize(points.size()); - closest_distances.fill(std::numeric_limits::max()); - - for (const int i : IndexRange(points.size())) { - const int point_i = points[i]; - TransData &td = tc.data[point_i]; - float3 *elem = &positions[point_i]; - - copy_v3_v3(td.iloc, *elem); - copy_v3_v3(td.center, td.iloc); - td.loc = *elem; - - td.flag = 0; - if (selection[point_i]) { - closest_distances[i] = 0.0f; - td.flag = TD_SELECTED; - } - - td.ext = nullptr; - - copy_m3_m3(td.smtx, smtx); - copy_m3_m3(td.mtx, mtx); - } - - if (use_connected_only) { - calculate_curve_point_distances_for_proportional_editing( - positions.slice(points), closest_distances.as_mutable_span()); - for (const int i : IndexRange(points.size())) { - TransData &td = tc.data[points[i]]; - td.dist = closest_distances[i]; - } - } - } - }); - } - else { - const IndexMask selected_indices = selection_per_object[i]; - threading::parallel_for(selected_indices.index_range(), 1024, [&](const IndexRange range) { - for (const int selection_i : range) { - TransData *td = &tc.data[selection_i]; - float3 *elem = &positions[selected_indices[selection_i]]; - - copy_v3_v3(td->iloc, *elem); - copy_v3_v3(td->center, td->iloc); - td->loc = *elem; - - td->flag = TD_SELECTED; - td->ext = nullptr; - - copy_m3_m3(td->smtx, smtx); - copy_m3_m3(td->mtx, mtx); - } - }); - } + curve_populate_trans_data_structs( + tc, + curves, + {} /* Currently no transform for attributes other than position. */, + selection_per_object[i], + use_proportional_edit, + use_connected_only, + 0 /* No data offset for curves. */); } } @@ -189,6 +123,106 @@ static void recalcData_curves(TransInfo *t) } // namespace blender::ed::transform::curves +void curve_populate_trans_data_structs(TransDataContainer &tc, + blender::bke::CurvesGeometry &curves, + std::optional> value_attribute, + const blender::IndexMask &selected_indices, + bool use_proportional_edit, + bool use_connected_only, + int trans_data_offset) +{ + using namespace blender; + + float mtx[3][3], smtx[3][3]; + copy_m3_m4(mtx, tc.obedit->object_to_world); + pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); + + MutableSpan positions = curves.positions_for_write(); + if (use_proportional_edit) { + const OffsetIndices points_by_curve = curves.points_by_curve(); + const VArray selection = *curves.attributes().lookup_or_default( + ".selection", ATTR_DOMAIN_POINT, true); + threading::parallel_for(curves.curves_range(), 512, [&](const IndexRange range) { + Vector closest_distances; + for (const int curve_i : range) { + const IndexRange points = points_by_curve[curve_i]; + const bool has_any_selected = ed::curves::has_anything_selected(selection, points); + if (!has_any_selected && use_connected_only) { + for (const int point_i : points) { + TransData &td = tc.data[point_i + trans_data_offset]; + td.flag |= TD_SKIP; + } + continue; + } + + closest_distances.reinitialize(points.size()); + closest_distances.fill(std::numeric_limits::max()); + + for (const int i : IndexRange(points.size())) { + const int point_i = points[i]; + TransData &td = tc.data[point_i + trans_data_offset]; + float3 *elem = &positions[point_i]; + + copy_v3_v3(td.iloc, *elem); + copy_v3_v3(td.center, td.iloc); + td.loc = *elem; + + td.flag = 0; + if (selection[point_i]) { + closest_distances[i] = 0.0f; + td.flag = TD_SELECTED; + } + + if (value_attribute) { + float *value = &((*value_attribute)[point_i]); + td.val = value; + td.ival = *value; + } + + td.ext = nullptr; + + copy_m3_m3(td.smtx, smtx); + copy_m3_m3(td.mtx, mtx); + } + + if (use_connected_only) { + blender::ed::transform::curves::calculate_curve_point_distances_for_proportional_editing( + positions.slice(points), closest_distances.as_mutable_span()); + for (const int i : IndexRange(points.size())) { + TransData &td = tc.data[points[i] + trans_data_offset]; + td.dist = closest_distances[i]; + } + } + } + }); + } + else { + threading::parallel_for(selected_indices.index_range(), 1024, [&](const IndexRange range) { + for (const int selection_i : range) { + TransData *td = &tc.data[selection_i + trans_data_offset]; + const int point_i = selected_indices[selection_i]; + float3 *elem = &positions[point_i]; + + copy_v3_v3(td->iloc, *elem); + copy_v3_v3(td->center, td->iloc); + td->loc = *elem; + + if (value_attribute) { + float *value = &((*value_attribute)[point_i]); + td->val = value; + td->ival = *value; + } + + td->flag = TD_SELECTED; + td->ext = nullptr; + + copy_m3_m3(td->smtx, smtx); + copy_m3_m3(td->mtx, mtx); + } + }); + } +} + /** \} */ TransConvertTypeInfo TransConvertType_Curves = { diff --git a/source/blender/editors/transform/transform_convert_grease_pencil.cc b/source/blender/editors/transform/transform_convert_grease_pencil.cc new file mode 100644 index 00000000000..3d171110fbf --- /dev/null +++ b/source/blender/editors/transform/transform_convert_grease_pencil.cc @@ -0,0 +1,145 @@ +/* SPDX-FileCopyrightText: 2023 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup edtransform + */ + +#include "BLI_math_matrix.h" + +#include "BKE_context.h" + +#include "ED_curves.hh" +#include "ED_grease_pencil.hh" + +#include "transform.hh" +#include "transform_convert.hh" + +/* -------------------------------------------------------------------- */ +/** \name Grease Pencil Transform Creation + * \{ */ + +namespace blender::ed::transform::greasepencil { + +static void createTransGreasePencilVerts(bContext *C, TransInfo *t) +{ + Scene *scene = CTX_data_scene(C); + MutableSpan trans_data_contrainers(t->data_container, t->data_container_len); + IndexMaskMemory memory; + Array selection_per_layer_per_object(t->data_container_len); + const bool use_proportional_edit = (t->flag & T_PROP_EDIT_ALL) != 0; + const bool use_connected_only = (t->flag & T_PROP_CONNECTED) != 0; + int layer_offset = 0; + + /* Count selected elements per layer per object and create TransData structs. */ + for (const int i : trans_data_contrainers.index_range()) { + TransDataContainer &tc = trans_data_contrainers[i]; + GreasePencil &grease_pencil = *static_cast(tc.obedit->data); + + grease_pencil.foreach_editable_drawing( + scene->r.cfra, [&](int /*layer_index*/, blender::bke::greasepencil::Drawing &drawing) { + const bke::CurvesGeometry &curves = drawing.strokes(); + + if (use_proportional_edit) { + tc.data_len += curves.point_num; + } + else { + selection_per_layer_per_object[i + layer_offset] = + ed::curves::retrieve_selected_points(curves, memory); + tc.data_len += selection_per_layer_per_object[i + layer_offset].size(); + } + + layer_offset++; + }); + + if (tc.data_len > 0) { + tc.data = MEM_cnew_array(tc.data_len, __func__); + } + } + + /* Reuse the variable `layer_offset` */ + layer_offset = 0; + + /* Populate TransData structs. */ + for (const int i : trans_data_contrainers.index_range()) { + TransDataContainer &tc = trans_data_contrainers[i]; + if (tc.data_len == 0) { + continue; + } + GreasePencil &grease_pencil = *static_cast(tc.obedit->data); + + float mtx[3][3], smtx[3][3]; + copy_m3_m4(mtx, tc.obedit->object_to_world); + pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); + + int layer_points_offset = 0; + + grease_pencil.foreach_editable_drawing( + scene->r.cfra, [&](int /*layer_index*/, blender::bke::greasepencil::Drawing &drawing) { + bke::CurvesGeometry &curves = drawing.strokes_for_write(); + + const IndexMask selected_indices = selection_per_layer_per_object[i + layer_offset]; + + std::optional> value_attribute; + + if (t->mode == TFM_CURVE_SHRINKFATTEN) { + MutableSpan radii = drawing.radii_for_write(); + value_attribute = radii; + } + else if (t->mode == TFM_GPENCIL_OPACITY) { + MutableSpan opacities = drawing.opacities_for_write(); + value_attribute = opacities; + } + + curve_populate_trans_data_structs(tc, + curves, + value_attribute, + selected_indices, + use_proportional_edit, + use_connected_only, + layer_points_offset); + + if (use_proportional_edit) { + layer_points_offset += curves.points_num(); + } + else { + layer_points_offset += selected_indices.size(); + } + layer_offset++; + }); + } +} + +static void recalcData_grease_pencil(TransInfo *t) +{ + bContext *C = t->context; + Scene *scene = CTX_data_scene(C); + + const Span trans_data_contrainers(t->data_container, t->data_container_len); + for (const TransDataContainer &tc : trans_data_contrainers) { + GreasePencil &grease_pencil = *static_cast(tc.obedit->data); + + grease_pencil.foreach_editable_drawing( + scene->r.cfra, [&](int /*layer_index*/, bke::greasepencil::Drawing &drawing) { + bke::CurvesGeometry &curves = drawing.strokes_for_write(); + + curves.calculate_bezier_auto_handles(); + curves.tag_positions_changed(); + drawing.tag_positions_changed(); + }); + + DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY); + } +} + +} // namespace blender::ed::transform::greasepencil + +/** \} */ + +TransConvertTypeInfo TransConvertType_GreasePencil = { + /*flags*/ (T_EDIT | T_POINTS), + /*create_trans_data*/ blender::ed::transform::greasepencil::createTransGreasePencilVerts, + /*recalc_data*/ blender::ed::transform::greasepencil::recalcData_grease_pencil, + /*special_aftertrans_update*/ nullptr, +}; diff --git a/source/blender/editors/transform/transform_generics.cc b/source/blender/editors/transform/transform_generics.cc index f39f3b376fc..989a636b900 100644 --- a/source/blender/editors/transform/transform_generics.cc +++ b/source/blender/editors/transform/transform_generics.cc @@ -230,6 +230,11 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->options |= CTX_GPENCIL_STROKES; } + /* Grease Pencil editing context */ + if (t->obedit_type == OB_GREASE_PENCIL && object_mode == OB_MODE_EDIT) { + t->options |= CTX_GPENCIL_STROKES; + } + /* Assign the space type, some exceptions for running in different mode */ if (area == nullptr) { /* background mode */ diff --git a/source/blender/editors/transform/transform_gizmo_3d.cc b/source/blender/editors/transform/transform_gizmo_3d.cc index 7c6f6a6bb71..399c13de23e 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.cc +++ b/source/blender/editors/transform/transform_gizmo_3d.cc @@ -10,6 +10,7 @@ * Used for 3D View */ +#include "BLI_array_utils.h" #include "BLI_function_ref.hh" #include "BLI_math_geom.h" #include "BLI_math_matrix.h" @@ -26,12 +27,12 @@ #include "BKE_editmesh.h" #include "BKE_global.h" #include "BKE_gpencil_legacy.h" +#include "BKE_grease_pencil.hh" #include "BKE_layer.h" #include "BKE_object.hh" #include "BKE_paint.hh" #include "BKE_pointcache.h" #include "BKE_scene.h" -#include "BLI_array_utils.h" #include "WM_api.hh" #include "WM_message.hh" @@ -41,6 +42,7 @@ #include "ED_gizmo_library.hh" #include "ED_gizmo_utils.hh" #include "ED_gpencil_legacy.hh" +#include "ED_grease_pencil.hh" #include "ED_object.hh" #include "ED_particle.hh" #include "ED_screen.hh" @@ -807,6 +809,35 @@ static int gizmo_3d_foreach_selected(const bContext *C, } FOREACH_EDIT_OBJECT_END(); } + else if (obedit->type == OB_GREASE_PENCIL) { + FOREACH_EDIT_OBJECT_BEGIN (ob_iter, use_mat_local) { + GreasePencil &grease_pencil = *static_cast(ob_iter->data); + + float4x4 mat_local; + if (use_mat_local) { + mat_local = float4x4(obedit->world_to_object) * float4x4(ob_iter->object_to_world); + } + + grease_pencil.foreach_editable_drawing( + scene->r.cfra, [&](int layer_index, blender::bke::greasepencil::Drawing &drawing) { + const bke::CurvesGeometry &curves = drawing.strokes(); + + const bke::crazyspace::GeometryDeformation deformation = + bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation( + *depsgraph, *ob, layer_index); + + IndexMaskMemory memory; + const IndexMask selected_points = ed::curves::retrieve_selected_points(curves, + memory); + const Span positions = deformation.positions; + totsel += selected_points.size(); + selected_points.foreach_index([&](const int point_i) { + run_coord_with_matrix(positions[point_i], use_mat_local, mat_local.ptr()); + }); + }); + } + FOREACH_EDIT_OBJECT_END(); + } #undef FOREACH_EDIT_OBJECT_BEGIN #undef FOREACH_EDIT_OBJECT_END diff --git a/source/blender/editors/transform/transform_mode.cc b/source/blender/editors/transform/transform_mode.cc index d9094a91744..d89b9b1b6c1 100644 --- a/source/blender/editors/transform/transform_mode.cc +++ b/source/blender/editors/transform/transform_mode.cc @@ -566,11 +566,17 @@ void ElementRotation_ex(const TransInfo *t, /* Apply gpencil falloff. */ if (t->options & CTX_GPENCIL_STROKES) { - bGPDstroke *gps = (bGPDstroke *)td->extra; - if (gps->runtime.multi_frame_falloff != 1.0f) { - float ident_mat[3][3]; - unit_m3(ident_mat); - interp_m3_m3m3(smat, ident_mat, smat, gps->runtime.multi_frame_falloff); + if (t->obedit_type == OB_GPENCIL_LEGACY) { + + bGPDstroke *gps = (bGPDstroke *)td->extra; + if (gps->runtime.multi_frame_falloff != 1.0f) { + float ident_mat[3][3]; + unit_m3(ident_mat); + interp_m3_m3m3(smat, ident_mat, smat, gps->runtime.multi_frame_falloff); + } + } + else if (t->obedit_type == OB_GREASE_PENCIL) { + /* pass */ } } @@ -1030,21 +1036,26 @@ void ElementResize(const TransInfo *t, * Operating on copies as a temporary solution. */ if (t->options & CTX_GPENCIL_STROKES) { - bGPDstroke *gps = (bGPDstroke *)td->extra; - mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff); + if (t->obedit_type == OB_GPENCIL_LEGACY) { + bGPDstroke *gps = (bGPDstroke *)td->extra; + mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff); - /* Scale stroke thickness. */ - if (td->val) { - NumInput num_evil = t->num; - float values_final_evil[4]; - copy_v4_v4(values_final_evil, t->values_final); - transform_snap_increment(t, values_final_evil); - applyNumInput(&num_evil, values_final_evil); + /* Scale stroke thickness. */ + if (td->val) { + NumInput num_evil = t->num; + float values_final_evil[4]; + copy_v4_v4(values_final_evil, t->values_final); + transform_snap_increment(t, values_final_evil); + applyNumInput(&num_evil, values_final_evil); - float ratio = values_final_evil[0]; - float transformed_value = td->ival * fabs(ratio); - *td->val = max_ff(interpf(transformed_value, td->ival, gps->runtime.multi_frame_falloff), - 0.001f); + float ratio = values_final_evil[0]; + float transformed_value = td->ival * fabs(ratio); + *td->val = max_ff(interpf(transformed_value, td->ival, gps->runtime.multi_frame_falloff), + 0.001f); + } + } + else if (t->obedit_type == OB_GREASE_PENCIL) { + mul_v3_fl(vec, td->factor); } } else { diff --git a/source/blender/editors/transform/transform_mode_gpopacity.cc b/source/blender/editors/transform/transform_mode_gpopacity.cc index 0a645af79ac..e92a3831877 100644 --- a/source/blender/editors/transform/transform_mode_gpopacity.cc +++ b/source/blender/editors/transform/transform_mode_gpopacity.cc @@ -60,10 +60,16 @@ static void applyGPOpacity(TransInfo *t) bool recalc = false; FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; - bGPdata *gpd = static_cast(td->ob->data); - const bool is_curve_edit = bool(GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)); - /* Only recalculate data when in curve edit mode. */ - if (is_curve_edit) { + + if (t->obedit_type == OB_GPENCIL_LEGACY) { + bGPdata *gpd = static_cast(td->ob->data); + const bool is_curve_edit = bool(GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)); + /* Only recalculate data when in curve edit mode. */ + if (is_curve_edit) { + recalc = true; + } + } + else if (t->obedit_type == OB_GREASE_PENCIL) { recalc = true; }