diff --git a/source/blender/editors/curves/intern/curves_data.cc b/source/blender/editors/curves/intern/curves_data.cc index fa73bf394dd..830fff4ca03 100644 --- a/source/blender/editors/curves/intern/curves_data.cc +++ b/source/blender/editors/curves/intern/curves_data.cc @@ -22,6 +22,17 @@ Vector> get_curves_positions_for_write(bke::CurvesGeometry & return positions_per_attribute; } +Vector> get_curves_positions(const bke::CurvesGeometry &curves) +{ + Vector> positions_per_attribute; + positions_per_attribute.append(curves.positions()); + if (curves.has_curve_with_type(CURVE_TYPE_BEZIER)) { + positions_per_attribute.append(curves.handle_positions_left()); + positions_per_attribute.append(curves.handle_positions_right()); + } + return positions_per_attribute; +} + void transverts_from_curves_positions_create(bke::CurvesGeometry &curves, TransVertStore *tvs, const bool skip_handles) diff --git a/source/blender/editors/include/ED_curves.hh b/source/blender/editors/include/ED_curves.hh index 2d394658586..d4a0c7ff9a7 100644 --- a/source/blender/editors/include/ED_curves.hh +++ b/source/blender/editors/include/ED_curves.hh @@ -60,6 +60,11 @@ Span get_curves_selection_attribute_names(const bke::CurvesGeometry & */ Vector> get_curves_positions_for_write(bke::CurvesGeometry &curves); +/** + * Get read-only positions per selection attribute for given curve. + */ +Vector> get_curves_positions(const bke::CurvesGeometry &curves); + /* Get all possible curve selection attribute names. */ Span get_curves_all_selection_attribute_names(); diff --git a/source/blender/editors/space_view3d/view3d_buttons.cc b/source/blender/editors/space_view3d/view3d_buttons.cc index ddc1397bc15..9eb46d86579 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.cc +++ b/source/blender/editors/space_view3d/view3d_buttons.cc @@ -30,11 +30,13 @@ #include "BLI_math_vector.h" #include "BLI_string.h" #include "BLI_utildefines.h" +#include "BLI_vector.hh" #include "BKE_action.hh" #include "BKE_armature.hh" #include "BKE_context.hh" #include "BKE_curve.hh" +#include "BKE_curves.hh" #include "BKE_customdata.hh" #include "BKE_deform.hh" #include "BKE_editmesh.hh" @@ -55,6 +57,8 @@ #include "RNA_access.hh" #include "RNA_prototypes.hh" +#include "ED_curves.hh" +#include "ED_grease_pencil.hh" #include "ED_mesh.hh" #include "ED_object.hh" #include "ED_object_vgroup.hh" @@ -92,11 +96,21 @@ struct TransformMedian_Lattice { float location[3], weight; }; +struct TransformMedian_GreasePencil { + float location[3]; +}; + +struct TransformMedian_Curves { + float location[3]; +}; + union TransformMedian { TransformMedian_Generic generic; TransformMedian_Mesh mesh; TransformMedian_Curve curve; TransformMedian_Lattice lattice; + TransformMedian_GreasePencil grease_pencil; + TransformMedian_Curves curves; }; /* temporary struct for storing transform properties */ @@ -293,8 +307,10 @@ static TransformProperties *v3d_transform_props_ensure(View3D *v3d) } /* is used for both read and write... */ -static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float lim) +static void v3d_editvertex_buts( + const bContext *C, uiLayout *layout, View3D *v3d, Object *ob, float lim) { + using namespace blender; uiBlock *block = (layout) ? uiLayoutAbsoluteBlock(layout) : nullptr; TransformProperties *tfp = v3d_transform_props_ensure(v3d); TransformMedian median_basis, ve_median_basis; @@ -468,6 +484,61 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float data_ptr = RNA_pointer_create_discrete(<->id, seltype, selp); } } + else if (ob->type == OB_GREASE_PENCIL) { + using namespace blender::ed::greasepencil; + using namespace ed::curves; + Scene &scene = *CTX_data_scene(C); + GreasePencil &grease_pencil = *static_cast(ob->data); + blender::Vector drawings = retrieve_editable_drawings(scene, + grease_pencil); + + threading::parallel_for_each(drawings, [&](const MutableDrawingInfo &info) { + const bke::CurvesGeometry &curves = info.drawing.strokes(); + if (curves.is_empty()) { + return; + } + + const Span selection_names = get_curves_selection_attribute_names(curves); + Vector> positions = get_curves_positions(curves); + TransformMedian_Curves &median = median_basis.curves; + for (int attribute_i : selection_names.index_range()) { + IndexMaskMemory memory; + const IndexMask selection = retrieve_selected_points( + curves, selection_names[attribute_i], memory); + if (selection.is_empty()) { + continue; + } + + tot += selection.size(); + selection.foreach_index( + [&](const int point) { add_v3_v3(median.location, positions[attribute_i][point]); }); + } + }); + } + else if (ob->type == OB_CURVES) { + using namespace ed::curves; + const Curves &curves_id = *static_cast(ob->data); + const bke::CurvesGeometry &curves = curves_id.geometry.wrap(); + if (curves.is_empty()) { + return; + } + + const Span selection_names = get_curves_selection_attribute_names(curves); + const Vector> positions = get_curves_positions(curves); + TransformMedian_Curves &median = median_basis.curves; + for (int attribute_i : selection_names.index_range()) { + IndexMaskMemory memory; + const IndexMask selection = retrieve_selected_points( + curves, selection_names[attribute_i], memory); + if (selection.is_empty()) { + continue; + } + + tot += selection.size(); + selection.foreach_index( + [&](const int point) { add_v3_v3(median.location, positions[attribute_i][point]); }); + } + } if (tot == 0) { uiDefBut( @@ -527,6 +598,9 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float /* Curve */ c = IFACE_("Control Point:"); } + else if (ELEM(ob->type, OB_CURVES, OB_GREASE_PENCIL)) { + c = IFACE_("Point:"); + } else { /* Mesh or lattice */ c = IFACE_("Vertex:"); @@ -1168,9 +1242,70 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float bp++; } } + else if (ob->type == OB_GREASE_PENCIL && apply_vcos) { + using namespace blender::ed::greasepencil; + using namespace ed::curves; + Scene &scene = *CTX_data_scene(C); + GreasePencil &grease_pencil = *static_cast(ob->data); + blender::Vector drawings = retrieve_editable_drawings(scene, + grease_pencil); - // ED_undo_push(C, "Transform properties"); + threading::parallel_for_each(drawings, [&](const MutableDrawingInfo &info) { + bke::CurvesGeometry &curves = info.drawing.strokes_for_write(); + if (curves.is_empty()) { + return; + } + + TransformMedian_GreasePencil &median = median_basis.grease_pencil; + TransformMedian_GreasePencil &ve_median = ve_median_basis.grease_pencil; + IndexMaskMemory memory; + const Span selection_names = get_curves_selection_attribute_names(curves); + const Vector> positions = get_curves_positions_for_write(curves); + for (int attribute_i : selection_names.index_range()) { + const IndexMask selection = retrieve_selected_points( + curves, selection_names[attribute_i], memory); + if (selection.is_empty()) { + continue; + } + + selection.foreach_index([&](const int point) { + apply_raw_diff_v3( + positions[attribute_i][point], tot, ve_median.location, median.location); + }); + info.drawing.tag_positions_changed(); + } + }); + } + else if (ob->type == OB_CURVES && apply_vcos) { + using namespace ed::curves; + Curves &curves_id = *static_cast(ob->data); + bke::CurvesGeometry &curves = curves_id.geometry.wrap(); + if (curves.is_empty()) { + return; + } + + TransformMedian_Curves &median = median_basis.curves; + TransformMedian_Curves &ve_median = ve_median_basis.curves; + IndexMaskMemory memory; + const Span selection_names = get_curves_selection_attribute_names(curves); + Vector> positions = get_curves_positions_for_write(curves); + for (int attribute_i : selection_names.index_range()) { + const IndexMask selection = retrieve_selected_points( + curves, selection_names[attribute_i], memory); + if (selection.is_empty()) { + continue; + } + + selection.foreach_index([&](const int point) { + apply_raw_diff_v3( + positions[attribute_i][point], tot, ve_median.location, median.location); + }); + } + curves.tag_positions_changed(); + } } + + // ED_undo_push(C, "Transform properties"); } #undef TRANSFORM_MEDIAN_ARRAY_LEN @@ -1691,7 +1826,7 @@ static void do_view3d_region_buttons(bContext *C, void * /*index*/, int event) case B_TRANSFORM_PANEL_MEDIAN: if (ob) { - v3d_editvertex_buts(nullptr, v3d, ob, 1.0); + v3d_editvertex_buts(C, nullptr, v3d, ob, 1.0); DEG_id_tag_update(static_cast(ob->data), ID_RECALC_GEOMETRY); } break; @@ -1738,7 +1873,7 @@ static void view3d_panel_transform(const bContext *C, Panel *panel) } else { View3D *v3d = CTX_wm_view3d(C); - v3d_editvertex_buts(col, v3d, ob, FLT_MAX); + v3d_editvertex_buts(C, col, v3d, ob, FLT_MAX); } } else if (ob->mode & OB_MODE_POSE) {