diff options
author | Hans Goudey <h.goudey@me.com> | 2022-06-04 13:55:19 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2022-06-04 13:55:19 +0300 |
commit | 735cf5069c8e36b28f747b5b1a8fffe7505b0aa2 (patch) | |
tree | b759966f323167c29cbb2d76b032f0cf857b10ce /source/blender/editors | |
parent | 5cbaf55fe60950c7e936f728bffbb2c68c80763e (diff) | |
parent | 9531eb24b3172d83660649cc0936c05f66aff79b (diff) |
Merge branch 'master' into refactor-mesh-hide-generic
Diffstat (limited to 'source/blender/editors')
85 files changed, 1960 insertions, 821 deletions
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index f9b973733af..5ef001812ab 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -375,13 +375,10 @@ static void updateDuplicateSubtarget(EditBone *dup_bone, /* does this constraint have a subtarget in * this armature? */ - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(curcon, &targets); - + if (BKE_constraint_targets_get(curcon, &targets)) { for (ct = targets.first; ct; ct = ct->next) { if ((ct->tar == ob) && (ct->subtarget[0])) { oldtarget = get_named_editbone(editbones, ct->subtarget); @@ -409,9 +406,7 @@ static void updateDuplicateSubtarget(EditBone *dup_bone, } } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(curcon, &targets, 0); - } + BKE_constraint_targets_flush(curcon, &targets, 0); } } } diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index e1f2605481f..1f02e24666d 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -109,13 +109,10 @@ static void constraint_bone_name_fix(Object *ob, bConstraintTarget *ct; for (curcon = conlist->first; curcon; curcon = curcon->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon); ListBase targets = {NULL, NULL}; /* constraint targets */ - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(curcon, &targets); - + if (BKE_constraint_targets_get(curcon, &targets)) { for (ct = targets.first; ct; ct = ct->next) { if (ct->tar == ob) { if (STREQ(ct->subtarget, oldname)) { @@ -124,9 +121,7 @@ static void constraint_bone_name_fix(Object *ob, } } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(curcon, &targets, 0); - } + BKE_constraint_targets_flush(curcon, &targets, 0); } /* action constraints */ diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index be4829c02be..950178e865d 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -68,14 +68,11 @@ static void joined_armature_fix_links_constraints(Main *bmain, bool changed = false; for (con = lb->first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; /* constraint targets */ - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - + if (BKE_constraint_targets_get(con, &targets)) { for (ct = targets.first; ct; ct = ct->next) { if (ct->tar == srcArm) { if (ct->subtarget[0] == '\0') { @@ -90,9 +87,7 @@ static void joined_armature_fix_links_constraints(Main *bmain, } } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 0); - } + BKE_constraint_targets_flush(con, &targets, 0); } /* action constraint? (pose constraints only) */ @@ -459,14 +454,11 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n if (ob->type == OB_ARMATURE) { for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; /* constraint targets */ - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - + if (BKE_constraint_targets_get(con, &targets)) { for (ct = targets.first; ct; ct = ct->next) { /* Any targets which point to original armature * are redirected to the new one only if: @@ -487,9 +479,7 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n } } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 0); - } + BKE_constraint_targets_flush(con, &targets, 0); } } } @@ -498,14 +488,11 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n /* fix object-level constraints */ if (ob != origArm) { for (con = ob->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; /* constraint targets */ - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - + if (BKE_constraint_targets_get(con, &targets)) { for (ct = targets.first; ct; ct = ct->next) { /* any targets which point to original armature are redirected to the new one only if: * - the target isn't origArm/newArm itself @@ -525,9 +512,7 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n } } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 0); - } + BKE_constraint_targets_flush(con, &targets, 0); } } } diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 8790a10f3e5..b6b5d3ee495 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -680,13 +680,10 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) { if (pchan->bone->flag & BONE_SELECTED) { for (con = pchan->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - + if (BKE_constraint_targets_get(con, &targets)) { for (ct = targets.first; ct; ct = ct->next) { Object *ob = ct->tar; @@ -702,9 +699,7 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op } } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 1); - } + BKE_constraint_targets_flush(con, &targets, 1); } } } diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 9da9845116d..dc49a5ed531 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -4729,6 +4729,7 @@ void CURVE_OT_make_segment(wmOperatorType *ot) bool ED_curve_editnurb_select_pick(bContext *C, const int mval[2], const int dist_px, + const bool vert_without_handles, const struct SelectPick_Params *params) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); @@ -4744,6 +4745,9 @@ bool ED_curve_editnurb_select_pick(bContext *C, ED_view3d_viewcontext_init(C, &vc, depsgraph); copy_v2_v2_int(vc.mval, mval); + const bool use_handle_select = vert_without_handles && + (vc.v3d->overlay.handle_display != CURVE_HANDLE_NONE); + bool found = ED_curve_pick_vert_ex(&vc, 1, dist_px, &nu, &bezt, &bp, &hand, &basact); if (params->sel_op == SEL_OP_SET) { @@ -4779,7 +4783,12 @@ bool ED_curve_editnurb_select_pick(bContext *C, case SEL_OP_ADD: { if (bezt) { if (hand == 1) { - select_beztriple(bezt, SELECT, SELECT, HIDDEN); + if (use_handle_select) { + bezt->f2 |= SELECT; + } + else { + select_beztriple(bezt, SELECT, SELECT, HIDDEN); + } } else { if (hand == 0) { @@ -4800,7 +4809,12 @@ bool ED_curve_editnurb_select_pick(bContext *C, case SEL_OP_SUB: { if (bezt) { if (hand == 1) { - select_beztriple(bezt, DESELECT, SELECT, HIDDEN); + if (use_handle_select) { + bezt->f2 &= ~SELECT; + } + else { + select_beztriple(bezt, DESELECT, SELECT, HIDDEN); + } if (bezt == vert) { cu->actvert = CU_ACT_NONE; } @@ -4824,13 +4838,23 @@ bool ED_curve_editnurb_select_pick(bContext *C, if (bezt) { if (hand == 1) { if (bezt->f2 & SELECT) { - select_beztriple(bezt, DESELECT, SELECT, HIDDEN); + if (use_handle_select) { + bezt->f2 &= ~SELECT; + } + else { + select_beztriple(bezt, DESELECT, SELECT, HIDDEN); + } if (bezt == vert) { cu->actvert = CU_ACT_NONE; } } else { - select_beztriple(bezt, SELECT, SELECT, HIDDEN); + if (use_handle_select) { + bezt->f2 |= SELECT; + } + else { + select_beztriple(bezt, SELECT, SELECT, HIDDEN); + } BKE_curve_nurb_vert_active_set(cu, nu, bezt); } } @@ -4861,7 +4885,12 @@ bool ED_curve_editnurb_select_pick(bContext *C, if (bezt) { if (hand == 1) { - select_beztriple(bezt, SELECT, SELECT, HIDDEN); + if (use_handle_select) { + bezt->f2 |= SELECT; + } + else { + select_beztriple(bezt, SELECT, SELECT, HIDDEN); + } } else { if (hand == 0) { diff --git a/source/blender/editors/curve/editcurve_pen.c b/source/blender/editors/curve/editcurve_pen.c index fca850076ae..a98b165e99d 100644 --- a/source/blender/editors/curve/editcurve_pen.c +++ b/source/blender/editors/curve/editcurve_pen.c @@ -1655,7 +1655,7 @@ static int curve_pen_modal(bContext *C, wmOperator *op, const wmEvent *event) else if (ELEM(event->type, LEFTMOUSE)) { if (ELEM(event->val, KM_RELEASE, KM_DBL_CLICK)) { if (delete_point && !cpd->new_point && !cpd->dragging) { - if (ED_curve_editnurb_select_pick(C, event->mval, threshold_dist_px, ¶ms)) { + if (ED_curve_editnurb_select_pick(C, event->mval, threshold_dist_px, false, ¶ms)) { cpd->acted = delete_point_under_mouse(&vc, event); } } @@ -1714,7 +1714,7 @@ static int curve_pen_modal(bContext *C, wmOperator *op, const wmEvent *event) } } else if (select_point) { - ED_curve_editnurb_select_pick(C, event->mval, threshold_dist_px, ¶ms); + ED_curve_editnurb_select_pick(C, event->mval, threshold_dist_px, false, ¶ms); } } diff --git a/source/blender/editors/curves/intern/curves_ops.cc b/source/blender/editors/curves/intern/curves_ops.cc index 5588f7440a8..85214e1608d 100644 --- a/source/blender/editors/curves/intern/curves_ops.cc +++ b/source/blender/editors/curves/intern/curves_ops.cc @@ -6,18 +6,23 @@ #include <atomic> +#include "BLI_devirtualize_parameters.hh" #include "BLI_utildefines.h" +#include "BLI_vector_set.hh" #include "ED_curves.h" #include "ED_object.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "WM_api.h" #include "BKE_bvhutils.h" #include "BKE_context.h" #include "BKE_curves.hh" +#include "BKE_geometry_set.hh" #include "BKE_layer.h" +#include "BKE_lib_id.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" #include "BKE_object.h" @@ -37,6 +42,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "RNA_prototypes.h" /** @@ -49,6 +55,41 @@ namespace blender::ed::curves { +static bool object_has_editable_curves(const Main &bmain, const Object &object) +{ + if (object.type != OB_CURVES) { + return false; + } + if (!ELEM(object.mode, OB_MODE_SCULPT_CURVES, OB_MODE_EDIT)) { + return false; + } + if (!BKE_id_is_editable(&bmain, static_cast<const ID *>(object.data))) { + return false; + } + return true; +} + +static VectorSet<Curves *> get_unique_editable_curves(const bContext &C) +{ + VectorSet<Curves *> unique_curves; + + const Main &bmain = *CTX_data_main(&C); + + Object *object = CTX_data_active_object(&C); + if (object && object_has_editable_curves(bmain, *object)) { + unique_curves.add_new(static_cast<Curves *>(object->data)); + } + + CTX_DATA_BEGIN (&C, Object *, object, selected_objects) { + if (object_has_editable_curves(bmain, *object)) { + unique_curves.add(static_cast<Curves *>(object->data)); + } + } + CTX_DATA_END; + + return unique_curves; +} + using bke::CurvesGeometry; namespace convert_to_particle_system { @@ -193,7 +234,7 @@ static void try_convert_single_object(Object &curves_ob, /* The old hair system still uses #MFace, so make sure those are available on the mesh. */ BKE_mesh_tessface_calc(&surface_me); - /* Prepare utility data structure to map hair roots to mfaces. */ + /* Prepare utility data structure to map hair roots to #MFace's. */ const Span<int> mface_to_poly_map{ static_cast<const int *>(CustomData_get_layer(&surface_me.fdata, CD_ORIGINDEX)), surface_me.totface}; @@ -645,6 +686,222 @@ static void CURVES_OT_snap_curves_to_surface(wmOperatorType *ot) "How to find the point on the surface to attach to"); } +static bool selection_poll(bContext *C) +{ + const Object *object = CTX_data_active_object(C); + if (object == nullptr) { + return false; + } + if (object->type != OB_CURVES) { + return false; + } + if (!BKE_id_is_editable(CTX_data_main(C), static_cast<const ID *>(object->data))) { + return false; + } + return true; +} + +namespace set_selection_domain { + +static int curves_set_selection_domain_exec(bContext *C, wmOperator *op) +{ + const eAttrDomain domain = eAttrDomain(RNA_enum_get(op->ptr, "domain")); + + for (Curves *curves_id : get_unique_editable_curves(*C)) { + if (curves_id->selection_domain == domain && (curves_id->flag & CV_SCULPT_SELECTION_ENABLED)) { + continue; + } + + const eAttrDomain old_domain = eAttrDomain(curves_id->selection_domain); + curves_id->selection_domain = domain; + curves_id->flag |= CV_SCULPT_SELECTION_ENABLED; + + CurveComponent component; + component.replace(curves_id, GeometryOwnershipType::Editable); + CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry); + + if (old_domain == ATTR_DOMAIN_POINT && domain == ATTR_DOMAIN_CURVE) { + VArray<float> curve_selection = curves.adapt_domain( + curves.selection_point_float(), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); + curve_selection.materialize(curves.selection_curve_float_for_write()); + component.attribute_try_delete(".selection_point_float"); + } + else if (old_domain == ATTR_DOMAIN_CURVE && domain == ATTR_DOMAIN_POINT) { + VArray<float> point_selection = curves.adapt_domain( + curves.selection_curve_float(), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT); + point_selection.materialize(curves.selection_point_float_for_write()); + component.attribute_try_delete(".selection_curve_float"); + } + + /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic + * attribute for now. */ + DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id); + } + + WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, nullptr); + + return OPERATOR_FINISHED; +} + +} // namespace set_selection_domain + +static void CURVES_OT_set_selection_domain(wmOperatorType *ot) +{ + PropertyRNA *prop; + + ot->name = "Set Select Mode"; + ot->idname = __func__; + ot->description = "Change the mode used for selection masking in curves sculpt mode"; + + ot->exec = set_selection_domain::curves_set_selection_domain_exec; + ot->poll = selection_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = prop = RNA_def_enum( + ot->srna, "domain", rna_enum_attribute_curves_domain_items, 0, "Domain", ""); + RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE)); +} + +namespace disable_selection { + +static int curves_disable_selection_exec(bContext *C, wmOperator *UNUSED(op)) +{ + for (Curves *curves_id : get_unique_editable_curves(*C)) { + curves_id->flag &= ~CV_SCULPT_SELECTION_ENABLED; + + /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic + * attribute for now. */ + DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id); + } + + WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, nullptr); + + return OPERATOR_FINISHED; +} + +} // namespace disable_selection + +static void CURVES_OT_disable_selection(wmOperatorType *ot) +{ + ot->name = "Disable Selection"; + ot->idname = __func__; + ot->description = "Disable the drawing of influence of selection in sculpt mode"; + + ot->exec = disable_selection::curves_disable_selection_exec; + ot->poll = selection_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +namespace select_all { + +static bool varray_contains_nonzero(const VArray<float> &data) +{ + bool contains_nonzero = false; + devirtualize_varray(data, [&](const auto array) { + for (const int i : data.index_range()) { + if (array[i] != 0.0f) { + contains_nonzero = true; + break; + } + } + }); + return contains_nonzero; +} + +static bool any_point_selected(const CurvesGeometry &curves) +{ + return varray_contains_nonzero(curves.selection_point_float()); +} + +static bool any_point_selected(const Span<Curves *> curves_ids) +{ + for (const Curves *curves_id : curves_ids) { + if (any_point_selected(CurvesGeometry::wrap(curves_id->geometry))) { + return true; + } + } + return false; +} + +static void invert_selection(MutableSpan<float> selection) +{ + threading::parallel_for(selection.index_range(), 2048, [&](IndexRange range) { + for (const int i : range) { + selection[i] = 1.0f - selection[i]; + } + }); +} + +static int select_all_exec(bContext *C, wmOperator *op) +{ + int action = RNA_enum_get(op->ptr, "action"); + + VectorSet<Curves *> unique_curves = get_unique_editable_curves(*C); + + if (action == SEL_TOGGLE) { + action = any_point_selected(unique_curves) ? SEL_DESELECT : SEL_SELECT; + } + + for (Curves *curves_id : unique_curves) { + if (action == SEL_SELECT) { + /* The optimization to avoid storing the selection when everything is selected causes too + * many problems at the moment, since there is no proper visualization yet. Keep the code but + * disable it for now. */ +#if 0 + CurveComponent component; + component.replace(curves_id, GeometryOwnershipType::Editable); + component.attribute_try_delete(".selection_point_float"); + component.attribute_try_delete(".selection_curve_float"); +#else + CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry); + MutableSpan<float> selection = curves_id->selection_domain == ATTR_DOMAIN_POINT ? + curves.selection_point_float_for_write() : + curves.selection_curve_float_for_write(); + selection.fill(1.0f); +#endif + } + else { + CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry); + MutableSpan<float> selection = curves_id->selection_domain == ATTR_DOMAIN_POINT ? + curves.selection_point_float_for_write() : + curves.selection_curve_float_for_write(); + if (action == SEL_DESELECT) { + selection.fill(0.0f); + } + else if (action == SEL_INVERT) { + invert_selection(selection); + } + } + + /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic + * attribute for now. */ + 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 select_all + +static void SCULPT_CURVES_OT_select_all(wmOperatorType *ot) +{ + ot->name = "(De)select All"; + ot->idname = __func__; + ot->description = "(De)select all control points"; + + ot->exec = select_all::select_all_exec; + ot->poll = selection_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + WM_operator_properties_select_all(ot); +} + } // namespace blender::ed::curves void ED_operatortypes_curves() @@ -653,4 +910,7 @@ void ED_operatortypes_curves() WM_operatortype_append(CURVES_OT_convert_to_particle_system); WM_operatortype_append(CURVES_OT_convert_from_particle_system); WM_operatortype_append(CURVES_OT_snap_curves_to_surface); + WM_operatortype_append(CURVES_OT_set_selection_domain); + WM_operatortype_append(SCULPT_CURVES_OT_select_all); + WM_operatortype_append(CURVES_OT_disable_selection); } diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc index ed16b8a903a..c9677da1af5 100644 --- a/source/blender/editors/geometry/geometry_attributes.cc +++ b/source/blender/editors/geometry/geometry_attributes.cc @@ -33,6 +33,7 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "ED_geometry.h" #include "ED_object.h" #include "geometry_intern.hh" @@ -89,8 +90,8 @@ static int geometry_attribute_add_exec(bContext *C, wmOperator *op) char name[MAX_NAME]; RNA_string_get(op->ptr, "name", name); - CustomDataType type = (CustomDataType)RNA_enum_get(op->ptr, "data_type"); - AttributeDomain domain = (AttributeDomain)RNA_enum_get(op->ptr, "domain"); + eCustomDataType type = (eCustomDataType)RNA_enum_get(op->ptr, "data_type"); + eAttrDomain domain = (eAttrDomain)RNA_enum_get(op->ptr, "domain"); CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports); if (layer == nullptr) { @@ -218,8 +219,8 @@ static int geometry_color_attribute_add_exec(bContext *C, wmOperator *op) char name[MAX_NAME]; RNA_string_get(op->ptr, "name", name); - CustomDataType type = (CustomDataType)RNA_enum_get(op->ptr, "data_type"); - AttributeDomain domain = (AttributeDomain)RNA_enum_get(op->ptr, "domain"); + eCustomDataType type = (eCustomDataType)RNA_enum_get(op->ptr, "data_type"); + eAttrDomain domain = (eAttrDomain)RNA_enum_get(op->ptr, "domain"); CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports); float color[4]; @@ -288,9 +289,8 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op) * 4. Create a new attribute based on the previously copied data. */ switch (mode) { case ConvertAttributeMode::Generic: { - const AttributeDomain dst_domain = static_cast<AttributeDomain>( - RNA_enum_get(op->ptr, "domain")); - const CustomDataType dst_type = static_cast<CustomDataType>( + const eAttrDomain dst_domain = static_cast<eAttrDomain>(RNA_enum_get(op->ptr, "domain")); + const eCustomDataType dst_type = static_cast<eCustomDataType>( RNA_enum_get(op->ptr, "data_type")); if (ELEM(dst_type, CD_PROP_STRING)) { @@ -572,3 +572,38 @@ void GEOMETRY_OT_attribute_convert(wmOperatorType *ot) } } // namespace blender::ed::geometry + +using blender::CPPType; +using blender::GVArray; + +bool ED_geometry_attribute_convert(Mesh *mesh, + const char *layer_name, + eCustomDataType old_type, + eAttrDomain old_domain, + eCustomDataType new_type, + eAttrDomain new_domain) +{ + CustomDataLayer *layer = BKE_id_attribute_find(&mesh->id, layer_name, old_type, old_domain); + const std::string name = layer->name; + + if (!layer) { + return false; + } + + MeshComponent mesh_component; + mesh_component.replace(mesh, GeometryOwnershipType::Editable); + GVArray src_varray = mesh_component.attribute_get_for_read(name, new_domain, new_type); + + const CPPType &cpp_type = src_varray.type(); + void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__); + src_varray.materialize_to_uninitialized(new_data); + mesh_component.attribute_try_delete(name); + mesh_component.attribute_try_create(name, new_domain, new_type, AttributeInitMove(new_data)); + + int *active_index = BKE_id_attributes_active_index_p(&mesh->id); + if (*active_index > 0) { + *active_index -= 1; + } + + return true; +} diff --git a/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c b/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c index 5b514e02099..429bf39234f 100644 --- a/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c +++ b/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c @@ -7,6 +7,8 @@ #include "../gizmo_geometry.h" +/* The numerical values in the `verts` array are used in arrow3d_gizmo.c + * If you change this mesh geometry, update the selection code also. */ static float verts[][3] = { {-0.000000, 0.012320, 0.000000}, {-0.000000, 0.012320, 0.974306}, {0.008711, 0.008711, 0.000000}, {0.008711, 0.008711, 0.974306}, diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c index a1fb0e205b1..0e7a8873965 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c @@ -50,10 +50,8 @@ /* to use custom arrows exported to geom_arrow_gizmo.c */ //#define USE_GIZMO_CUSTOM_ARROWS -/** Margins to add when selecting the arrow stem. */ -#define ARROW_SELECT_THRESHOLD_PX_STEM (5 * UI_DPI_FAC) -/** Margins to add when selecting the arrow head. */ -#define ARROW_SELECT_THRESHOLD_PX_HEAD (12 * UI_DPI_FAC) +/* Margin to add when selecting the arrow. */ +#define ARROW_SELECT_THRESHOLD_PX (5) typedef struct ArrowGizmo3D { wmGizmo gizmo; @@ -121,8 +119,8 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const }; if (draw_options & ED_GIZMO_ARROW_DRAW_FLAG_STEM) { - const float stem_width = (arrow->gizmo.line_width * U.pixelsize) + - (select ? ARROW_SELECT_THRESHOLD_PX_STEM : 0); + const float stem_width = arrow->gizmo.line_width * U.pixelsize + + (select ? ARROW_SELECT_THRESHOLD_PX * U.dpi_fac : 0); immUniform1f("lineWidth", stem_width); wm_gizmo_vec_draw(color, vec, ARRAY_SIZE(vec), pos, GPU_PRIM_LINE_STRIP); } @@ -134,7 +132,7 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const GPU_matrix_push(); - /* NOTE: ideally #ARROW_SELECT_THRESHOLD_PX_HEAD would be added here, however adding a + /* NOTE: ideally #ARROW_SELECT_THRESHOLD_PX would be added here, however adding a * margin in pixel space isn't so simple, nor is it as important as for the arrow stem. */ if (draw_style == ED_GIZMO_ARROW_STYLE_BOX) { const float size = 0.05f; @@ -223,9 +221,15 @@ static void gizmo_arrow_draw(const bContext *UNUSED(C), wmGizmo *gz) */ static int gizmo_arrow_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mval[2]) { + /* This following values are based on manual inspection of `verts[]` defined in + * geom_arrow_gizmo.c */ + const float head_center_z = (0.974306f + 1.268098f) / 2; + const float head_geo_x = 0.051304f; + const float stem_geo_x = 0.012320f; + /* Project into 2D space since it simplifies pixel threshold tests. */ ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz; - const float arrow_length = RNA_float_get(arrow->gizmo.ptr, "length"); + const float arrow_length = RNA_float_get(arrow->gizmo.ptr, "length") * head_center_z; float matrix_final[4][4]; WM_gizmo_calc_matrix_final(gz, matrix_final); @@ -239,12 +243,15 @@ static int gizmo_arrow_test_select(bContext *UNUSED(C), wmGizmo *gz, const int m copy_v2_v2(arrow_end, co); } + const float scale_final = mat4_to_scale(matrix_final); + const float head_width = ARROW_SELECT_THRESHOLD_PX * scale_final * head_geo_x; + const float stem_width = ARROW_SELECT_THRESHOLD_PX * scale_final * stem_geo_x; + float select_threshold_base = gz->line_width * U.pixelsize; + const float mval_fl[2] = {UNPACK2(mval)}; - const float arrow_stem_threshold_px = ARROW_SELECT_THRESHOLD_PX_STEM; - const float arrow_head_threshold_px = ARROW_SELECT_THRESHOLD_PX_HEAD; /* Distance to arrow head. */ - if (len_squared_v2v2(mval_fl, arrow_end) < square_f(arrow_head_threshold_px)) { + if (len_squared_v2v2(mval_fl, arrow_end) < square_f(select_threshold_base + head_width)) { return 0; } @@ -253,8 +260,8 @@ static int gizmo_arrow_test_select(bContext *UNUSED(C), wmGizmo *gz, const int m const float lambda = closest_to_line_v2(co_isect, mval_fl, arrow_start, arrow_end); /* Clamp inside the line, to avoid overlapping with other gizmos, * especially around the start of the arrow. */ - if (lambda >= 0.0 && lambda <= 1.0) { - if (len_squared_v2v2(mval_fl, co_isect) < square_f(arrow_stem_threshold_px)) { + if (lambda >= 0.0f && lambda <= 1.0f) { + if (len_squared_v2v2(mval_fl, co_isect) < square_f(select_threshold_base + stem_width)) { return 0; } } diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 4f9468cc9c4..0601d009bf7 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -1104,7 +1104,7 @@ static void gpencil_stroke_to_bezier(bContext *C, rad_fac, minmax_weights); - /* shift coord vects */ + /* Shift coord vectors. */ copy_v3_v3(p3d_prev, p3d_cur); copy_v3_v3(p3d_cur, p3d_next); diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 3c8e6d6e5f5..5028baf1589 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -1811,7 +1811,16 @@ static int gpencil_move_to_layer_exec(bContext *C, wmOperator *op) } else { /* Create a new layer. */ - target_layer = BKE_gpencil_layer_addnew(gpd, "GP_Layer", true, false); + PropertyRNA *prop; + char name[128]; + prop = RNA_struct_find_property(op->ptr, "new_layer_name"); + if (RNA_property_is_set(op->ptr, prop)) { + RNA_property_string_get(op->ptr, prop, name); + } + else { + strcpy(name, "GP_Layer"); + } + target_layer = BKE_gpencil_layer_addnew(gpd, name, true, false); } if (target_layer == NULL) { @@ -1888,8 +1897,46 @@ static int gpencil_move_to_layer_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static void layer_new_name_get(bGPdata *gpd, char *rname) +{ + int index = 0; + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + if (strstr(gpl->info, "GP_Layer")) { + index++; + } + } + + if (index == 0) { + BLI_strncpy(rname, "GP_Layer", 128); + return; + } + char *name = BLI_sprintfN("%.*s.%03d", 128, "GP_Layer", index); + BLI_strncpy(rname, name, 128); + MEM_freeN(name); +} + +static int gpencil_move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + Object *ob = CTX_data_active_object(C); + PropertyRNA *prop; + if (RNA_int_get(op->ptr, "layer") == -1) { + prop = RNA_struct_find_property(op->ptr, "new_layer_name"); + if (!RNA_property_is_set(op->ptr, prop)) { + char name[MAX_NAME]; + bGPdata *gpd = ob->data; + layer_new_name_get(gpd, name); + RNA_property_string_set(op->ptr, prop, name); + return WM_operator_props_dialog_popup(C, op, 200); + } + } + + return gpencil_move_to_layer_exec(C, op); +} + void GPENCIL_OT_move_to_layer(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Move Strokes to Layer"; ot->idname = "GPENCIL_OT_move_to_layer"; @@ -1898,15 +1945,20 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot) /* callbacks */ ot->exec = gpencil_move_to_layer_exec; - ot->poll = gpencil_stroke_edit_poll; /* XXX? */ + ot->invoke = gpencil_move_to_layer_invoke; + ot->poll = gpencil_stroke_edit_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* GPencil layer to use. */ - ot->prop = RNA_def_int( - ot->srna, "layer", 0, -1, INT_MAX, "Grease Pencil Layer", "", -1, INT_MAX); - RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_int(ot->srna, "layer", 0, -1, INT_MAX, "Grease Pencil Layer", "", -1, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + prop = RNA_def_string( + ot->srna, "new_layer_name", NULL, MAX_NAME, "Name", "Name of the newly added layer"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + ot->prop = prop; } /** \} */ diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 56c94e4494d..d656241c463 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -726,16 +726,16 @@ struct GP_EditableStrokes_Iter { (void)0 /** - * Iterate over all editable editcurves in the current context, - * stopping on each usable layer + stroke + curve pair (i.e. gpl, gps and gpc) + * Iterate over all editable edit-curves in the current context, + * stopping on each usable layer + stroke + curve pair (i.e. `gpl`, `gps` and `gpc`) * to perform some operations on the curve. * * \param gpl: The identifier to use for the layer of the stroke being processed. - * Choose a suitable value to avoid name clashes. + * Choose a suitable value to avoid name clashes. * \param gps: The identifier to use for current stroke being processed. - * Choose a suitable value to avoid name clashes. + * Choose a suitable value to avoid name clashes. * \param gpc: The identifier to use for current editcurve being processed. - * Choose a suitable value to avoid name clashes. + * Choose a suitable value to avoid name clashes. */ #define GP_EDITABLE_CURVES_BEGIN(gpstroke_iter, C, gpl, gps, gpc) \ { \ diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index 01ac02a9a1d..6d0848de36d 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -829,7 +829,7 @@ static bool gpencil_brush_randomize_apply(tGP_BrushEditData *gso, mul_v2_fl(svec, fac); } - /* convert to dataspace */ + /* Convert to data-space. */ if (gps->flag & GP_STROKE_3DSPACE) { /* 3D: Project to 3D space */ bool flip; diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 23c385c1213..5e8610c6b81 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -525,7 +525,7 @@ bool ED_gpencil_stroke_can_use_direct(const ScrArea *area, const bGPDstroke *gps return (area->spacetype == SPACE_IMAGE); } if (gps->flag & GP_STROKE_2DSPACE) { - /* 2D strokes (dataspace) - for any 2D view (i.e. everything other than 3D view) */ + /* 2D strokes (data-space) - for any 2D view (i.e. everything other than 3D view). */ return (area->spacetype != SPACE_VIEW3D); } /* view aligned - anything goes */ diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h index 3f1b8d6ecda..84512653a24 100644 --- a/source/blender/editors/include/BIF_glutil.h +++ b/source/blender/editors/include/BIF_glutil.h @@ -55,17 +55,17 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin); * finished. */ void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state, - const float x, - const float y, - const int img_w, - const int img_h, - const eGPUTextureFormat gpu_format, - const bool use_filter, + float x, + float y, + int img_w, + int img_h, + eGPUTextureFormat gpu_format, + bool use_filter, const void *rect, - const float scaleX, - const float scaleY, - const float xzoom, - const float yzoom, + float scaleX, + float scaleY, + float xzoom, + float yzoom, const float color[4]); /** diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h index 9f4833bf1d7..061b783797d 100644 --- a/source/blender/editors/include/ED_curve.h +++ b/source/blender/editors/include/ED_curve.h @@ -49,10 +49,12 @@ void ED_curve_editnurb_free(struct Object *obedit); /** * \param dist_px: Maximum distance to pick (in pixels). + * \param vert_without_handles: When true, selecting the knot doesn't select the handles. */ bool ED_curve_editnurb_select_pick(struct bContext *C, const int mval[2], int dist_px, + bool vert_without_handles, const struct SelectPick_Params *params); struct Nurb *ED_curve_add_nurbs_primitive( diff --git a/source/blender/editors/include/ED_geometry.h b/source/blender/editors/include/ED_geometry.h index 74ff968828c..4620181894a 100644 --- a/source/blender/editors/include/ED_geometry.h +++ b/source/blender/editors/include/ED_geometry.h @@ -7,12 +7,22 @@ #pragma once +#include "BKE_attribute.h" +#include "DNA_customdata_types.h" + #ifdef __cplusplus extern "C" { #endif -void ED_operatortypes_geometry(void); +struct Mesh; +void ED_operatortypes_geometry(void); +bool ED_geometry_attribute_convert(struct Mesh *mesh, + const char *layer_name, + eCustomDataType old_type, + eAttrDomain old_domain, + eCustomDataType new_type, + eAttrDomain new_domain); #ifdef __cplusplus } #endif diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index a9a9c98cab8..98c98f99d32 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1866,7 +1866,7 @@ struct PointerRNA *UI_region_panel_custom_data_under_cursor(const struct bContex const struct wmEvent *event); void UI_panel_custom_data_set(struct Panel *panel, struct PointerRNA *custom_data); -/* Polyinstantiated panels for representing a list of data. */ +/* Poly-instantiated panels for representing a list of data. */ /** * Called in situations where panels need to be added dynamically rather than * having only one panel corresponding to each #PanelType. diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c index aec8f56678a..01b958576b6 100644 --- a/source/blender/editors/interface/interface_eyedropper_datablock.c +++ b/source/blender/editors/interface/interface_eyedropper_datablock.c @@ -156,7 +156,7 @@ static void datadropper_id_sample_pt( CTX_wm_area_set(C, area); CTX_wm_region_set(C, region); - /* grr, always draw else we leave stale text */ + /* Unfortunately it's necessary to always draw else we leave stale text. */ ED_region_tag_redraw(region); if (area->spacetype == SPACE_VIEW3D) { diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c index 56bc1a6d956..3c6f127582a 100644 --- a/source/blender/editors/interface/interface_eyedropper_depth.c +++ b/source/blender/editors/interface/interface_eyedropper_depth.c @@ -171,7 +171,7 @@ static void depthdropper_depth_sample_pt(bContext *C, CTX_wm_area_set(C, area); CTX_wm_region_set(C, region); - /* grr, always draw else we leave stale text */ + /* Unfortunately it's necessary to always draw otherwise we leave stale text. */ ED_region_tag_redraw(region); view3d_operator_needs_opengl(C); diff --git a/source/blender/editors/interface/interface_template_attribute_search.cc b/source/blender/editors/interface/interface_template_attribute_search.cc index 65764e31ec8..4e587bd5338 100644 --- a/source/blender/editors/interface/interface_template_attribute_search.cc +++ b/source/blender/editors/interface/interface_template_attribute_search.cc @@ -24,14 +24,14 @@ using blender::nodes::geometry_nodes_eval_log::GeometryAttributeInfo; namespace blender::ui { -static StringRef attribute_data_type_string(const CustomDataType type) +static StringRef attribute_data_type_string(const eCustomDataType type) { const char *name = nullptr; RNA_enum_name_from_value(rna_enum_attribute_type_items, type, &name); return StringRef(IFACE_(name)); } -static StringRef attribute_domain_string(const AttributeDomain domain) +static StringRef attribute_domain_string(const eAttrDomain domain) { const char *name = nullptr; RNA_enum_name_from_value(rna_enum_attribute_domain_items, domain, &name); diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c index 609230eefea..8a24b48be5e 100644 --- a/source/blender/editors/io/io_usd.c +++ b/source/blender/editors/io/io_usd.c @@ -217,6 +217,7 @@ void WM_OT_usd_export(struct wmOperatorType *ot) ot->check = wm_usd_export_check; ot->flag = OPTYPE_REGISTER; /* No UNDO possible. */ + ot->flag |= OPTYPE_PRESET; WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_USD, diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index 41af8bcfef5..9e28dbcb803 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -182,7 +182,7 @@ void paintface_reveal(bContext *C, Object *ob, const bool select) paintface_flush_flags(C, ob, SELECT, true); } -/* Set tface seams based on edge data, uses hash table to find seam edges. */ +/* Set object-mode face selection seams based on edge data, uses hash table to find seam edges. */ static void select_linked_tfaces_with_seams(Mesh *me, const uint index, const bool select) { diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 5b3487b0a33..c16b82e34bd 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -4672,6 +4672,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event) case MOUSEMOVE: /* Mouse moved somewhere to select another loop. */ if (kcd->mode != MODE_PANNING) { knifetool_update_mval_i(kcd, event->mval); + knife_update_header(C, op, kcd); if (kcd->is_drag_hold) { if (kcd->totlinehit >= 2) { @@ -4754,6 +4755,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event) /* We don't really need to update mval, * but this happens to be the best way to refresh at the moment. */ knifetool_update_mval_i(kcd, event->mval); + knife_update_header(C, op, kcd); } /* Keep going until the user confirms. */ diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index ecc5f8f8ef5..d75c92f963f 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -72,7 +72,7 @@ static CLG_LogRef LOG = {"ed.undo.mesh"}; /* Single linked list of layers stored per type */ typedef struct BArrayCustomData { struct BArrayCustomData *next; - CustomDataType type; + eCustomDataType type; int states_len; /* number of layers for each type */ BArrayState *states[0]; } BArrayCustomData; @@ -149,7 +149,7 @@ static void um_arraystore_cd_compact(struct CustomData *cdata, const BArrayCustomData *bcd_reference_current = bcd_reference; BArrayCustomData *bcd = NULL, *bcd_first = NULL, *bcd_prev = NULL; for (int layer_start = 0, layer_end; layer_start < cdata->totlayer; layer_start = layer_end) { - const CustomDataType type = cdata->layers[layer_start].type; + const eCustomDataType type = cdata->layers[layer_start].type; /* Perform a full copy on dynamic layers. * diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc index 422aaa03120..5e09948e192 100644 --- a/source/blender/editors/object/object_add.cc +++ b/source/blender/editors/object/object_add.cc @@ -621,9 +621,16 @@ Object *ED_object_add_type_with_obdata(bContext *C, else { ob = BKE_object_add(bmain, view_layer, type, name); } - BASACT(view_layer)->local_view_bits = local_view_bits; - /* editor level activate, notifiers */ - ED_object_base_activate(C, view_layer->basact); + + Base *ob_base_act = BASACT(view_layer); + /* While not getting a valid base is not a good thing, it can happen in convoluted corner cases, + * better not crash on it in releases. */ + BLI_assert(ob_base_act != nullptr); + if (ob_base_act != nullptr) { + ob_base_act->local_view_bits = local_view_bits; + /* editor level activate, notifiers */ + ED_object_base_activate(C, ob_base_act); + } /* more editor stuff */ ED_object_base_init_transform_on_add(ob, loc, rot); diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index 1483c24ac70..effbde41c38 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -220,22 +220,22 @@ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *l MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0); Mesh *me = (Mesh *)ob->data; MultiresModifierData tmp_mmd = *mmd; - DerivedMesh *cddm = CDDM_from_mesh(me); - DM_set_only_copy(cddm, &CD_MASK_BAREMESH); + *lvl = mmd->lvl; if (mmd->lvl == 0) { - dm = CDDM_copy(cddm); - } - else { - tmp_mmd.lvl = mmd->lvl; - tmp_mmd.sculptlvl = mmd->lvl; - dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, 0); + DerivedMesh *cddm = CDDM_from_mesh(me); + DM_set_only_copy(cddm, &CD_MASK_BAREMESH); + return cddm; } - cddm->release(cddm); + DerivedMesh *cddm = CDDM_from_mesh(me); + DM_set_only_copy(cddm, &CD_MASK_BAREMESH); + tmp_mmd.lvl = mmd->lvl; + tmp_mmd.sculptlvl = mmd->lvl; + dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, 0); - *lvl = mmd->lvl; + cddm->release(cddm); return dm; } diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 114b2ce8102..006379123f8 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -21,6 +21,7 @@ #include "BLI_path_util.h" #include "BLI_string.h" +#include "BKE_callbacks.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_image.h" @@ -1535,7 +1536,7 @@ static int bake(const BakeAPIRender *bkr, ob_low_eval->obmat); } else { - /* from multiresolution */ + /* From multi-resolution. */ Mesh *me_nores = NULL; ModifierData *md = NULL; int mode; @@ -1806,6 +1807,17 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa RE_SetReports(bkr->render, NULL); } +static void bake_job_complete(void *bkv) +{ + BakeAPIRender *bkr = (BakeAPIRender *)bkv; + BKE_callback_exec_id(bkr->main, &bkr->ob->id, BKE_CB_EVT_OBJECT_BAKE_COMPLETE); +} +static void bake_job_canceled(void *bkv) +{ + BakeAPIRender *bkr = (BakeAPIRender *)bkv; + BKE_callback_exec_id(bkr->main, &bkr->ob->id, BKE_CB_EVT_OBJECT_BAKE_CANCEL); +} + static void bake_freejob(void *bkv) { BakeAPIRender *bkr = (BakeAPIRender *)bkv; @@ -1941,6 +1953,7 @@ static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event) /* init bake render */ bake_init_api_data(op, C, bkr); + BKE_callback_exec_id(CTX_data_main(C), &bkr->ob->id, BKE_CB_EVT_OBJECT_BAKE_PRE); re = bkr->render; /* setup new render */ @@ -1958,7 +1971,8 @@ static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event) /* TODO: only draw bake image, can we enforce this. */ WM_jobs_timer( wm_job, 0.5, (bkr->target == R_BAKE_TARGET_VERTEX_COLORS) ? NC_GEOM | ND_DATA : NC_IMAGE, 0); - WM_jobs_callbacks(wm_job, bake_startjob, NULL, NULL, NULL); + WM_jobs_callbacks_ex( + wm_job, bake_startjob, NULL, NULL, NULL, bake_job_complete, bake_job_canceled); G.is_break = false; G.is_rendering = true; diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index d982d86fe77..bf3b71178e8 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -245,13 +245,11 @@ static void set_constraint_nth_target(bConstraint *con, const char subtarget[], int index) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; int num_targets, i; - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); + if (BKE_constraint_targets_get(con, &targets)) { num_targets = BLI_listbase_count(&targets); if (index < 0) { @@ -274,9 +272,7 @@ static void set_constraint_nth_target(bConstraint *con, } } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 0); - } + BKE_constraint_targets_flush(con, &targets, 0); } } @@ -289,7 +285,6 @@ static void set_constraint_nth_target(bConstraint *con, static void test_constraint( Main *bmain, Object *owner, bPoseChannel *pchan, bConstraint *con, int type) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; bool check_targets = true; @@ -465,14 +460,7 @@ static void test_constraint( } /* Check targets for constraints */ - if (check_targets && cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - /* constraints with empty target list that actually require targets */ - if (!targets.first && ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) { - con->flag |= CONSTRAINT_DISABLE; - } - + if (check_targets && BKE_constraint_targets_get(con, &targets)) { /* disable and clear constraints targets that are incorrect */ for (ct = targets.first; ct; ct = ct->next) { /* general validity checks (for those constraints that need this) */ @@ -543,8 +531,12 @@ static void test_constraint( } /* free any temporary targets */ - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 0); + BKE_constraint_targets_flush(con, &targets, 0); + } + else if (check_targets) { + /* constraints with empty target list that actually require targets */ + if (ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) { + con->flag |= CONSTRAINT_DISABLE; } } } diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index b9a4c79ac03..4837b538bf6 100644 --- a/source/blender/editors/object/object_data_transfer.c +++ b/source/blender/editors/object/object_data_transfer.c @@ -88,14 +88,14 @@ static const EnumPropertyItem DT_layer_items[] = { }; static void dt_add_vcol_layers(CustomData *cdata, - CustomDataMask mask, + eCustomDataMask mask, EnumPropertyItem **r_item, int *r_totitem) { int types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR}; for (int i = 0; i < 2; i++) { - CustomDataType type = types[i]; + eCustomDataType type = types[i]; if (!(mask & CD_TYPE_AS_MASK(type))) { continue; diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 1067c2d6a95..8a0d380ff2f 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -281,7 +281,7 @@ void ED_operatormacros_object(void) ot = WM_operatortype_append_macro("OBJECT_OT_duplicate_move", "Duplicate Objects", - "Duplicate selected objects and move them", + "Duplicate the selected objects and move them", OPTYPE_UNDO | OPTYPE_REGISTER); if (ot) { WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate"); @@ -289,11 +289,11 @@ void ED_operatormacros_object(void) RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false); } - /* grr, should be able to pass options on... */ - ot = WM_operatortype_append_macro("OBJECT_OT_duplicate_move_linked", - "Duplicate Linked", - "Duplicate selected objects and move them", - OPTYPE_UNDO | OPTYPE_REGISTER); + ot = WM_operatortype_append_macro( + "OBJECT_OT_duplicate_move_linked", + "Duplicate Linked", + "Duplicate the selected objects, but not their object data, and move them", + OPTYPE_UNDO | OPTYPE_REGISTER); if (ot) { otmacro = WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate"); RNA_boolean_set(otmacro->ptr, "linked", true); diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 39c664193f1..0a18ad7c50d 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -4269,7 +4269,6 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr) Mesh *me = ob->data; BMEditMesh *em = me->edit_mesh; - float weight_act; int i; if (em) { @@ -4281,18 +4280,15 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr) if (dvert_act == NULL) { return; } - weight_act = BKE_defvert_find_weight(dvert_act, def_nr); BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && (eve != eve_act)) { - MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr); - if (dw) { - dw->weight = weight_act; + MDeformVert *dvert_dst = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - if (me->symmetry & ME_SYMMETRY_X) { - ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset); - } + BKE_defvert_copy_index(dvert_dst, def_nr, dvert_act, def_nr); + + if (me->symmetry & ME_SYMMETRY_X) { + ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset); } } } @@ -4309,17 +4305,15 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr) if (dvert_act == NULL) { return; } - weight_act = BKE_defvert_find_weight(dvert_act, def_nr); dv = me->dvert; for (i = 0; i < me->totvert; i++, dv++) { if ((me->mvert[i].flag & SELECT) && (dv != dvert_act)) { - MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr); - if (dw) { - dw->weight = weight_act; - if (me->symmetry & ME_SYMMETRY_X) { - ED_mesh_defvert_mirror_update_ob(ob, -1, i); - } + + BKE_defvert_copy_index(dv, def_nr, dvert_act, def_nr); + + if (me->symmetry & ME_SYMMETRY_X) { + ED_mesh_defvert_mirror_update_ob(ob, -1, i); } } } diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 43c19670a41..08c8c863729 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -626,8 +626,8 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win) screen_geom_vertices_scale(win, screen); ED_screen_areas_iter (win, screen, area) { - /* set spacetype and region callbacks, calls init() */ - /* sets subwindows for regions, adds handlers */ + /* Set space-type and region callbacks, calls init() */ + /* Sets sub-windows for regions, adds handlers. */ ED_area_init(wm, win, area); } diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index a922e5aaaee..3022bbbd42c 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -1477,7 +1477,7 @@ static int area_close_exec(bContext *C, wmOperator *op) bScreen *screen = CTX_wm_screen(C); ScrArea *area = CTX_wm_area(C); - /* This operator is scriptable, so the area passed could be invalid. */ + /* This operator is script-able, so the area passed could be invalid. */ if (BLI_findindex(&screen->areabase, area) == -1) { BKE_report(op->reports, RPT_ERROR, "Area not found in the active screen"); return OPERATOR_CANCELLED; @@ -2722,7 +2722,7 @@ static int region_scale_invoke(bContext *C, wmOperator *op, const wmEvent *event rmd->region->sizey = rmd->region->winy; } - /* now copy to regionmovedata */ + /* Now copy to region-move-data. */ if (ELEM(rmd->edge, AE_LEFT_TO_TOPRIGHT, AE_RIGHT_TO_TOPLEFT)) { rmd->origval = rmd->region->sizex; } diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index d3bf28798c4..dfd8f8b1bb9 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -33,6 +33,8 @@ set(SRC curves_sculpt_delete.cc curves_sculpt_grow_shrink.cc curves_sculpt_ops.cc + curves_sculpt_selection.cc + curves_sculpt_selection_paint.cc curves_sculpt_snake_hook.cc paint_canvas.cc paint_cursor.c diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc index d7f4b71d2d0..390f142ac0f 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc @@ -85,10 +85,7 @@ static void initialize_straight_curve_positions(const float3 &p1, */ struct AddOperationExecutor { AddOperation *self_ = nullptr; - const Depsgraph *depsgraph_ = nullptr; - const Scene *scene_ = nullptr; - ARegion *region_ = nullptr; - const View3D *v3d_ = nullptr; + CurvesSculptCommonContext ctx_; Object *object_ = nullptr; Curves *curves_id_ = nullptr; @@ -143,14 +140,14 @@ struct AddOperationExecutor { static constexpr int max_neighbors = 5; using NeighborsVector = Vector<NeighborInfo, max_neighbors>; + AddOperationExecutor(const bContext &C) : ctx_(C) + { + } + void execute(AddOperation &self, const bContext &C, const StrokeExtension &stroke_extension) { self_ = &self; - depsgraph_ = CTX_data_depsgraph_pointer(&C); - scene_ = CTX_data_scene(&C); object_ = CTX_data_active_object(&C); - region_ = CTX_wm_region(&C); - v3d_ = CTX_wm_view3d(&C); curves_id_ = static_cast<Curves *>(object_->data); curves_ = &CurvesGeometry::wrap(curves_id_->geometry); @@ -176,10 +173,10 @@ struct AddOperationExecutor { reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_->ldata, CD_NORMAL)), surface_->totloop}; - curves_sculpt_ = scene_->toolsettings->curves_sculpt; + curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt; brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint); brush_settings_ = brush_->curves_sculpt_settings; - brush_radius_re_ = brush_radius_get(*scene_, *brush_, stroke_extension); + brush_radius_re_ = brush_radius_get(*ctx_.scene, *brush_, stroke_extension); brush_pos_re_ = stroke_extension.mouse_position; use_front_face_ = brush_->flag & BRUSH_FRONTFACE; @@ -256,7 +253,7 @@ struct AddOperationExecutor { DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id); - ED_region_tag_redraw(region_); + ED_region_tag_redraw(ctx_.region); } float3 get_bary_coords(const Mesh &mesh, const MLoopTri &looptri, const float3 position) const @@ -276,7 +273,7 @@ struct AddOperationExecutor { { float3 ray_start_wo, ray_end_wo; ED_view3d_win_to_segment_clipped( - depsgraph_, region_, v3d_, brush_pos_re_, ray_start_wo, ray_end_wo, true); + ctx_.depsgraph, ctx_.region, ctx_.v3d, brush_pos_re_, ray_start_wo, ray_end_wo, true); const float3 ray_start_su = world_to_surface_mat_ * ray_start_wo; const float3 ray_end_su = world_to_surface_mat_ * ray_end_wo; @@ -352,7 +349,7 @@ struct AddOperationExecutor { float3 ray_start_wo, ray_end_wo; ED_view3d_win_to_segment_clipped( - depsgraph_, region_, v3d_, pos_re, ray_start_wo, ray_end_wo, true); + ctx_.depsgraph, ctx_.region, ctx_.v3d, pos_re, ray_start_wo, ray_end_wo, true); const float3 ray_start_su = brush_transform * (world_to_surface_mat_ * ray_start_wo); const float3 ray_end_su = brush_transform * (world_to_surface_mat_ * ray_end_wo); const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su); @@ -400,17 +397,22 @@ struct AddOperationExecutor { { /* Find ray that starts in the center of the brush. */ float3 brush_ray_start_wo, brush_ray_end_wo; - ED_view3d_win_to_segment_clipped( - depsgraph_, region_, v3d_, brush_pos_re_, brush_ray_start_wo, brush_ray_end_wo, true); + ED_view3d_win_to_segment_clipped(ctx_.depsgraph, + ctx_.region, + ctx_.v3d, + brush_pos_re_, + brush_ray_start_wo, + brush_ray_end_wo, + true); const float3 brush_ray_start_su = world_to_surface_mat_ * brush_ray_start_wo; const float3 brush_ray_end_su = world_to_surface_mat_ * brush_ray_end_wo; /* Find ray that starts on the boundary of the brush. That is used to compute the brush radius * in 3D. */ float3 brush_radius_ray_start_wo, brush_radius_ray_end_wo; - ED_view3d_win_to_segment_clipped(depsgraph_, - region_, - v3d_, + ED_view3d_win_to_segment_clipped(ctx_.depsgraph, + ctx_.region, + ctx_.v3d, brush_pos_re_ + float2(brush_radius_re_, 0), brush_radius_ray_start_wo, brush_radius_ray_end_wo, @@ -652,6 +654,8 @@ struct AddOperationExecutor { Array<float3> new_normals_su = this->compute_normals_for_added_curves_su(added_points); this->initialize_surface_attachment(added_points); + this->fill_new_selection(); + if (interpolate_shape_) { this->initialize_position_with_interpolation( added_points, neighbors_per_curve, new_normals_su, new_lengths_cu); @@ -662,6 +666,33 @@ struct AddOperationExecutor { } } + /** + * Select newly created points or curves in new curves if necessary. + */ + void fill_new_selection() + { + switch (curves_id_->selection_domain) { + case ATTR_DOMAIN_CURVE: { + const VArray<float> selection = curves_->selection_curve_float(); + if (selection.is_single() && selection.get_internal_single() >= 1.0f) { + return; + } + curves_->selection_curve_float_for_write().drop_front(tot_old_curves_).fill(1.0f); + break; + } + case ATTR_DOMAIN_POINT: { + const VArray<float> selection = curves_->selection_point_float(); + if (selection.is_single() && selection.get_internal_single() >= 1.0f) { + return; + } + curves_->selection_point_float_for_write().drop_front(tot_old_points_).fill(1.0f); + break; + } + default: + BLI_assert_unreachable(); + } + } + Array<NeighborsVector> find_curve_neighbors(const AddedPoints &added_points) { const int tot_added_curves = added_points.bary_coords.size(); @@ -866,7 +897,7 @@ struct AddOperationExecutor { void AddOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) { - AddOperationExecutor executor; + AddOperationExecutor executor{C}; executor.execute(*this, C, stroke_extension); } diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc index 92ce6ba3153..11d3548a082 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc @@ -13,6 +13,7 @@ #include "UI_interface.h" #include "BLI_enumerable_thread_specific.hh" +#include "BLI_length_parameterize.hh" #include "BLI_task.hh" /** @@ -277,4 +278,44 @@ Vector<float4x4> get_symmetry_brush_transforms(const eCurvesSymmetryType symmetr return matrices; } +void move_last_point_and_resample(MutableSpan<float3> positions, const float3 &new_last_position) +{ + /* Find the accumulated length of each point in the original curve, + * treating it as a poly curve for performance reasons and simplicity. */ + Array<float> orig_lengths(length_parameterize::lengths_num(positions.size(), false)); + length_parameterize::accumulate_lengths<float3>(positions, false, orig_lengths); + const float orig_total_length = orig_lengths.last(); + + /* Find the factor by which the new curve is shorter or longer than the original. */ + const float new_last_segment_length = math::distance(positions.last(1), new_last_position); + const float new_total_length = orig_lengths.last(1) + new_last_segment_length; + const float length_factor = safe_divide(new_total_length, orig_total_length); + + /* Calculate the lengths to sample the original curve with by scaling the original lengths. */ + Array<float> new_lengths(positions.size() - 1); + new_lengths.first() = 0.0f; + for (const int i : new_lengths.index_range().drop_front(1)) { + new_lengths[i] = orig_lengths[i - 1] * length_factor; + } + + Array<int> indices(positions.size() - 1); + Array<float> factors(positions.size() - 1); + length_parameterize::create_samples_from_sorted_lengths( + orig_lengths, new_lengths, false, indices, factors); + + Array<float3> new_positions(positions.size() - 1); + length_parameterize::linear_interpolation<float3>(positions, indices, factors, new_positions); + positions.drop_back(1).copy_from(new_positions); + positions.last() = new_last_position; +} + +CurvesSculptCommonContext::CurvesSculptCommonContext(const bContext &C) +{ + this->depsgraph = CTX_data_depsgraph_pointer(&C); + this->scene = CTX_data_scene(&C); + this->region = CTX_wm_region(&C); + this->v3d = CTX_wm_view3d(&C); + this->rv3d = CTX_wm_region_view3d(&C); +} + } // namespace blender::ed::sculpt_paint diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc index 1fcab2290e8..71f08cce8ff 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc @@ -78,11 +78,7 @@ class CombOperation : public CurvesSculptStrokeOperation { */ struct CombOperationExecutor { CombOperation *self_ = nullptr; - const Depsgraph *depsgraph_ = nullptr; - const Scene *scene_ = nullptr; - ARegion *region_ = nullptr; - const View3D *v3d_ = nullptr; - const RegionView3D *rv3d_ = nullptr; + CurvesSculptCommonContext ctx_; const CurvesSculpt *curves_sculpt_ = nullptr; const Brush *brush_ = nullptr; @@ -96,9 +92,9 @@ struct CombOperationExecutor { Curves *curves_id_ = nullptr; CurvesGeometry *curves_ = nullptr; - const Object *surface_ob_ = nullptr; - const Mesh *surface_ = nullptr; - Span<MLoopTri> surface_looptris_; + VArray<float> point_factors_; + Vector<int64_t> selected_curve_indices_; + IndexMask curve_selection_; float2 brush_pos_prev_re_; float2 brush_pos_re_; @@ -110,7 +106,9 @@ struct CombOperationExecutor { float4x4 surface_to_world_mat_; float4x4 world_to_surface_mat_; - BVHTreeFromMesh surface_bvh_; + CombOperationExecutor(const bContext &C) : ctx_(C) + { + } void execute(CombOperation &self, const bContext &C, const StrokeExtension &stroke_extension) { @@ -118,18 +116,13 @@ struct CombOperationExecutor { BLI_SCOPED_DEFER([&]() { self_->brush_pos_last_re_ = stroke_extension.mouse_position; }); - depsgraph_ = CTX_data_depsgraph_pointer(&C); - scene_ = CTX_data_scene(&C); object_ = CTX_data_active_object(&C); - region_ = CTX_wm_region(&C); - v3d_ = CTX_wm_view3d(&C); - rv3d_ = CTX_wm_region_view3d(&C); - curves_sculpt_ = scene_->toolsettings->curves_sculpt; + curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt; brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint); - brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_); + brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_); brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension); - brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension); + brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension); curves_to_world_mat_ = object_->obmat; world_to_curves_mat_ = curves_to_world_mat_.inverted(); @@ -142,27 +135,14 @@ struct CombOperationExecutor { return; } + point_factors_ = get_point_selection(*curves_id_); + curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_); + brush_pos_prev_re_ = self_->brush_pos_last_re_; brush_pos_re_ = stroke_extension.mouse_position; brush_pos_diff_re_ = brush_pos_re_ - brush_pos_prev_re_; brush_pos_diff_length_re_ = math::length(brush_pos_diff_re_); - surface_ob_ = curves_id_->surface; - if (surface_ob_ != nullptr) { - surface_ = static_cast<const Mesh *>(surface_ob_->data); - surface_looptris_ = {BKE_mesh_runtime_looptri_ensure(surface_), - BKE_mesh_runtime_looptri_len(surface_)}; - surface_to_world_mat_ = surface_ob_->obmat; - world_to_surface_mat_ = surface_to_world_mat_.inverted(); - BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2); - } - - BLI_SCOPED_DEFER([&]() { - if (surface_ob_ != nullptr) { - free_bvhtree_from_mesh(&surface_bvh_); - } - }); - if (stroke_extension.is_first) { if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) { this->initialize_spherical_brush_reference_point(); @@ -189,7 +169,7 @@ struct CombOperationExecutor { curves_->tag_positions_changed(); DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id); - ED_region_tag_redraw(region_); + ED_region_tag_redraw(ctx_.region); } /** @@ -212,14 +192,14 @@ struct CombOperationExecutor { MutableSpan<float3> positions_cu = curves_->positions_for_write(); float4x4 projection; - ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values); + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_; const float brush_radius_sq_re = pow2f(brush_radius_re); - threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) { + threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) { Vector<int> &local_changed_curves = r_changed_curves.local(); - for (const int curve_i : curves_range) { + for (const int curve_i : curve_selection_.slice(range)) { bool curve_changed = false; const IndexRange points = curves_->points_for_curve(curve_i); for (const int point_i : points.drop_front(1)) { @@ -227,7 +207,7 @@ struct CombOperationExecutor { /* Find the position of the point in screen space. */ float2 old_pos_re; - ED_view3d_project_float_v2_m4(region_, old_pos_cu, old_pos_re, projection.values); + ED_view3d_project_float_v2_m4(ctx_.region, old_pos_cu, old_pos_re, projection.values); const float distance_to_brush_sq_re = dist_squared_to_line_segment_v2( old_pos_re, brush_pos_prev_re_, brush_pos_re_); @@ -241,13 +221,17 @@ struct CombOperationExecutor { const float radius_falloff = BKE_brush_curve_strength( brush_, distance_to_brush_re, brush_radius_re); /* Combine the falloff and brush strength. */ - const float weight = brush_strength_ * radius_falloff; + const float weight = brush_strength_ * radius_falloff * point_factors_[point_i]; - /* Offset the old point position in screen space and transform it back into 3D space. */ + /* Offset the old point position in screen space and transform it back into 3D space. + */ const float2 new_position_re = old_pos_re + brush_pos_diff_re_ * weight; float3 new_position_wo; - ED_view3d_win_to_3d( - v3d_, region_, curves_to_world_mat_ * old_pos_cu, new_position_re, new_position_wo); + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, + curves_to_world_mat_ * old_pos_cu, + new_position_re, + new_position_wo); const float3 new_position_cu = brush_transform * (world_to_curves_mat_ * new_position_wo); positions_cu[point_i] = new_position_cu; @@ -267,16 +251,16 @@ struct CombOperationExecutor { void comb_spherical_with_symmetry(EnumerableThreadSpecific<Vector<int>> &r_changed_curves) { float4x4 projection; - ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values); + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); float3 brush_start_wo, brush_end_wo; - ED_view3d_win_to_3d(v3d_, - region_, + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, curves_to_world_mat_ * self_->brush_3d_.position_cu, brush_pos_prev_re_, brush_start_wo); - ED_view3d_win_to_3d(v3d_, - region_, + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, curves_to_world_mat_ * self_->brush_3d_.position_cu, brush_pos_re_, brush_end_wo); @@ -304,9 +288,9 @@ struct CombOperationExecutor { const float brush_radius_sq_cu = pow2f(brush_radius_cu); const float3 brush_diff_cu = brush_end_cu - brush_start_cu; - threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) { + threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) { Vector<int> &local_changed_curves = r_changed_curves.local(); - for (const int curve_i : curves_range) { + for (const int curve_i : curve_selection_.slice(range)) { bool curve_changed = false; const IndexRange points = curves_->points_for_curve(curve_i); for (const int point_i : points.drop_front(1)) { @@ -326,7 +310,7 @@ struct CombOperationExecutor { const float radius_falloff = BKE_brush_curve_strength( brush_, distance_to_brush_cu, brush_radius_cu); /* Combine the falloff and brush strength. */ - const float weight = brush_strength_ * radius_falloff; + const float weight = brush_strength_ * radius_falloff * point_factors_[point_i]; /* Update the point position. */ positions_cu[point_i] = pos_old_cu + weight * brush_diff_cu; @@ -344,8 +328,13 @@ struct CombOperationExecutor { */ void initialize_spherical_brush_reference_point() { - std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush( - *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_); + std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph, + *ctx_.region, + *ctx_.v3d, + *ctx_.rv3d, + *object_, + brush_pos_re_, + brush_radius_base_re_); if (brush_3d.has_value()) { self_->brush_3d_ = *brush_3d; } @@ -399,7 +388,7 @@ struct CombOperationExecutor { void CombOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) { - CombOperationExecutor executor; + CombOperationExecutor executor{C}; executor.execute(*this, C, stroke_extension); } diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc index 323e99df099..6f12d539aa2 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc @@ -60,16 +60,15 @@ class DeleteOperation : public CurvesSculptStrokeOperation { struct DeleteOperationExecutor { DeleteOperation *self_ = nullptr; - const Depsgraph *depsgraph_ = nullptr; - const Scene *scene_ = nullptr; - ARegion *region_ = nullptr; - const View3D *v3d_ = nullptr; - const RegionView3D *rv3d_ = nullptr; + CurvesSculptCommonContext ctx_; Object *object_ = nullptr; Curves *curves_id_ = nullptr; CurvesGeometry *curves_ = nullptr; + Vector<int64_t> selected_curve_indices_; + IndexMask curve_selection_; + const CurvesSculpt *curves_sculpt_ = nullptr; const Brush *brush_ = nullptr; float brush_radius_base_re_; @@ -80,23 +79,24 @@ struct DeleteOperationExecutor { float4x4 curves_to_world_mat_; float4x4 world_to_curves_mat_; - void execute(DeleteOperation &self, const bContext &C, const StrokeExtension &stroke_extension) + DeleteOperationExecutor(const bContext &C) : ctx_(C) { + } + void execute(DeleteOperation &self, const bContext &C, const StrokeExtension &stroke_extension) + { self_ = &self; - depsgraph_ = CTX_data_depsgraph_pointer(&C); - scene_ = CTX_data_scene(&C); object_ = CTX_data_active_object(&C); - region_ = CTX_wm_region(&C); - v3d_ = CTX_wm_view3d(&C); - rv3d_ = CTX_wm_region_view3d(&C); curves_id_ = static_cast<Curves *>(object_->data); curves_ = &CurvesGeometry::wrap(curves_id_->geometry); - curves_sculpt_ = scene_->toolsettings->curves_sculpt; + selected_curve_indices_.clear(); + curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_); + + curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt; brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint); - brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_); + brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_); brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension); brush_pos_re_ = stroke_extension.mouse_position; @@ -134,7 +134,7 @@ struct DeleteOperationExecutor { DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id); - ED_region_tag_redraw(region_); + ED_region_tag_redraw(ctx_.region); } void delete_projected_with_symmetry(MutableSpan<bool> curves_to_delete) @@ -151,20 +151,20 @@ struct DeleteOperationExecutor { const float4x4 brush_transform_inv = brush_transform.inverted(); float4x4 projection; - ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values); + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); Span<float3> positions_cu = curves_->positions(); const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_; const float brush_radius_sq_re = pow2f(brush_radius_re); - threading::parallel_for(curves_->curves_range(), 512, [&](IndexRange curve_range) { - for (const int curve_i : curve_range) { + threading::parallel_for(curve_selection_.index_range(), 512, [&](const IndexRange range) { + for (const int curve_i : curve_selection_.slice(range)) { const IndexRange points = curves_->points_for_curve(curve_i); if (points.size() == 1) { const float3 pos_cu = brush_transform_inv * positions_cu[points.first()]; float2 pos_re; - ED_view3d_project_float_v2_m4(region_, pos_cu, pos_re, projection.values); + ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values); if (math::distance_squared(brush_pos_re_, pos_re) <= brush_radius_sq_re) { curves_to_delete[curve_i] = true; @@ -177,8 +177,8 @@ struct DeleteOperationExecutor { const float3 pos2_cu = brush_transform_inv * positions_cu[segment_i + 1]; float2 pos1_re, pos2_re; - ED_view3d_project_float_v2_m4(region_, pos1_cu, pos1_re, projection.values); - ED_view3d_project_float_v2_m4(region_, pos2_cu, pos2_re, projection.values); + ED_view3d_project_float_v2_m4(ctx_.region, pos1_cu, pos1_re, projection.values); + ED_view3d_project_float_v2_m4(ctx_.region, pos2_cu, pos2_re, projection.values); const float dist_sq_re = dist_squared_to_line_segment_v2( brush_pos_re_, pos1_re, pos2_re); @@ -194,11 +194,11 @@ struct DeleteOperationExecutor { void delete_spherical_with_symmetry(MutableSpan<bool> curves_to_delete) { float4x4 projection; - ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values); + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); float3 brush_wo; - ED_view3d_win_to_3d(v3d_, - region_, + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, curves_to_world_mat_ * self_->brush_3d_.position_cu, brush_pos_re_, brush_wo); @@ -219,8 +219,8 @@ struct DeleteOperationExecutor { const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_; const float brush_radius_sq_cu = pow2f(brush_radius_cu); - threading::parallel_for(curves_->curves_range(), 512, [&](IndexRange curve_range) { - for (const int curve_i : curve_range) { + threading::parallel_for(curve_selection_.index_range(), 512, [&](const IndexRange range) { + for (const int curve_i : curve_selection_.slice(range)) { const IndexRange points = curves_->points_for_curve(curve_i); if (points.size() == 1) { @@ -249,8 +249,13 @@ struct DeleteOperationExecutor { void initialize_spherical_brush_reference_point() { - std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush( - *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_); + std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph, + *ctx_.region, + *ctx_.v3d, + *ctx_.rv3d, + *object_, + brush_pos_re_, + brush_radius_base_re_); if (brush_3d.has_value()) { self_->brush_3d_ = *brush_3d; } @@ -260,7 +265,7 @@ struct DeleteOperationExecutor { void DeleteOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) { - DeleteOperationExecutor executor; + DeleteOperationExecutor executor{C}; executor.execute(*this, C, stroke_extension); } diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc index 25eb8041f4c..3420659520b 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc @@ -151,50 +151,10 @@ class ExtrapolateCurvesEffect : public CurvesEffect { const float3 direction = math::normalize(old_last_pos_cu - direction_reference_point); const float3 new_last_pos_cu = old_last_pos_cu + direction * move_distance_cu; - this->move_last_point_and_resample(positions_cu, curve_points, new_last_pos_cu); + move_last_point_and_resample(positions_cu.slice(curve_points), new_last_pos_cu); } }); } - - void move_last_point_and_resample(MutableSpan<float3> positions, - const IndexRange curve_points, - const float3 &new_last_point_position) const - { - Vector<float> old_lengths; - old_lengths.append(0.0f); - /* Used to (1) normalize the segment sizes over time and (2) support making zero-length - * segments */ - const float extra_length = 0.001f; - for (const int segment_i : IndexRange(curve_points.size() - 1)) { - const float3 &p1 = positions[curve_points[segment_i]]; - const float3 &p2 = positions[curve_points[segment_i] + 1]; - const float length = math::distance(p1, p2); - old_lengths.append(old_lengths.last() + length + extra_length); - } - Vector<float> point_factors; - for (float &old_length : old_lengths) { - point_factors.append(old_length / old_lengths.last()); - } - - PolySpline new_spline; - new_spline.resize(curve_points.size()); - MutableSpan<float3> new_spline_positions = new_spline.positions(); - for (const int i : IndexRange(curve_points.size() - 1)) { - new_spline_positions[i] = positions[curve_points[i]]; - } - new_spline_positions.last() = new_last_point_position; - new_spline.mark_cache_invalid(); - - for (const int i : IndexRange(curve_points.size())) { - const float factor = point_factors[i]; - const Spline::LookupResult lookup = new_spline.lookup_evaluated_factor(factor); - const float index_factor = lookup.evaluated_index + lookup.factor; - float3 p; - new_spline.sample_with_index_factors<float3>( - new_spline_positions, {&index_factor, 1}, {&p, 1}); - positions[curve_points[i]] = p; - } - } }; /** @@ -270,16 +230,16 @@ class CurvesEffectOperation : public CurvesSculptStrokeOperation { */ struct CurvesEffectOperationExecutor { CurvesEffectOperation *self_ = nullptr; - const Depsgraph *depsgraph_ = nullptr; - const Scene *scene_ = nullptr; - ARegion *region_ = nullptr; - const View3D *v3d_ = nullptr; - const RegionView3D *rv3d_ = nullptr; + CurvesSculptCommonContext ctx_; Object *object_ = nullptr; Curves *curves_id_ = nullptr; CurvesGeometry *curves_ = nullptr; + VArray<float> curve_selection_factors_; + Vector<int64_t> selected_curve_indices_; + IndexMask curve_selection_; + const Brush *brush_ = nullptr; float brush_radius_base_re_; float brush_radius_factor_; @@ -298,6 +258,10 @@ struct CurvesEffectOperationExecutor { Vector<float> move_distances_cu; }; + CurvesEffectOperationExecutor(const bContext &C) : ctx_(C) + { + } + void execute(CurvesEffectOperation &self, const bContext &C, const StrokeExtension &stroke_extension) @@ -305,12 +269,7 @@ struct CurvesEffectOperationExecutor { BLI_SCOPED_DEFER([&]() { self.last_mouse_position_ = stroke_extension.mouse_position; }); self_ = &self; - depsgraph_ = CTX_data_depsgraph_pointer(&C); - scene_ = CTX_data_scene(&C); object_ = CTX_data_active_object(&C); - region_ = CTX_wm_region(&C); - v3d_ = CTX_wm_view3d(&C); - rv3d_ = CTX_wm_region_view3d(&C); curves_id_ = static_cast<Curves *>(object_->data); curves_ = &CurvesGeometry::wrap(curves_id_->geometry); @@ -318,13 +277,16 @@ struct CurvesEffectOperationExecutor { return; } - const CurvesSculpt &curves_sculpt = *scene_->toolsettings->curves_sculpt; + curve_selection_factors_ = get_curves_selection(*curves_id_); + curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_); + + const CurvesSculpt &curves_sculpt = *ctx_.scene->toolsettings->curves_sculpt; brush_ = BKE_paint_brush_for_read(&curves_sculpt.paint); - brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension); + brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension); - brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_); + brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_); brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension); - brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension); + brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension); falloff_shape_ = eBrushFalloffShape(brush_->falloff_shape); @@ -337,10 +299,10 @@ struct CurvesEffectOperationExecutor { if (stroke_extension.is_first) { if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) { if (std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush( - *depsgraph_, - *region_, - *v3d_, - *rv3d_, + *ctx_.depsgraph, + *ctx_.region, + *ctx_.v3d, + *ctx_.rv3d, *object_, stroke_extension.mouse_position, brush_radius_base_re_)) { @@ -369,7 +331,7 @@ struct CurvesEffectOperationExecutor { curves_->tag_positions_changed(); DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id); - ED_region_tag_redraw(region_); + ED_region_tag_redraw(ctx_.region); } void gather_influences_projected( @@ -378,7 +340,7 @@ struct CurvesEffectOperationExecutor { const Span<float3> positions_cu = curves_->positions(); float4x4 projection; - ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values); + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms( eCurvesSymmetryType(curves_id_->symmetry)); @@ -396,6 +358,8 @@ struct CurvesEffectOperationExecutor { for (const int curve_i : curves_range) { const IndexRange points = curves_->points_for_curve(curve_i); + const float curve_selection_factor = curve_selection_factors_[curve_i]; + float max_move_distance_cu = 0.0f; for (const float4x4 &brush_transform_inv : symmetry_brush_transforms_inv) { for (const int segment_i : points.drop_back(1)) { @@ -403,8 +367,8 @@ struct CurvesEffectOperationExecutor { const float3 p2_cu = brush_transform_inv * positions_cu[segment_i + 1]; float2 p1_re, p2_re; - ED_view3d_project_float_v2_m4(region_, p1_cu, p1_re, projection.values); - ED_view3d_project_float_v2_m4(region_, p2_cu, p2_re, projection.values); + ED_view3d_project_float_v2_m4(ctx_.region, p1_cu, p1_re, projection.values); + ED_view3d_project_float_v2_m4(ctx_.region, p2_cu, p2_re, projection.values); float2 closest_on_brush_re; float2 closest_on_segment_re; @@ -426,19 +390,19 @@ struct CurvesEffectOperationExecutor { const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re); const float radius_falloff = BKE_brush_curve_strength( brush_, dist_to_brush_re, brush_radius_re); - const float weight = brush_strength_ * radius_falloff; + const float weight = brush_strength_ * radius_falloff * curve_selection_factor; const float3 closest_on_segment_cu = math::interpolate( p1_cu, p2_cu, lambda_on_segment); float3 brush_start_pos_wo, brush_end_pos_wo; - ED_view3d_win_to_3d(v3d_, - region_, + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, curves_to_world_mat_ * closest_on_segment_cu, brush_pos_start_re_, brush_start_pos_wo); - ED_view3d_win_to_3d(v3d_, - region_, + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, curves_to_world_mat_ * closest_on_segment_cu, brush_pos_end_re_, brush_end_pos_wo); @@ -464,13 +428,13 @@ struct CurvesEffectOperationExecutor { const Span<float3> positions_cu = curves_->positions(); float3 brush_pos_start_wo, brush_pos_end_wo; - ED_view3d_win_to_3d(v3d_, - region_, + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, curves_to_world_mat_ * self_->brush_3d_.position_cu, brush_pos_start_re_, brush_pos_start_wo); - ED_view3d_win_to_3d(v3d_, - region_, + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, curves_to_world_mat_ * self_->brush_3d_.position_cu, brush_pos_end_re_, brush_pos_end_wo); @@ -491,6 +455,9 @@ struct CurvesEffectOperationExecutor { const IndexRange points = curves_->points_for_curve(curve_i); float max_move_distance_cu = 0.0f; + + const float curve_selection_factor = curve_selection_factors_[curve_i]; + for (const float4x4 &brush_transform : symmetry_brush_transforms) { const float3 brush_pos_start_transformed_cu = brush_transform * brush_pos_start_cu; const float3 brush_pos_end_transformed_cu = brush_transform * brush_pos_end_cu; @@ -517,7 +484,7 @@ struct CurvesEffectOperationExecutor { const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu); const float radius_falloff = BKE_brush_curve_strength( brush_, dist_to_brush_cu, brush_radius_cu); - const float weight = brush_strength_ * radius_falloff; + const float weight = brush_strength_ * radius_falloff * curve_selection_factor; const float move_distance_cu = weight * brush_pos_diff_length_cu; max_move_distance_cu = std::max(max_move_distance_cu, move_distance_cu); @@ -535,7 +502,7 @@ struct CurvesEffectOperationExecutor { void CurvesEffectOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) { - CurvesEffectOperationExecutor executor; + CurvesEffectOperationExecutor executor{C}; executor.execute(*this, C, stroke_extension); } diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh index 842de234761..4aaf6671cdb 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh +++ b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh @@ -8,7 +8,10 @@ #include "paint_intern.h" #include "BLI_math_vector.hh" +#include "BLI_vector.hh" +#include "BLI_virtual_array.hh" +#include "BKE_attribute.h" #include "BKE_curves.hh" struct ARegion; @@ -55,6 +58,8 @@ std::unique_ptr<CurvesSculptStrokeOperation> new_delete_operation(); std::unique_ptr<CurvesSculptStrokeOperation> new_snake_hook_operation(); std::unique_ptr<CurvesSculptStrokeOperation> new_grow_shrink_operation( const BrushStrokeMode brush_mode, const bContext &C); +std::unique_ptr<CurvesSculptStrokeOperation> new_selection_paint_operation( + const BrushStrokeMode brush_mode, const bContext &C); struct CurvesBrush3D { float3 position_cu; @@ -74,4 +79,33 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(const Depsgraph &depsgraph, Vector<float4x4> get_symmetry_brush_transforms(eCurvesSymmetryType symmetry); +/** + * Get the floating point selection on the curve domain, averaged from points if necessary. + */ +VArray<float> get_curves_selection(const Curves &curves_id); + +/** + * Get the floating point selection on the curve domain, copied from curves if necessary. + */ +VArray<float> get_point_selection(const Curves &curves_id); + +/** + * Find curves that have any point selected (a selection factor greater than zero), + * or curves that have their own selection factor greater than zero. + */ +IndexMask retrieve_selected_curves(const Curves &curves_id, Vector<int64_t> &r_indices); + +void move_last_point_and_resample(MutableSpan<float3> positions, const float3 &new_last_position); + +class CurvesSculptCommonContext { + public: + const Depsgraph *depsgraph = nullptr; + const Scene *scene = nullptr; + ARegion *region = nullptr; + const View3D *v3d = nullptr; + const RegionView3D *rv3d = nullptr; + + CurvesSculptCommonContext(const bContext &C); +}; + } // namespace blender::ed::sculpt_paint diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc index 15d0f73592d..dc3dacf9c81 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc @@ -49,7 +49,7 @@ bool CURVES_SCULPT_mode_poll(bContext *C) { - Object *ob = CTX_data_active_object(C); + const Object *ob = CTX_data_active_object(C); return ob && ob->mode & OB_MODE_SCULPT_CURVES; } @@ -109,9 +109,9 @@ static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bConte { const BrushStrokeMode mode = static_cast<BrushStrokeMode>(RNA_enum_get(op.ptr, "mode")); - Scene &scene = *CTX_data_scene(&C); - CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt; - Brush &brush = *BKE_paint_brush(&curves_sculpt.paint); + const Scene &scene = *CTX_data_scene(&C); + const CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt; + const Brush &brush = *BKE_paint_brush_for_read(&curves_sculpt.paint); switch (brush.curves_sculpt_tool) { case CURVES_SCULPT_TOOL_COMB: return new_comb_operation(); @@ -123,6 +123,8 @@ static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bConte return new_add_operation(C, op.reports); case CURVES_SCULPT_TOOL_GROW_SHRINK: return new_grow_shrink_operation(mode, C); + case CURVES_SCULPT_TOOL_SELECTION_PAINT: + return new_selection_paint_operation(mode, C); } BLI_assert_unreachable(); return {}; @@ -180,8 +182,8 @@ static void stroke_done(const bContext *C, PaintStroke *stroke) static int sculpt_curves_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - Paint *paint = BKE_paint_get_active_from_context(C); - Brush *brush = BKE_paint_brush(paint); + const Paint *paint = BKE_paint_get_active_from_context(C); + const Brush *brush = BKE_paint_brush_for_read(paint); if (brush == nullptr) { return OPERATOR_CANCELLED; } @@ -250,7 +252,7 @@ static void SCULPT_CURVES_OT_brush_stroke(struct wmOperatorType *ot) static bool curves_sculptmode_toggle_poll(bContext *C) { - Object *ob = CTX_data_active_object(C); + const Object *ob = CTX_data_active_object(C); if (ob == nullptr) { return false; } diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc b/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc new file mode 100644 index 00000000000..f620fed5761 --- /dev/null +++ b/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_index_mask_ops.hh" + +#include "BKE_curves.hh" + +#include "curves_sculpt_intern.hh" + +namespace blender::ed::sculpt_paint { + +static VArray<float> get_curves_selection(const CurvesGeometry &curves, const eAttrDomain domain) +{ + switch (domain) { + case ATTR_DOMAIN_CURVE: + return curves.selection_curve_float(); + case ATTR_DOMAIN_POINT: + return curves.adapt_domain( + curves.selection_point_float(), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); + default: + BLI_assert_unreachable(); + return {}; + } +} + +VArray<float> get_curves_selection(const Curves &curves_id) +{ + if (!(curves_id.flag & CV_SCULPT_SELECTION_ENABLED)) { + return VArray<float>::ForSingle(1.0f, CurvesGeometry::wrap(curves_id.geometry).curves_num()); + } + return get_curves_selection(CurvesGeometry::wrap(curves_id.geometry), + eAttrDomain(curves_id.selection_domain)); +} + +static VArray<float> get_point_selection(const CurvesGeometry &curves, const eAttrDomain domain) +{ + switch (domain) { + case ATTR_DOMAIN_CURVE: + return curves.adapt_domain( + curves.selection_curve_float(), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT); + case ATTR_DOMAIN_POINT: + return curves.selection_point_float(); + default: + BLI_assert_unreachable(); + return {}; + } +} + +VArray<float> get_point_selection(const Curves &curves_id) +{ + if (!(curves_id.flag & CV_SCULPT_SELECTION_ENABLED)) { + return VArray<float>::ForSingle(1.0f, CurvesGeometry::wrap(curves_id.geometry).points_num()); + } + return get_point_selection(CurvesGeometry::wrap(curves_id.geometry), + eAttrDomain(curves_id.selection_domain)); +} + +static IndexMask retrieve_selected_curves(const CurvesGeometry &curves, + const eAttrDomain domain, + Vector<int64_t> &r_indices) +{ + switch (domain) { + case ATTR_DOMAIN_POINT: { + const VArray<float> selection = curves.selection_point_float(); + if (selection.is_single()) { + return selection.get_internal_single() == 0.0f ? IndexMask(0) : + IndexMask(curves.curves_num()); + } + return index_mask_ops::find_indices_based_on_predicate( + curves.curves_range(), 512, r_indices, [&](const int curve_i) { + for (const int i : curves.points_for_curve(curve_i)) { + if (selection[i] > 0.0f) { + return true; + } + } + return false; + }); + } + case ATTR_DOMAIN_CURVE: { + const VArray<float> selection = curves.selection_curve_float(); + if (selection.is_single()) { + return selection.get_internal_single() == 0.0f ? IndexMask(0) : + IndexMask(curves.curves_num()); + } + return index_mask_ops::find_indices_based_on_predicate( + curves.curves_range(), 2048, r_indices, [&](const int i) { + return selection[i] > 0.0f; + }); + } + default: + BLI_assert_unreachable(); + return {}; + } +} + +IndexMask retrieve_selected_curves(const Curves &curves_id, Vector<int64_t> &r_indices) +{ + if (!(curves_id.flag & CV_SCULPT_SELECTION_ENABLED)) { + return CurvesGeometry::wrap(curves_id.geometry).curves_range(); + } + return retrieve_selected_curves(CurvesGeometry::wrap(curves_id.geometry), + eAttrDomain(curves_id.selection_domain), + r_indices); +} + +} // namespace blender::ed::sculpt_paint diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc b/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc new file mode 100644 index 00000000000..30793c45bd0 --- /dev/null +++ b/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc @@ -0,0 +1,393 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <algorithm> +#include <numeric> + +#include "BLI_memory_utils.hh" +#include "BLI_task.hh" + +#include "DNA_brush_types.h" + +#include "BKE_brush.h" +#include "BKE_context.h" +#include "BKE_curves.hh" + +#include "DEG_depsgraph.h" + +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "WM_api.h" + +#include "curves_sculpt_intern.hh" + +/** + * The code below uses a suffix naming convention to indicate the coordinate space: + * cu: Local space of the curves object that is being edited. + * wo: World space. + * re: 2D coordinates within the region. + */ + +namespace blender::ed::sculpt_paint { + +using bke::CurvesGeometry; + +class SelectionPaintOperation : public CurvesSculptStrokeOperation { + private: + bool use_select_; + bool clear_selection_; + + CurvesBrush3D brush_3d_; + + friend struct SelectionPaintOperationExecutor; + + public: + SelectionPaintOperation(const bool use_select, const bool clear_selection) + : use_select_(use_select), clear_selection_(clear_selection) + { + } + void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override; +}; + +struct SelectionPaintOperationExecutor { + SelectionPaintOperation *self_ = nullptr; + CurvesSculptCommonContext ctx_; + + Object *object_ = nullptr; + Curves *curves_id_ = nullptr; + CurvesGeometry *curves_ = nullptr; + + const Brush *brush_ = nullptr; + float brush_radius_base_re_; + float brush_radius_factor_; + float brush_strength_; + + float selection_goal_; + + float2 brush_pos_re_; + + float4x4 curves_to_world_mat_; + float4x4 world_to_curves_mat_; + + SelectionPaintOperationExecutor(const bContext &C) : ctx_(C) + { + } + + void execute(SelectionPaintOperation &self, + const bContext &C, + const StrokeExtension &stroke_extension) + { + self_ = &self; + object_ = CTX_data_active_object(&C); + + curves_id_ = static_cast<Curves *>(object_->data); + curves_ = &CurvesGeometry::wrap(curves_id_->geometry); + curves_id_->flag |= CV_SCULPT_SELECTION_ENABLED; + + brush_ = BKE_paint_brush_for_read(&ctx_.scene->toolsettings->curves_sculpt->paint); + brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_); + brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension); + brush_strength_ = BKE_brush_alpha_get(ctx_.scene, brush_); + + brush_pos_re_ = stroke_extension.mouse_position; + + if (self.clear_selection_) { + if (stroke_extension.is_first) { + if (curves_id_->selection_domain == ATTR_DOMAIN_POINT) { + curves_->selection_point_float_for_write().fill(0.0f); + } + else if (curves_id_->selection_domain == ATTR_DOMAIN_CURVE) { + curves_->selection_curve_float_for_write().fill(0.0f); + } + } + } + + curves_to_world_mat_ = object_->obmat; + world_to_curves_mat_ = curves_to_world_mat_.inverted(); + + const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>( + brush_->falloff_shape); + + selection_goal_ = self_->use_select_ ? 1.0f : 0.0f; + + if (stroke_extension.is_first) { + if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) { + this->initialize_spherical_brush_reference_point(); + } + } + + if (curves_id_->selection_domain == ATTR_DOMAIN_POINT) { + MutableSpan<float> selection = curves_->selection_point_float_for_write(); + if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + this->paint_point_selection_projected_with_symmetry(selection); + } + else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) { + this->paint_point_selection_spherical_with_symmetry(selection); + } + } + else { + MutableSpan<float> selection = curves_->selection_curve_float_for_write(); + if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + this->paint_curve_selection_projected_with_symmetry(selection); + } + else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) { + this->paint_curve_selection_spherical_with_symmetry(selection); + } + } + + /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because + * selection is handled as a generic attribute for now. */ + DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id); + ED_region_tag_redraw(ctx_.region); + } + + void paint_point_selection_projected_with_symmetry(MutableSpan<float> selection) + { + const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms( + eCurvesSymmetryType(curves_id_->symmetry)); + for (const float4x4 &brush_transform : symmetry_brush_transforms) { + this->paint_point_selection_projected(brush_transform, selection); + } + } + + void paint_point_selection_projected(const float4x4 &brush_transform, + MutableSpan<float> selection) + { + const float4x4 brush_transform_inv = brush_transform.inverted(); + + float4x4 projection; + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); + + Span<float3> positions_cu = curves_->positions(); + + const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_; + const float brush_radius_sq_re = pow2f(brush_radius_re); + + threading::parallel_for(curves_->points_range(), 1024, [&](const IndexRange point_range) { + for (const int point_i : point_range) { + const float3 pos_cu = brush_transform_inv * positions_cu[point_i]; + + /* Find the position of the point in screen space. */ + float2 pos_re; + ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values); + + const float distance_to_brush_sq_re = math::distance_squared(pos_re, brush_pos_re_); + if (distance_to_brush_sq_re > brush_radius_sq_re) { + /* Ignore the point because it's too far away. */ + continue; + } + + const float distance_to_brush_re = std::sqrt(distance_to_brush_sq_re); + /* A falloff that is based on how far away the point is from the stroke. */ + const float radius_falloff = BKE_brush_curve_strength( + brush_, distance_to_brush_re, brush_radius_re); + /* Combine the falloff and brush strength. */ + const float weight = brush_strength_ * radius_falloff; + + selection[point_i] = math::interpolate(selection[point_i], selection_goal_, weight); + } + }); + } + + void paint_point_selection_spherical_with_symmetry(MutableSpan<float> selection) + { + float4x4 projection; + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); + + float3 brush_wo; + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, + curves_to_world_mat_ * self_->brush_3d_.position_cu, + brush_pos_re_, + brush_wo); + const float3 brush_cu = world_to_curves_mat_ * brush_wo; + + const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms( + eCurvesSymmetryType(curves_id_->symmetry)); + + for (const float4x4 &brush_transform : symmetry_brush_transforms) { + this->paint_point_selection_spherical(selection, brush_transform * brush_cu); + } + } + + void paint_point_selection_spherical(MutableSpan<float> selection, const float3 &brush_cu) + { + Span<float3> positions_cu = curves_->positions(); + + const float brush_radius_cu = self_->brush_3d_.radius_cu; + const float brush_radius_sq_cu = pow2f(brush_radius_cu); + + threading::parallel_for(curves_->points_range(), 1024, [&](const IndexRange point_range) { + for (const int i : point_range) { + const float3 pos_old_cu = positions_cu[i]; + + /* Compute distance to the brush. */ + const float distance_to_brush_sq_cu = math::distance_squared(pos_old_cu, brush_cu); + if (distance_to_brush_sq_cu > brush_radius_sq_cu) { + /* Ignore the point because it's too far away. */ + continue; + } + + const float distance_to_brush_cu = std::sqrt(distance_to_brush_sq_cu); + + /* A falloff that is based on how far away the point is from the stroke. */ + const float radius_falloff = BKE_brush_curve_strength( + brush_, distance_to_brush_cu, brush_radius_cu); + /* Combine the falloff and brush strength. */ + const float weight = brush_strength_ * radius_falloff; + + selection[i] = math::interpolate(selection[i], selection_goal_, weight); + } + }); + } + + void paint_curve_selection_projected_with_symmetry(MutableSpan<float> selection) + { + const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms( + eCurvesSymmetryType(curves_id_->symmetry)); + for (const float4x4 &brush_transform : symmetry_brush_transforms) { + this->paint_curve_selection_projected(brush_transform, selection); + } + } + + void paint_curve_selection_projected(const float4x4 &brush_transform, + MutableSpan<float> selection) + { + const Span<float3> positions_cu = curves_->positions(); + const float4x4 brush_transform_inv = brush_transform.inverted(); + + float4x4 projection; + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); + + const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_; + const float brush_radius_sq_re = pow2f(brush_radius_re); + + threading::parallel_for(curves_->curves_range(), 1024, [&](const IndexRange curves_range) { + for (const int curve_i : curves_range) { + const float max_weight = threading::parallel_reduce( + curves_->points_for_curve(curve_i).drop_back(1), + 1024, + 0.0f, + [&](const IndexRange segment_range, const float init) { + float max_weight = init; + for (const int segment_i : segment_range) { + const float3 pos1_cu = brush_transform_inv * positions_cu[segment_i]; + const float3 pos2_cu = brush_transform_inv * positions_cu[segment_i + 1]; + + float2 pos1_re; + float2 pos2_re; + ED_view3d_project_float_v2_m4(ctx_.region, pos1_cu, pos1_re, projection.values); + ED_view3d_project_float_v2_m4(ctx_.region, pos2_cu, pos2_re, projection.values); + + const float distance_sq_re = dist_squared_to_line_segment_v2( + brush_pos_re_, pos1_re, pos2_re); + if (distance_sq_re > brush_radius_sq_re) { + continue; + } + const float radius_falloff = BKE_brush_curve_strength( + brush_, std::sqrt(distance_sq_re), brush_radius_re); + const float weight = brush_strength_ * radius_falloff; + max_weight = std::max(max_weight, weight); + } + return max_weight; + }, + [](float a, float b) { return std::max(a, b); }); + selection[curve_i] = math::interpolate(selection[curve_i], selection_goal_, max_weight); + } + }); + } + + void paint_curve_selection_spherical_with_symmetry(MutableSpan<float> selection) + { + float4x4 projection; + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); + + float3 brush_wo; + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, + curves_to_world_mat_ * self_->brush_3d_.position_cu, + brush_pos_re_, + brush_wo); + const float3 brush_cu = world_to_curves_mat_ * brush_wo; + + const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms( + eCurvesSymmetryType(curves_id_->symmetry)); + + for (const float4x4 &brush_transform : symmetry_brush_transforms) { + this->paint_curve_selection_spherical(selection, brush_transform * brush_cu); + } + } + + void paint_curve_selection_spherical(MutableSpan<float> selection, const float3 &brush_cu) + { + const Span<float3> positions_cu = curves_->positions(); + + const float brush_radius_cu = self_->brush_3d_.radius_cu; + const float brush_radius_sq_cu = pow2f(brush_radius_cu); + + threading::parallel_for(curves_->curves_range(), 1024, [&](const IndexRange curves_range) { + for (const int curve_i : curves_range) { + const float max_weight = threading::parallel_reduce( + curves_->points_for_curve(curve_i).drop_back(1), + 1024, + 0.0f, + [&](const IndexRange segment_range, const float init) { + float max_weight = init; + for (const int segment_i : segment_range) { + const float3 &pos1_cu = positions_cu[segment_i]; + const float3 &pos2_cu = positions_cu[segment_i + 1]; + + const float distance_sq_cu = dist_squared_to_line_segment_v3( + brush_cu, pos1_cu, pos2_cu); + if (distance_sq_cu > brush_radius_sq_cu) { + continue; + } + const float radius_falloff = BKE_brush_curve_strength( + brush_, std::sqrt(distance_sq_cu), brush_radius_cu); + const float weight = brush_strength_ * radius_falloff; + max_weight = std::max(max_weight, weight); + } + return max_weight; + }, + [](float a, float b) { return std::max(a, b); }); + selection[curve_i] = math::interpolate(selection[curve_i], selection_goal_, max_weight); + } + }); + } + + void initialize_spherical_brush_reference_point() + { + std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph, + *ctx_.region, + *ctx_.v3d, + *ctx_.rv3d, + *object_, + brush_pos_re_, + brush_radius_base_re_); + if (brush_3d.has_value()) { + self_->brush_3d_ = *brush_3d; + } + } +}; + +void SelectionPaintOperation::on_stroke_extended(const bContext &C, + const StrokeExtension &stroke_extension) +{ + SelectionPaintOperationExecutor executor{C}; + executor.execute(*this, C, stroke_extension); +} + +std::unique_ptr<CurvesSculptStrokeOperation> new_selection_paint_operation( + const BrushStrokeMode brush_mode, const bContext &C) +{ + Scene &scene = *CTX_data_scene(&C); + Brush &brush = *BKE_paint_brush(&scene.toolsettings->curves_sculpt->paint); + const bool use_select = ELEM(brush_mode, BRUSH_STROKE_INVERT) == + ((brush.flag & BRUSH_DIR_IN) != 0); + const bool clear_selection = use_select && brush_mode != BRUSH_STROKE_SMOOTH; + + return std::make_unique<SelectionPaintOperation>(use_select, clear_selection); +} + +} // namespace blender::ed::sculpt_paint diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc index bcdeaaeabf2..166ef133c68 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc @@ -72,11 +72,7 @@ class SnakeHookOperation : public CurvesSculptStrokeOperation { */ struct SnakeHookOperatorExecutor { SnakeHookOperation *self_ = nullptr; - const Depsgraph *depsgraph_ = nullptr; - const Scene *scene_ = nullptr; - ARegion *region_ = nullptr; - const View3D *v3d_ = nullptr; - const RegionView3D *rv3d_ = nullptr; + CurvesSculptCommonContext ctx_; const CurvesSculpt *curves_sculpt_ = nullptr; const Brush *brush_ = nullptr; @@ -90,6 +86,10 @@ struct SnakeHookOperatorExecutor { Curves *curves_id_ = nullptr; CurvesGeometry *curves_ = nullptr; + VArray<float> curve_factors_; + Vector<int64_t> selected_curve_indices_; + IndexMask curve_selection_; + float4x4 curves_to_world_mat_; float4x4 world_to_curves_mat_; @@ -97,6 +97,10 @@ struct SnakeHookOperatorExecutor { float2 brush_pos_re_; float2 brush_pos_diff_re_; + SnakeHookOperatorExecutor(const bContext &C) : ctx_(C) + { + } + void execute(SnakeHookOperation &self, const bContext &C, const StrokeExtension &stroke_extension) @@ -104,20 +108,14 @@ struct SnakeHookOperatorExecutor { BLI_SCOPED_DEFER([&]() { self.last_mouse_position_re_ = stroke_extension.mouse_position; }); self_ = &self; - depsgraph_ = CTX_data_depsgraph_pointer(&C); - scene_ = CTX_data_scene(&C); - scene_ = CTX_data_scene(&C); object_ = CTX_data_active_object(&C); - region_ = CTX_wm_region(&C); - v3d_ = CTX_wm_view3d(&C); - rv3d_ = CTX_wm_region_view3d(&C); - curves_sculpt_ = scene_->toolsettings->curves_sculpt; + curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt; brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint); - brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_); + brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_); brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension); - brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension); + brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension); falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape); @@ -130,14 +128,22 @@ struct SnakeHookOperatorExecutor { return; } + curve_factors_ = get_curves_selection(*curves_id_); + curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_); + brush_pos_prev_re_ = self.last_mouse_position_re_; brush_pos_re_ = stroke_extension.mouse_position; brush_pos_diff_re_ = brush_pos_re_ - brush_pos_prev_re_; if (stroke_extension.is_first) { if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) { - std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush( - *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_); + std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph, + *ctx_.region, + *ctx_.v3d, + *ctx_.rv3d, + *object_, + brush_pos_re_, + brush_radius_base_re_); if (brush_3d.has_value()) { self_->brush_3d_ = *brush_3d; } @@ -158,7 +164,7 @@ struct SnakeHookOperatorExecutor { curves_->tag_positions_changed(); DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id); - ED_region_tag_redraw(region_); + ED_region_tag_redraw(ctx_.region); } void projected_snake_hook_with_symmetry() @@ -177,7 +183,7 @@ struct SnakeHookOperatorExecutor { MutableSpan<float3> positions_cu = curves_->positions_for_write(); float4x4 projection; - ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values); + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_; const float brush_radius_sq_re = pow2f(brush_radius_re); @@ -189,7 +195,7 @@ struct SnakeHookOperatorExecutor { const float3 old_pos_cu = brush_transform_inv * positions_cu[last_point_i]; float2 old_pos_re; - ED_view3d_project_float_v2_m4(region_, old_pos_cu, old_pos_re, projection.values); + ED_view3d_project_float_v2_m4(ctx_.region, old_pos_cu, old_pos_re, projection.values); const float distance_to_brush_sq_re = math::distance_squared(old_pos_re, brush_pos_prev_re_); @@ -199,15 +205,18 @@ struct SnakeHookOperatorExecutor { const float radius_falloff = BKE_brush_curve_strength( brush_, std::sqrt(distance_to_brush_sq_re), brush_radius_re); - const float weight = brush_strength_ * radius_falloff; + const float weight = brush_strength_ * radius_falloff * curve_factors_[curve_i]; const float2 new_position_re = old_pos_re + brush_pos_diff_re_ * weight; float3 new_position_wo; - ED_view3d_win_to_3d( - v3d_, region_, curves_to_world_mat_ * old_pos_cu, new_position_re, new_position_wo); + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, + curves_to_world_mat_ * old_pos_cu, + new_position_re, + new_position_wo); const float3 new_position_cu = brush_transform * (world_to_curves_mat_ * new_position_wo); - this->move_last_point_and_resample(positions_cu.slice(points), new_position_cu); + move_last_point_and_resample(positions_cu.slice(points), new_position_cu); } }); } @@ -215,16 +224,16 @@ struct SnakeHookOperatorExecutor { void spherical_snake_hook_with_symmetry() { float4x4 projection; - ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values); + ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values); float3 brush_start_wo, brush_end_wo; - ED_view3d_win_to_3d(v3d_, - region_, + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, curves_to_world_mat_ * self_->brush_3d_.position_cu, brush_pos_prev_re_, brush_start_wo); - ED_view3d_win_to_3d(v3d_, - region_, + ED_view3d_win_to_3d(ctx_.v3d, + ctx_.region, curves_to_world_mat_ * self_->brush_3d_.position_cu, brush_pos_re_, brush_end_wo); @@ -265,52 +274,20 @@ struct SnakeHookOperatorExecutor { const float radius_falloff = BKE_brush_curve_strength( brush_, distance_to_brush_cu, brush_radius_cu); - const float weight = brush_strength_ * radius_falloff; + const float weight = brush_strength_ * radius_falloff * curve_factors_[curve_i]; const float3 new_pos_cu = old_pos_cu + weight * brush_diff_cu; - this->move_last_point_and_resample(positions_cu.slice(points), new_pos_cu); + move_last_point_and_resample(positions_cu.slice(points), new_pos_cu); } }); } - - void move_last_point_and_resample(MutableSpan<float3> positions, - const float3 &new_last_position) const - { - /* Find the accumulated length of each point in the original curve, - * treating it as a poly curve for performance reasons and simplicity. */ - Array<float> orig_lengths(length_parameterize::lengths_num(positions.size(), false)); - length_parameterize::accumulate_lengths<float3>(positions, false, orig_lengths); - const float orig_total_length = orig_lengths.last(); - - /* Find the factor by which the new curve is shorter or longer than the original. */ - const float new_last_segment_length = math::distance(positions.last(1), new_last_position); - const float new_total_length = orig_lengths.last(1) + new_last_segment_length; - const float length_factor = new_total_length / orig_total_length; - - /* Calculate the lengths to sample the original curve with by scaling the original lengths. */ - Array<float> new_lengths(positions.size() - 1); - new_lengths.first() = 0.0f; - for (const int i : new_lengths.index_range().drop_front(1)) { - new_lengths[i] = orig_lengths[i - 1] * length_factor; - } - - Array<int> indices(positions.size() - 1); - Array<float> factors(positions.size() - 1); - length_parameterize::create_samples_from_sorted_lengths( - orig_lengths, new_lengths, false, indices, factors); - - Array<float3> new_positions(positions.size() - 1); - length_parameterize::linear_interpolation<float3>(positions, indices, factors, new_positions); - positions.drop_back(1).copy_from(new_positions); - positions.last() = new_last_position; - } }; void SnakeHookOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) { - SnakeHookOperatorExecutor executor; + SnakeHookOperatorExecutor executor{C}; executor.execute(*this, C, stroke_extension); } diff --git a/source/blender/editors/sculpt_paint/paint_image.cc b/source/blender/editors/sculpt_paint/paint_image.cc index a313489885d..e726fd3f338 100644 --- a/source/blender/editors/sculpt_paint/paint_image.cc +++ b/source/blender/editors/sculpt_paint/paint_image.cc @@ -736,7 +736,7 @@ void PAINT_OT_sample_color(wmOperatorType *ot) ot->poll = sample_color_poll; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER; /* properties */ PropertyRNA *prop; @@ -954,7 +954,7 @@ void PAINT_OT_brush_colors_flip(wmOperatorType *ot) ot->poll = brush_colors_flip_poll; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER; } void ED_imapaint_bucket_fill(struct bContext *C, diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index b7ec427349f..50480b8aef0 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -3132,7 +3132,7 @@ static void project_paint_face_init(const ProjPaintState *ps, } } - /* Is this UV visible from the view? - raytrace */ + /* Is this UV visible from the view? - ray-trace */ /* project_paint_PickFace is less complex, use for testing */ // if (project_paint_PickFace(ps, pixelScreenCo, w, &side) == tri_index) { if ((ps->do_occlude == false) || @@ -3222,7 +3222,7 @@ static void project_paint_face_init(const ProjPaintState *ps, float seam_subsection[4][2]; float fac1, fac2; - /* Pixelspace UVs. */ + /* Pixel-space UV's. */ float lt_puv[3][2]; lt_puv[0][0] = lt_uv_pxoffset[0][0] * ibuf->x; @@ -4492,7 +4492,8 @@ static void project_paint_begin(const bContext *C, } } - /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */ + /* when using sub-surface or multi-resolution, + * mesh-data arrays are thrown away, we need to keep a copy. */ if (ps->is_shared_user == false) { proj_paint_state_cavity_init(ps); } @@ -6488,14 +6489,14 @@ static CustomDataLayer *proj_paint_color_attribute_create(wmOperator *op, Object { char name[MAX_NAME] = ""; float color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; - AttributeDomain domain = ATTR_DOMAIN_POINT; - CustomDataType type = CD_PROP_COLOR; + eAttrDomain domain = ATTR_DOMAIN_POINT; + eCustomDataType type = CD_PROP_COLOR; if (op) { RNA_string_get(op->ptr, "name", name); RNA_float_get_array(op->ptr, "color", color); - domain = (AttributeDomain)RNA_enum_get(op->ptr, "domain"); - type = (CustomDataType)RNA_enum_get(op->ptr, "data_type"); + domain = (eAttrDomain)RNA_enum_get(op->ptr, "domain"); + type = (eCustomDataType)RNA_enum_get(op->ptr, "data_type"); } ID *id = (ID *)ob->data; diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 210cffcbcda..c3c69bf4e0a 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -912,8 +912,13 @@ PaintStroke *paint_stroke_new(bContext *C, rv3d->rflag |= RV3D_PAINTING; } - zero_v3(ups->average_stroke_accum); - ups->average_stroke_counter = 0; + /* Preserve location from last stroke while applying and resetting + * ups->average_stroke_counter to 1. + */ + if (ups->average_stroke_counter) { + mul_v3_fl(ups->average_stroke_accum, 1.0f / (float)ups->average_stroke_counter); + ups->average_stroke_counter = 1; + } /* initialize here to avoid initialization conflict with threaded strokes */ BKE_curvemapping_init(br->curve); diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc index fb1c8ceaa1a..fea501f20a9 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.cc +++ b/source/blender/editors/sculpt_paint/paint_vertex.cc @@ -140,7 +140,7 @@ struct NormalAnglePrecalc { static int get_vcol_elements(Mesh *me, size_t *r_elem_size) { CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id); - AttributeDomain domain = BKE_id_attribute_domain(&me->id, layer); + eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer); if (r_elem_size) { *r_elem_size = layer->type == CD_PROP_COLOR ? sizeof(float) * 4ULL : 4ULL; @@ -324,7 +324,7 @@ bool weight_paint_poll_ignore_tool(bContext *C) return weight_paint_poll_ex(C, false); } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static Color vpaint_get_current_col(Scene *scene, VPaint *vp, bool secondary) { Brush *brush = BKE_paint_brush(&vp->paint); @@ -2823,11 +2823,11 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot) struct VPaintDataBase { ViewContext vc; - AttributeDomain domain; - CustomDataType type; + eAttrDomain domain; + eCustomDataType type; }; -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> struct VPaintData : public VPaintDataBase { NormalAnglePrecalc normal_angle_precalc; @@ -2855,7 +2855,7 @@ struct VPaintData : public VPaintDataBase { } smear; }; -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void *vpaint_init_vpaint(bContext *C, wmOperator *op, Scene *scene, @@ -2949,7 +2949,7 @@ static bool vpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo return false; } - AttributeDomain domain = BKE_id_attribute_domain(&me->id, layer); + eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer); void *vpd = nullptr; if (domain == ATTR_DOMAIN_POINT) { @@ -3272,7 +3272,7 @@ static void do_vpaint_brush_blur_verts(bContext *C, }); } -template<typename Color = ColorPaint4b, typename Traits, AttributeDomain domain> +template<typename Color = ColorPaint4b, typename Traits, eAttrDomain domain> static void do_vpaint_brush_smear(bContext *C, Sculpt *UNUSED(sd), VPaint *vp, @@ -3451,7 +3451,7 @@ static void do_vpaint_brush_smear(bContext *C, }); } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void calculate_average_color(VPaintData<Color, Traits, domain> *vpd, Object *ob, Mesh *me, @@ -3541,7 +3541,7 @@ static void calculate_average_color(VPaintData<Color, Traits, domain> *vpd, } } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static float paint_and_tex_color_alpha(VPaint *vp, VPaintData<Color, Traits, domain> *vpd, const float v_co[3], @@ -3559,7 +3559,7 @@ static float paint_and_tex_color_alpha(VPaint *vp, return rgba[3]; } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void vpaint_do_draw(bContext *C, Sculpt *UNUSED(sd), VPaint *vp, @@ -3699,7 +3699,7 @@ static void vpaint_do_draw(bContext *C, }); } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void vpaint_do_blur(bContext *C, Sculpt *sd, VPaint *vp, @@ -3718,7 +3718,7 @@ static void vpaint_do_blur(bContext *C, } } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void vpaint_paint_leaves(bContext *C, Sculpt *sd, VPaint *vp, @@ -3754,7 +3754,7 @@ static void vpaint_paint_leaves(bContext *C, } } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void vpaint_do_paint(bContext *C, Sculpt *sd, VPaint *vp, @@ -3785,7 +3785,7 @@ static void vpaint_do_paint(bContext *C, } } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void vpaint_do_radial_symmetry(bContext *C, Sculpt *sd, VPaint *vp, @@ -3804,7 +3804,7 @@ static void vpaint_do_radial_symmetry(bContext *C, /* near duplicate of: sculpt.c's, * 'do_symmetrical_brush_actions' and 'wpaint_do_symmetrical_brush_actions'. */ -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void vpaint_do_symmetrical_brush_actions( bContext *C, Sculpt *sd, VPaint *vp, VPaintData<Color, Traits, domain> *vpd, Object *ob) { @@ -3851,7 +3851,7 @@ static void vpaint_do_symmetrical_brush_actions( cache->is_last_valid = true; } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void vpaint_stroke_update_step_intern(bContext *C, PaintStroke *stroke, PointerRNA *itemptr) { Scene *scene = CTX_data_scene(C); @@ -3939,7 +3939,7 @@ static void vpaint_stroke_update_step(bContext *C, } } -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static void vpaint_free_vpaintdata(Object *UNUSED(ob), void *_vpd) { VPaintData<Color, Traits, domain> *vpd = static_cast<VPaintData<Color, Traits, domain> *>(_vpd); @@ -4096,7 +4096,7 @@ void PAINT_OT_vertex_paint(wmOperatorType *ot) /** \name Set Vertex Colors Operator * \{ */ -template<typename Color, typename Traits, AttributeDomain domain> +template<typename Color, typename Traits, eAttrDomain domain> static bool vertex_color_set(Object *ob, ColorPaint4f paintcol_in, Color *color_layer) { Mesh *me; @@ -4164,7 +4164,7 @@ static bool paint_object_attributes_active_color_fill_ex(Object *ob, me->editflag &= ~ME_EDIT_PAINT_FACE_SEL; me->editflag &= ~ME_EDIT_PAINT_VERT_SEL; } - AttributeDomain domain = BKE_id_attribute_domain(&me->id, layer); + eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer); bool ok = false; if (domain == ATTR_DOMAIN_POINT) { if (layer->type == CD_PROP_COLOR) { diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index c7a662df39a..b3e6c34195b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -50,6 +50,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "ED_geometry.h" #include "ED_object.h" #include "ED_sculpt.h" #include "ED_undo.h" @@ -105,7 +106,7 @@ typedef struct UndoSculpt { } UndoSculpt; typedef struct SculptAttrRef { - AttributeDomain domain; + eAttrDomain domain; int type; char name[MAX_CUSTOMDATA_LAYER_NAME]; bool was_set; @@ -1569,6 +1570,24 @@ static void sculpt_undo_set_active_layer(struct bContext *C, SculptAttrRef *attr CustomDataLayer *layer; layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain); + /* Temporary fix for T97408. This is a fundamental + * bug in the undo stack; the operator code needs to push + * an extra undo step before running an operator if a + * non-memfile undo system is active. + * + * For now, detect if the layer does exist but with a different + * domain and just unconvert it. + */ + if (!layer) { + layer = BKE_id_attribute_search(&me->id, attr->name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL); + eAttrDomain domain = layer ? BKE_id_attribute_domain(&me->id, layer) : ATTR_DOMAIN_NUM; + + if (layer && ED_geometry_attribute_convert( + me, attr->name, layer->type, domain, attr->type, attr->domain)) { + layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain); + } + } + if (!layer) { /* Memfile undo killed the layer; re-create it. */ CustomData *cdata = attr->domain == ATTR_DOMAIN_POINT ? &me->vdata : &me->ldata; diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index cfbbc1a1b45..7417f1bdb12 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -3075,7 +3075,7 @@ static int filelist_readjob_list_dir(const char *root, } target = entry->redirection_path; #ifdef WIN32 - /* On Windows don't show ".lnk" extension for valid shortcuts. */ + /* On Windows don't show `.lnk` extension for valid shortcuts. */ BLI_path_extension_replace(entry->relpath, FILE_MAXDIR, ""); #endif } diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index 10cde239987..310c688383b 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -890,7 +890,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) continue; } - /* Exclude "all my files" as it makes no sense in blender fileselector */ + /* Exclude "all my files" as it makes no sense in blender file-selector. */ /* Exclude "airdrop" if wlan not active as it would show "" ) */ if (!strstr(line, "myDocuments.cannedSearch") && (*line != '\0')) { fsmenu_insert_entry( diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 208928afc1f..d0c21f85472 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -845,7 +845,10 @@ void uiTemplateImage(uiLayout *layout, row = uiLayoutRow(row, true); uiLayoutSetEnabled(row, is_packed == false); - uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE); + + prop = RNA_struct_find_property(&imaptr, "filepath"); + uiDefAutoButR(block, &imaptr, prop, -1, "", ICON_NONE, 0, 0, 200, UI_UNIT_Y); + uiItemO(row, "", ICON_FILEBROWSER, "image.file_browse"); uiItemO(row, "", ICON_FILE_REFRESH, "image.reload"); } diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h index 2322420069e..364bec1377d 100644 --- a/source/blender/editors/space_image/image_intern.h +++ b/source/blender/editors/space_image/image_intern.h @@ -49,6 +49,7 @@ void IMAGE_OT_new(struct wmOperatorType *ot); * Called by other space types too. */ void IMAGE_OT_open(struct wmOperatorType *ot); +void IMAGE_OT_file_browse(struct wmOperatorType *ot); /** * Called by other space types too. */ diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index bd1cb3a345e..0761568e480 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -197,6 +197,20 @@ static ImageUser *image_user_from_context(const bContext *C) return (sima) ? &sima->iuser : NULL; } +static ImageUser image_user_from_active_tile(Image *ima) +{ + ImageUser iuser; + BKE_imageuser_default(&iuser); + + /* Use the file associated with the active tile. Otherwise use the first tile. */ + if (ima && ima->source == IMA_SRC_TILED) { + const ImageTile *active = (ImageTile *)BLI_findlink(&ima->tiles, ima->active_tile_index); + iuser.tile = active ? active->tile_number : ((ImageTile *)ima->tiles.first)->tile_number; + } + + return iuser; +} + static bool image_from_context_has_data_poll(bContext *C) { Image *ima = image_from_context(C); @@ -214,13 +228,14 @@ static bool image_from_context_has_data_poll(bContext *C) } /** - * Use this when the image buffer is accessed without the image user. + * Use this when the image buffer is accessing the active tile without the image user. */ -static bool image_from_context_has_data_poll_no_image_user(bContext *C) +static bool image_from_context_has_data_poll_active_tile(bContext *C) { Image *ima = image_from_context(C); + ImageUser iuser = image_user_from_active_tile(ima); - return BKE_image_has_ibuf(ima, NULL); + return BKE_image_has_ibuf(ima, &iuser); } static bool image_not_packed_poll(bContext *C) @@ -1446,7 +1461,7 @@ static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED( image_open_init(C, op); - /* show multiview save options only if scene has multiviews */ + /* Show multi-view save options only if scene has multi-views. */ PropertyRNA *prop; prop = RNA_struct_find_property(op->ptr, "show_multiview"); RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0); @@ -1535,6 +1550,115 @@ void IMAGE_OT_open(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Browse Image Operator + * \{ */ + +static int image_file_browse_exec(bContext *C, wmOperator *op) +{ + Image *ima = op->customdata; + if (ima == NULL) { + return OPERATOR_CANCELLED; + } + + char filepath[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", filepath); + + /* If loading into a tiled texture, ensure that the filename is tokenized. */ + if (ima->source == IMA_SRC_TILED) { + char *filename = (char *)BLI_path_basename(filepath); + BKE_image_ensure_tile_token(filename); + } + + PointerRNA imaptr; + PropertyRNA *imaprop; + RNA_id_pointer_create(&ima->id, &imaptr); + imaprop = RNA_struct_find_property(&imaptr, "filepath"); + + RNA_property_string_set(&imaptr, imaprop, filepath); + RNA_property_update(C, &imaptr, imaprop); + + return OPERATOR_FINISHED; +} + +static int image_file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Image *ima = image_from_context(C); + if (!ima) { + return OPERATOR_CANCELLED; + } + + char filepath[FILE_MAX]; + BLI_strncpy(filepath, ima->filepath, sizeof(filepath)); + + /* Shift+Click to open the file, Alt+Click to browse a folder in the OS's browser. */ + if (event->modifier & (KM_SHIFT | KM_ALT)) { + wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true); + PointerRNA props_ptr; + + if (event->modifier & KM_ALT) { + char *lslash = (char *)BLI_path_slash_rfind(filepath); + if (lslash) { + *lslash = '\0'; + } + } + else if (ima->source == IMA_SRC_TILED) { + ImageUser iuser = image_user_from_active_tile(ima); + BKE_image_user_file_path(&iuser, ima, filepath); + } + + WM_operator_properties_create_ptr(&props_ptr, ot); + RNA_string_set(&props_ptr, "filepath", filepath); + WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &props_ptr, NULL); + WM_operator_properties_free(&props_ptr); + + return OPERATOR_CANCELLED; + } + + /* The image is typically passed to the operator via layout/button context (e.g. + * #uiLayoutSetContextPointer()). The File Browser doesn't support restoring this context + * when calling `exec()` though, so we have to pass it the image via custom data. */ + op->customdata = ima; + + image_filesel(C, op, filepath); + + return OPERATOR_RUNNING_MODAL; +} + +static bool image_file_browse_poll(bContext *C) +{ + return image_from_context(C) != NULL; +} + +void IMAGE_OT_file_browse(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Browse Image"; + ot->description = + "Open an image file browser, hold Shift to open the file, Alt to browse containing " + "directory"; + ot->idname = "IMAGE_OT_file_browse"; + + /* api callbacks */ + ot->exec = image_file_browse_exec; + ot->invoke = image_file_browse_invoke; + ot->poll = image_file_browse_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + WM_operator_properties_filesel(ot, + FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, + FILE_SPECIAL, + FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, + FILE_DEFAULTDISPLAY, + FILE_SORT_DEFAULT); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Match Movie Length Operator * \{ */ @@ -1696,7 +1820,6 @@ static void image_save_options_from_op(Main *bmain, ImageSaveOptions *opts, wmOp RNA_boolean_get(op->ptr, "copy")); opts->save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") && RNA_boolean_get(op->ptr, "save_as_render")); - opts->do_newpath = true; } static bool save_image_op( @@ -1733,6 +1856,8 @@ static ImageSaveData *image_save_as_init(bContext *C, wmOperator *op) return NULL; } + isd->opts.do_newpath = true; + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { RNA_string_set(op->ptr, "filepath", isd->opts.filepath); } @@ -2573,7 +2698,8 @@ void IMAGE_OT_new(wmOperatorType *ot) static int image_flip_exec(bContext *C, wmOperator *op) { Image *ima = image_from_context(C); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + ImageUser iuser = image_user_from_active_tile(ima); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); SpaceImage *sima = CTX_wm_space_image(C); const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT)); @@ -2670,7 +2796,7 @@ void IMAGE_OT_flip(wmOperatorType *ot) /* api callbacks */ ot->exec = image_flip_exec; - ot->poll = image_from_context_has_data_poll_no_image_user; + ot->poll = image_from_context_has_data_poll_active_tile; /* properties */ PropertyRNA *prop; @@ -2693,7 +2819,8 @@ void IMAGE_OT_flip(wmOperatorType *ot) static int image_invert_exec(bContext *C, wmOperator *op) { Image *ima = image_from_context(C); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + ImageUser iuser = image_user_from_active_tile(ima); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); SpaceImage *sima = CTX_wm_space_image(C); const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT)); @@ -2791,7 +2918,7 @@ void IMAGE_OT_invert(wmOperatorType *ot) /* api callbacks */ ot->exec = image_invert_exec; - ot->poll = image_from_context_has_data_poll_no_image_user; + ot->poll = image_from_context_has_data_poll_active_tile; /* properties */ prop = RNA_def_boolean(ot->srna, "invert_r", 0, "Red", "Invert red channel"); @@ -2816,9 +2943,10 @@ void IMAGE_OT_invert(wmOperatorType *ot) static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Image *ima = image_from_context(C); + ImageUser iuser = image_user_from_active_tile(ima); PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size"); if (!RNA_property_is_set(op->ptr, prop)) { - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); const int size[2] = {ibuf->x, ibuf->y}; RNA_property_int_set_array(op->ptr, prop, size); BKE_image_release_ibuf(ima, ibuf, NULL); @@ -2829,7 +2957,8 @@ static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED static int image_scale_exec(bContext *C, wmOperator *op) { Image *ima = image_from_context(C); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + ImageUser iuser = image_user_from_active_tile(ima); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); SpaceImage *sima = CTX_wm_space_image(C); const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT)); @@ -2879,7 +3008,7 @@ void IMAGE_OT_resize(wmOperatorType *ot) /* api callbacks */ ot->invoke = image_scale_invoke; ot->exec = image_scale_exec; - ot->poll = image_from_context_has_data_poll_no_image_user; + ot->poll = image_from_context_has_data_poll_active_tile; /* properties */ RNA_def_int_vector(ot->srna, "size", 2, NULL, 1, INT_MAX, "Size", "", 1, SHRT_MAX); diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c index 1fd9fde084b..a7a8bde1115 100644 --- a/source/blender/editors/space_image/image_undo.c +++ b/source/blender/editors/space_image/image_undo.c @@ -287,7 +287,7 @@ static void ptile_restore_runtime_list(ListBase *paint_tiles) ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ } if (ibuf->mipmap[0]) { - ibuf->userflags |= IB_MIPMAP_INVALID; /* force mip-map recreation. */ + ibuf->userflags |= IB_MIPMAP_INVALID; /* Force MIP-MAP recreation. */ } ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 63f919a1713..9832fcfdb70 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -199,6 +199,7 @@ static void image_operatortypes(void) WM_operatortype_append(IMAGE_OT_new); WM_operatortype_append(IMAGE_OT_open); + WM_operatortype_append(IMAGE_OT_file_browse); WM_operatortype_append(IMAGE_OT_match_movie_length); WM_operatortype_append(IMAGE_OT_replace); WM_operatortype_append(IMAGE_OT_reload); diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index 2aa9b347ed7..81520445000 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -1004,7 +1004,7 @@ static int nlaedit_add_meta_exec(bContext *C, wmOperator *UNUSED(op)) NlaStrip *strip; if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { - /* No making metastrips in non-local tracks of override data. */ + /* No making meta-strips in non-local tracks of override data. */ continue; } @@ -1078,7 +1078,7 @@ static int nlaedit_remove_meta_exec(bContext *C, wmOperator *UNUSED(op)) NlaTrack *nlt = (NlaTrack *)ale->data; if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { - /* No removing metastrips from non-local tracks of override data. */ + /* No removing meta-strips from non-local tracks of override data. */ continue; } @@ -1714,7 +1714,7 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op) BKE_nlatrack_add_strip(nlt, sb, is_liboverride); } - /* clear (temp) metastrips */ + /* Clear (temp) meta-strips. */ BKE_nlastrips_clear_metas(&nlt->strips, 0, 1); } diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index e0ff4212a94..7003d51b2b6 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -66,6 +66,7 @@ #include "NOD_geometry_nodes_eval_log.hh" #include "NOD_node_declaration.hh" +#include "NOD_socket_declarations_geometry.hh" #include "FN_field.hh" #include "FN_field_cpp_type.hh" @@ -75,7 +76,7 @@ using blender::GPointer; using blender::fn::GField; namespace geo_log = blender::nodes::geometry_nodes_eval_log; -using geo_log::NamedAttributeUsage; +using geo_log::eNamedAttrUsage; extern "C" { /* XXX interface.h */ @@ -871,7 +872,8 @@ static void create_inspection_string_for_gfield(const geo_log::GFieldValueLog &v } static void create_inspection_string_for_geometry(const geo_log::GeometryValueLog &value_log, - std::stringstream &ss) + std::stringstream &ss, + const nodes::decl::Geometry *geometry) { Span<GeometryComponentType> component_types = value_log.component_types(); if (component_types.is_empty()) { @@ -938,6 +940,45 @@ static void create_inspection_string_for_geometry(const geo_log::GeometryValueLo } } } + + /* If the geometry declaration is null, as is the case for input to group output, + * or it is an output socket don't show supported types. */ + if (geometry == nullptr || geometry->in_out() == SOCK_OUT) { + return; + } + + Span<GeometryComponentType> supported_types = geometry->supported_types(); + if (supported_types.is_empty()) { + ss << ".\n\n" << TIP_("Supported: All Types"); + return; + } + + ss << ".\n\n" << TIP_("Supported: "); + for (GeometryComponentType type : supported_types) { + switch (type) { + case GEO_COMPONENT_TYPE_MESH: { + ss << TIP_("Mesh"); + break; + } + case GEO_COMPONENT_TYPE_POINT_CLOUD: { + ss << TIP_("Point Cloud"); + break; + } + case GEO_COMPONENT_TYPE_CURVE: { + ss << TIP_("Curve"); + break; + } + case GEO_COMPONENT_TYPE_INSTANCES: { + ss << TIP_("Instances"); + break; + } + case GEO_COMPONENT_TYPE_VOLUME: { + ss << TIP_("Volume"); + break; + } + } + ss << ((type == supported_types.last()) ? "" : ", "); + } } static std::optional<std::string> create_socket_inspection_string(bContext *C, @@ -970,7 +1011,10 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C, } else if (const geo_log::GeometryValueLog *geo_value_log = dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) { - create_inspection_string_for_geometry(*geo_value_log, ss); + create_inspection_string_for_geometry( + *geo_value_log, + ss, + dynamic_cast<const nodes::decl::Geometry *>(socket.runtime->declaration)); } return ss.str(); @@ -1695,7 +1739,7 @@ struct NodeExtraInfoRow { }; struct NamedAttributeTooltipArg { - Map<std::string, NamedAttributeUsage> usage_by_attribute; + Map<std::string, eNamedAttrUsage> usage_by_attribute; }; static char *named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char *UNUSED(tip)) @@ -1707,7 +1751,7 @@ static char *named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char struct NameWithUsage { StringRefNull name; - NamedAttributeUsage usage; + eNamedAttrUsage usage; }; Vector<NameWithUsage> sorted_used_attribute; @@ -1722,16 +1766,16 @@ static char *named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char for (const NameWithUsage &attribute : sorted_used_attribute) { const StringRefNull name = attribute.name; - const NamedAttributeUsage usage = attribute.usage; + const eNamedAttrUsage usage = attribute.usage; ss << " \u2022 \"" << name << "\": "; Vector<std::string> usages; - if ((usage & NamedAttributeUsage::Read) != NamedAttributeUsage::None) { + if ((usage & eNamedAttrUsage::Read) != eNamedAttrUsage::None) { usages.append(TIP_("read")); } - if ((usage & NamedAttributeUsage::Write) != NamedAttributeUsage::None) { + if ((usage & eNamedAttrUsage::Write) != eNamedAttrUsage::None) { usages.append(TIP_("write")); } - if ((usage & NamedAttributeUsage::Remove) != NamedAttributeUsage::None) { + if ((usage & eNamedAttrUsage::Remove) != eNamedAttrUsage::None) { usages.append(TIP_("remove")); } for (const int i : usages.index_range()) { @@ -1749,7 +1793,7 @@ static char *named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char } static NodeExtraInfoRow row_from_used_named_attribute( - const Map<std::string, NamedAttributeUsage> &usage_by_attribute_name) + const Map<std::string, eNamedAttrUsage> &usage_by_attribute_name) { const int attributes_num = usage_by_attribute_name.size(); @@ -1777,7 +1821,7 @@ static std::optional<NodeExtraInfoRow> node_get_accessed_attributes_row(const Sp return std::nullopt; } - Map<std::string, NamedAttributeUsage> usage_by_attribute; + Map<std::string, eNamedAttrUsage> usage_by_attribute; tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) { for (const geo_log::UsedNamedAttribute &used_attribute : node_log.used_named_attributes()) { usage_by_attribute.lookup_or_add_as(used_attribute.name, @@ -1807,7 +1851,7 @@ static std::optional<NodeExtraInfoRow> node_get_accessed_attributes_row(const Sp if (node_log == nullptr) { return std::nullopt; } - Map<std::string, NamedAttributeUsage> usage_by_attribute; + Map<std::string, eNamedAttrUsage> usage_by_attribute; for (const geo_log::UsedNamedAttribute &used_attribute : node_log->used_named_attributes()) { usage_by_attribute.lookup_or_add_as(used_attribute.name, used_attribute.usage) |= used_attribute.usage; diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index ab80a44d636..ffc9befc81c 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -15,6 +15,7 @@ #include "DNA_text_types.h" #include "DNA_world_types.h" +#include "BKE_callbacks.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_image.h" @@ -275,6 +276,7 @@ static void compo_startjob(void *cjv, // XXX BIF_store_spare(); /* 1 is do_previews */ + BKE_callback_exec_id(cj->bmain, &scene->id, BKE_CB_EVT_COMPOSITE_PRE); if ((cj->scene->r.scemode & R_MULTIVIEW) == 0) { ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, ""); @@ -293,6 +295,22 @@ static void compo_startjob(void *cjv, ntree->progress = nullptr; } +static void compo_canceljob(void *cjv) +{ + CompoJob *cj = (CompoJob *)cjv; + Main *bmain = cj->bmain; + Scene *scene = cj->scene; + BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_COMPOSITE_CANCEL); +} + +static void compo_completejob(void *cjv) +{ + CompoJob *cj = (CompoJob *)cjv; + Main *bmain = cj->bmain; + Scene *scene = cj->scene; + BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_COMPOSITE_POST); +} + /** \} */ } // namespace blender::ed::space_node @@ -339,7 +357,13 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene /* setup job */ WM_jobs_customdata_set(wm_job, cj, compo_freejob); WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_COMPO_RESULT, NC_SCENE | ND_COMPO_RESULT); - WM_jobs_callbacks(wm_job, compo_startjob, compo_initjob, compo_updatejob, nullptr); + WM_jobs_callbacks_ex(wm_job, + compo_startjob, + compo_initjob, + compo_updatejob, + nullptr, + compo_completejob, + compo_canceljob); WM_jobs_start(CTX_wm_manager(C), wm_job); } diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc index 9c0172cfabf..f08e23c8371 100644 --- a/source/blender/editors/space_node/node_geometry_attribute_search.cc +++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc @@ -82,8 +82,10 @@ static Vector<const GeometryAttributeInfo *> get_attribute_info_from_context( if (const geo_log::GeometryValueLog *geo_value_log = dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) { for (const GeometryAttributeInfo &attribute : geo_value_log->attributes()) { - if (names.add(attribute.name)) { - attributes.append(&attribute); + if (bke::allow_procedural_attribute_access(attribute.name)) { + if (names.add(attribute.name)) { + attributes.append(&attribute); + } } } } @@ -126,7 +128,7 @@ static void attribute_search_update_fn( * Some custom data types don't correspond to node types and therefore can't be * used by the named attribute input node. Find the best option or fallback to float. */ -static CustomDataType data_type_in_attribute_input_node(const CustomDataType type) +static eCustomDataType data_type_in_attribute_input_node(const eCustomDataType type) { switch (type) { case CD_PROP_FLOAT: @@ -185,7 +187,7 @@ static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v) /* For the attribute input node, also adjust the type and links connected to the output. */ if (node->type == GEO_NODE_INPUT_NAMED_ATTRIBUTE && item->data_type.has_value()) { NodeGeometryInputNamedAttribute &storage = *(NodeGeometryInputNamedAttribute *)node->storage; - const CustomDataType new_type = data_type_in_attribute_input_node(*item->data_type); + const eCustomDataType new_type = data_type_in_attribute_input_node(*item->data_type); if (new_type != storage.data_type) { storage.data_type = new_type; /* Make the output socket with the new type on the attribute input node active. */ diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 5796a712205..e10bedb18f4 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -454,7 +454,7 @@ static bool socket_can_be_viewed(const OutputSocketRef &socket) SOCK_RGBA); } -static CustomDataType socket_type_to_custom_data_type(const eNodeSocketDatatype socket_type) +static eCustomDataType socket_type_to_custom_data_type(const eNodeSocketDatatype socket_type) { switch (socket_type) { case SOCK_FLOAT: @@ -491,7 +491,7 @@ static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree, return viewer_socket; } NodeGeometryViewer *storage = (NodeGeometryViewer *)viewer_node.storage; - const CustomDataType data_type = socket_type_to_custom_data_type( + const eCustomDataType data_type = socket_type_to_custom_data_type( (eNodeSocketDatatype)src_socket.type); BLI_assert(data_type != CD_AUTO_FROM_NAME); storage->data_type = data_type; diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 10c6e828e96..ea6d3351eaa 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -191,10 +191,11 @@ static int sequencer_generic_invoke_xy_guess_channel(bContext *C, int type) } for (seq = ed->seqbasep->first; seq; seq = seq->next) { - if ((ELEM(type, -1, seq->type)) && (seq->enddisp < timeline_frame) && - (timeline_frame - seq->enddisp < proximity)) { + const int strip_end = SEQ_time_right_handle_frame_get(seq); + if ((ELEM(type, -1, seq->type)) && (strip_end < timeline_frame) && + (timeline_frame - strip_end < proximity)) { tgt = seq; - proximity = timeline_frame - seq->enddisp; + proximity = timeline_frame - strip_end; } } @@ -785,7 +786,6 @@ static void seq_build_proxy(bContext *C, SeqCollection *movie_strips) } static void sequencer_add_movie_clamp_sound_strip_length(Scene *scene, - ListBase *seqbase, Sequence *seq_movie, Sequence *seq_sound) { @@ -793,9 +793,8 @@ static void sequencer_add_movie_clamp_sound_strip_length(Scene *scene, return; } - SEQ_time_right_handle_frame_set(seq_sound, SEQ_time_right_handle_frame_get(seq_movie)); - SEQ_time_left_handle_frame_set(seq_sound, SEQ_time_left_handle_frame_get(seq_movie)); - SEQ_time_update_sequence(scene, seqbase, seq_sound); + SEQ_time_right_handle_frame_set(scene, seq_sound, SEQ_time_right_handle_frame_get(seq_movie)); + SEQ_time_left_handle_frame_set(scene, seq_sound, SEQ_time_left_handle_frame_get(seq_movie)); } static void sequencer_add_movie_multiple_strips(bContext *C, @@ -833,7 +832,7 @@ static void sequencer_add_movie_multiple_strips(bContext *C, else { if (RNA_boolean_get(op->ptr, "sound")) { seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data); - sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound); + sequencer_add_movie_clamp_sound_strip_length(scene, seq_movie, seq_sound); if (seq_sound) { /* The video has sound, shift the video strip up a channel to make room for the sound @@ -842,7 +841,8 @@ static void sequencer_add_movie_multiple_strips(bContext *C, } } - load_data->start_frame += seq_movie->enddisp - seq_movie->startdisp; + load_data->start_frame += SEQ_time_right_handle_frame_get(seq_movie) - + SEQ_time_left_handle_frame_get(seq_movie); if (overlap_shuffle_override) { has_seq_overlap |= seq_load_apply_generic_options_only_test_overlap( C, op, seq_sound, strip_col); @@ -890,7 +890,7 @@ static bool sequencer_add_movie_single_strip(bContext *C, } if (RNA_boolean_get(op->ptr, "sound")) { seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data); - sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound); + sequencer_add_movie_clamp_sound_strip_length(scene, seq_movie, seq_sound); if (seq_sound) { /* The video has sound, shift the video strip up a channel to make room for the sound * strip. */ @@ -1073,7 +1073,8 @@ static void sequencer_add_sound_multiple_strips(bContext *C, } else { seq_load_apply_generic_options(C, op, seq); - load_data->start_frame += seq->enddisp - seq->startdisp; + load_data->start_frame += SEQ_time_right_handle_frame_get(seq) - + SEQ_time_left_handle_frame_get(seq); } } RNA_END; @@ -1300,8 +1301,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op) /* Adjust length. */ if (load_data.image.len == 1) { - SEQ_time_right_handle_frame_set(seq, load_data.image.end_frame); - SEQ_time_update_sequence(scene, SEQ_active_seqbase_get(ed), seq); + SEQ_time_right_handle_frame_set(scene, seq, load_data.image.end_frame); } seq_load_apply_generic_options(C, op, seq); diff --git a/source/blender/editors/space_sequencer/sequencer_drag_drop.c b/source/blender/editors/space_sequencer/sequencer_drag_drop.c index 645c0dc9a1d..8dadb9360e3 100644 --- a/source/blender/editors/space_sequencer/sequencer_drag_drop.c +++ b/source/blender/editors/space_sequencer/sequencer_drag_drop.c @@ -231,9 +231,8 @@ static void update_overlay_strip_poistion_data(bContext *C, const int mval[2]) else { /* Check if there is a strip that would intersect with the new strip(s). */ coords->is_intersecting = false; - Sequence dummy_seq = {.machine = coords->channel, - .startdisp = coords->start_frame, - .enddisp = coords->start_frame + coords->strip_len}; + Sequence dummy_seq = { + .machine = coords->channel, .start = coords->start_frame, .len = coords->strip_len}; Editing *ed = SEQ_editing_get(scene); for (int i = 0; i < coords->channel_len && !coords->is_intersecting; i++) { diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 02e77732e02..25701c323b9 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -617,8 +617,8 @@ static void drawmeta_contents(Scene *scene, /* Draw only immediate children (1 level depth). */ for (seq = meta_seqbase->first; seq; seq = seq->next) { - const int startdisp = seq->startdisp + offset; - const int enddisp = seq->enddisp + offset; + const int startdisp = SEQ_time_left_handle_frame_get(seq) + offset; + const int enddisp = SEQ_time_right_handle_frame_get(seq) + offset; if ((startdisp > x2 || enddisp < x1) == 0) { float y_chan = (seq->machine - chan_min) / (float)(chan_range)*draw_range; @@ -668,7 +668,10 @@ float sequence_handle_size_get_clamped(Sequence *seq, const float pixelx) const float maxhandle = (pixelx * SEQ_HANDLE_SIZE) * U.pixelsize; /* Ensure that handle is not wider, than quarter of strip. */ - return min_ff(maxhandle, ((float)(seq->enddisp - seq->startdisp) / 4.0f)); + return min_ff( + maxhandle, + ((float)(SEQ_time_right_handle_frame_get(seq) - SEQ_time_left_handle_frame_get(seq)) / + 4.0f)); } /* Draw a handle, on left or right side of strip. */ @@ -686,8 +689,8 @@ static void draw_seq_handle(View2D *v2d, uint whichsel = 0; uchar col[4]; - x1 = seq->startdisp; - x2 = seq->enddisp; + x1 = SEQ_time_left_handle_frame_get(seq); + x2 = SEQ_time_right_handle_frame_get(seq); y1 = seq->machine + SEQ_STRIP_OFSBOTTOM; y2 = seq->machine + SEQ_STRIP_OFSTOP; @@ -739,7 +742,11 @@ static void draw_seq_handle(View2D *v2d, BLF_set_default(); /* Calculate if strip is wide enough for showing the labels. */ - numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d%d", seq->startdisp, seq->enddisp); + numstr_len = BLI_snprintf_rlen(numstr, + sizeof(numstr), + "%d%d", + SEQ_time_left_handle_frame_get(seq), + SEQ_time_right_handle_frame_get(seq)); float tot_width = BLF_width(fontid, numstr, numstr_len); if ((x2 - x1) / pixelx > 20 + tot_width) { @@ -747,12 +754,14 @@ static void draw_seq_handle(View2D *v2d, float text_margin = 1.2f * handsize_clamped; if (direction == SEQ_LEFTHANDLE) { - numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", seq->startdisp); + numstr_len = BLI_snprintf_rlen( + numstr, sizeof(numstr), "%d", SEQ_time_left_handle_frame_get(seq)); x1 += text_margin; y1 += 0.09f; } else { - numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", seq->enddisp - 1); + numstr_len = BLI_snprintf_rlen( + numstr, sizeof(numstr), "%d", SEQ_time_right_handle_frame_get(seq) - 1); x1 = x2 - (text_margin + pixelx * BLF_width(fontid, numstr, numstr_len)); y1 += 0.09f; } @@ -913,7 +922,8 @@ static size_t draw_seq_text_get_overlay_string(SpaceSeq *sseq, char strip_duration_text[16]; if (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_DURATION) { - const int strip_duration = seq->enddisp - seq->startdisp; + const int strip_duration = SEQ_time_right_handle_frame_get(seq) - + SEQ_time_left_handle_frame_get(seq); SNPRINTF(strip_duration_text, "%d", strip_duration); if (i != 0) { text_array[i++] = text_sep; @@ -980,8 +990,8 @@ static void draw_sequence_extensions_overlay( float x1, x2, y1, y2; uchar col[4], blend_col[3]; - x1 = seq->startdisp; - x2 = seq->enddisp; + x1 = SEQ_time_left_handle_frame_get(seq); + x2 = SEQ_time_right_handle_frame_get(seq); y1 = seq->machine + SEQ_STRIP_OFSBOTTOM; y2 = seq->machine + SEQ_STRIP_OFSTOP; @@ -1038,15 +1048,19 @@ static void draw_color_strip_band( immUniformColor4ubv(col); - immRectf(pos, seq->startdisp, y1, seq->enddisp, text_margin_y); + immRectf(pos, + SEQ_time_left_handle_frame_get(seq), + y1, + SEQ_time_right_handle_frame_get(seq), + text_margin_y); /* 1px line to better separate the color band. */ UI_GetColorPtrShade3ubv(col, col, -20); immUniformColor4ubv(col); immBegin(GPU_PRIM_LINES, 2); - immVertex2f(pos, seq->startdisp, text_margin_y); - immVertex2f(pos, seq->enddisp, text_margin_y); + immVertex2f(pos, SEQ_time_left_handle_frame_get(seq), text_margin_y); + immVertex2f(pos, SEQ_time_right_handle_frame_get(seq), text_margin_y); immEnd(); GPU_blend(GPU_BLEND_NONE); @@ -1111,12 +1125,12 @@ static void draw_seq_background(Scene *scene, immUniformColor4ubv(col); if (SEQ_time_has_left_still_frames(seq)) { - const float content_start = min_ff(seq->enddisp, seq->start); - immRectf(pos, seq->startdisp, y1, content_start, y2); + const float content_start = min_ff(SEQ_time_right_handle_frame_get(seq), seq->start); + immRectf(pos, SEQ_time_left_handle_frame_get(seq), y1, content_start, y2); } if (SEQ_time_has_right_still_frames(seq)) { - const float content_end = max_ff(seq->startdisp, seq->start + seq->len); - immRectf(pos, content_end, y1, seq->enddisp, y2); + const float content_end = max_ff(SEQ_time_left_handle_frame_get(seq), seq->start + seq->len); + immRectf(pos, content_end, y1, SEQ_time_right_handle_frame_get(seq), y2); } } @@ -1333,14 +1347,15 @@ static void draw_seq_strip(const bContext *C, SEQ_TIMELINE_SHOW_STRIP_COLOR_TAG); /* Draw strip body. */ - x1 = SEQ_time_has_left_still_frames(seq) ? seq->start : seq->startdisp; + x1 = SEQ_time_has_left_still_frames(seq) ? seq->start : SEQ_time_left_handle_frame_get(seq); y1 = seq->machine + SEQ_STRIP_OFSBOTTOM; - x2 = SEQ_time_has_right_still_frames(seq) ? (seq->start + seq->len) : seq->enddisp; + x2 = SEQ_time_has_right_still_frames(seq) ? (seq->start + seq->len) : + SEQ_time_right_handle_frame_get(seq); y2 = seq->machine + SEQ_STRIP_OFSTOP; /* Limit body to strip bounds. Meta strip can end up with content outside of strip range. */ - x1 = min_ff(x1, seq->enddisp); - x2 = max_ff(x2, seq->startdisp); + x1 = min_ff(x1, SEQ_time_right_handle_frame_get(seq)); + x2 = max_ff(x2, SEQ_time_left_handle_frame_get(seq)); float text_margin_y; bool y_threshold; @@ -1380,8 +1395,8 @@ static void draw_seq_strip(const bContext *C, } immUnbindProgram(); - x1 = seq->startdisp; - x2 = seq->enddisp; + x1 = SEQ_time_left_handle_frame_get(seq); + x2 = SEQ_time_right_handle_frame_get(seq); if ((seq->type == SEQ_TYPE_META) || ((seq->type == SEQ_TYPE_SCENE) && (seq->flag & SEQ_SCENE_STRIPS))) { @@ -1471,23 +1486,23 @@ static void draw_effect_inputs_highlight(Sequence *seq) immUniformColor4ub(255, 255, 255, 48); immRectf(pos, - seq1->startdisp, + SEQ_time_left_handle_frame_get(seq1), seq1->machine + SEQ_STRIP_OFSBOTTOM, - seq1->enddisp, + SEQ_time_right_handle_frame_get(seq1), seq1->machine + SEQ_STRIP_OFSTOP); if (seq2 && seq2 != seq1) { immRectf(pos, - seq2->startdisp, + SEQ_time_left_handle_frame_get(seq2), seq2->machine + SEQ_STRIP_OFSBOTTOM, - seq2->enddisp, + SEQ_time_right_handle_frame_get(seq2), seq2->machine + SEQ_STRIP_OFSTOP); } if (seq3 && !ELEM(seq3, seq1, seq2)) { immRectf(pos, - seq3->startdisp, + SEQ_time_left_handle_frame_get(seq3), seq3->machine + SEQ_STRIP_OFSBOTTOM, - seq3->enddisp, + SEQ_time_right_handle_frame_get(seq3), seq3->machine + SEQ_STRIP_OFSTOP); } immUnbindProgram(); @@ -2081,10 +2096,10 @@ static int sequencer_draw_get_transform_preview_frame(Scene *scene) int preview_frame; if (last_seq->flag & SEQ_RIGHTSEL) { - preview_frame = last_seq->enddisp - 1; + preview_frame = SEQ_time_right_handle_frame_get(last_seq) - 1; } else { - preview_frame = last_seq->startdisp; + preview_frame = SEQ_time_left_handle_frame_get(last_seq); } return preview_frame; @@ -2310,10 +2325,10 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region) if (seq == last_seq && (last_seq->flag & SELECT)) { continue; } - if (min_ii(seq->startdisp, seq->start) > v2d->cur.xmax) { + if (min_ii(SEQ_time_left_handle_frame_get(seq), seq->start) > v2d->cur.xmax) { continue; } - if (max_ii(seq->enddisp, seq->start + seq->len) < v2d->cur.xmin) { + if (max_ii(SEQ_time_right_handle_frame_get(seq), seq->start + seq->len) < v2d->cur.xmin) { continue; } if (seq->machine + 1.0f < v2d->cur.ymin) { @@ -2368,9 +2383,9 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region) immUniformColor4ub(255, 255, 255, 48); immRectf(pos, - seq->startdisp, + SEQ_time_left_handle_frame_get(seq), seq->machine + SEQ_STRIP_OFSBOTTOM, - seq->enddisp, + SEQ_time_right_handle_frame_get(seq), seq->machine + SEQ_STRIP_OFSTOP); immUnbindProgram(); @@ -2597,7 +2612,8 @@ static void draw_cache_view(const bContext *C) continue; } - if (seq->startdisp > v2d->cur.xmax || seq->enddisp < v2d->cur.xmin) { + if (SEQ_time_left_handle_frame_get(seq) > v2d->cur.xmax || + SEQ_time_right_handle_frame_get(seq) < v2d->cur.xmin) { continue; } @@ -2607,7 +2623,11 @@ static void draw_cache_view(const bContext *C) if (scene->ed->cache_flag & SEQ_CACHE_VIEW_RAW) { const float bg_color[4] = {1.0f, 0.1f, 0.02f, 0.1f}; immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]); - immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top); + immRectf(pos, + SEQ_time_left_handle_frame_get(seq), + stripe_bot, + SEQ_time_right_handle_frame_get(seq), + stripe_top); } stripe_bot += stripe_ht + stripe_ofs_y; @@ -2616,7 +2636,11 @@ static void draw_cache_view(const bContext *C) if (scene->ed->cache_flag & SEQ_CACHE_VIEW_PREPROCESSED) { const float bg_color[4] = {0.1f, 0.1f, 0.75f, 0.1f}; immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]); - immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top); + immRectf(pos, + SEQ_time_left_handle_frame_get(seq), + stripe_bot, + SEQ_time_right_handle_frame_get(seq), + stripe_top); } stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_ofs_y; @@ -2625,7 +2649,11 @@ static void draw_cache_view(const bContext *C) if (scene->ed->cache_flag & SEQ_CACHE_VIEW_COMPOSITE) { const float bg_color[4] = {1.0f, 0.6f, 0.0f, 0.1f}; immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]); - immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top); + immRectf(pos, + SEQ_time_left_handle_frame_get(seq), + stripe_bot, + SEQ_time_right_handle_frame_get(seq), + stripe_top); } } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 08f98dfb161..75966d4f070 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -77,7 +77,6 @@ typedef struct TransSeq { int start, machine; - int startdisp, enddisp; int startofs, endofs; int anim_startofs, anim_endofs; /* int final_left, final_right; */ /* UNUSED */ @@ -345,7 +344,6 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene); - ListBase *seqbase = SEQ_active_seqbase_get(ed); ListBase *channels = SEQ_channels_displayed_get(ed); Sequence *seq; int snap_frame; @@ -361,15 +359,15 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) } else { if (seq->flag & SEQ_LEFTSEL) { - SEQ_time_left_handle_frame_set(seq, snap_frame); + SEQ_time_left_handle_frame_set(scene, seq, snap_frame); } else { /* SEQ_RIGHTSEL */ - SEQ_time_right_handle_frame_set(seq, snap_frame); + SEQ_time_right_handle_frame_set(scene, seq, snap_frame); } - SEQ_transform_handle_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL); - SEQ_transform_fix_single_image_seq_offsets(seq); + SEQ_transform_handle_xlimits( + scene, seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL); + SEQ_transform_fix_single_image_seq_offsets(scene, seq); } - SEQ_time_update_sequence(scene, seqbase, seq); } } @@ -390,27 +388,22 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) if (seq->seq1 && (seq->seq1->flag & SELECT)) { if (!either_handle_selected) { - SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); + SEQ_offset_animdata(scene, seq, (snap_frame - SEQ_time_left_handle_frame_get(seq))); } - SEQ_time_update_sequence(scene, seqbase, seq); } else if (seq->seq2 && (seq->seq2->flag & SELECT)) { if (!either_handle_selected) { - SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); + SEQ_offset_animdata(scene, seq, (snap_frame - SEQ_time_left_handle_frame_get(seq))); } - SEQ_time_update_sequence(scene, seqbase, seq); } else if (seq->seq3 && (seq->seq3->flag & SELECT)) { if (!either_handle_selected) { - SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); + SEQ_offset_animdata(scene, seq, (snap_frame - SEQ_time_left_handle_frame_get(seq))); } - SEQ_time_update_sequence(scene, seqbase, seq); } } } - SEQ_sort(SEQ_active_seqbase_get(ed)); - DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -477,8 +470,6 @@ static void transseq_backup(TransSeq *ts, Sequence *seq) { ts->start = seq->start; ts->machine = seq->machine; - ts->startdisp = seq->startdisp; - ts->enddisp = seq->enddisp; ts->startofs = seq->startofs; ts->endofs = seq->endofs; ts->anim_startofs = seq->anim_startofs; @@ -490,8 +481,6 @@ static void transseq_restore(TransSeq *ts, Sequence *seq) { seq->start = ts->start; seq->machine = ts->machine; - seq->startdisp = ts->startdisp; - seq->enddisp = ts->enddisp; seq->startofs = ts->startofs; seq->endofs = ts->endofs; seq->anim_startofs = ts->anim_startofs; @@ -605,22 +594,8 @@ static void sequencer_slip_recursively(Scene *scene, SlipData *data, int offset) endframe = seq->start + seq->len; /* Compute the sequence offsets. */ - seq->endofs = endframe - seq->enddisp; - seq->startofs = seq->startdisp - seq->start; - } - else { - /* No transform data (likely effect strip). Only move start and end. */ - seq->startdisp = data->ts[i].startdisp + offset; - seq->enddisp = data->ts[i].enddisp + offset; - } - - /* Effects are only added if we they are in a meta-strip. - * In this case, dependent strips will just be transformed and - * we can skip calculating for effects. - * This way we can avoid an extra loop just for effects. */ - if (!(seq->type & SEQ_TYPE_EFFECT)) { - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); - SEQ_time_update_sequence(scene, seqbase, seq); + seq->endofs = endframe - SEQ_time_right_handle_frame_get(seq); + seq->startofs = SEQ_time_left_handle_frame_get(seq) - seq->start; } } @@ -640,12 +615,12 @@ static void sequencer_slip_apply_limits(SlipData *data, int *offset) int seq_content_end = seq_content_start + seq->len + seq->anim_startofs + seq->anim_endofs; int diff = 0; - if (seq_content_start >= seq->enddisp) { - diff = seq->enddisp - seq_content_start - 1; + if (seq_content_start >= SEQ_time_right_handle_frame_get(seq)) { + diff = SEQ_time_right_handle_frame_get(seq) - seq_content_start - 1; } - if (seq_content_end <= seq->startdisp) { - diff = seq->startdisp - seq_content_end + 1; + if (seq_content_end <= SEQ_time_left_handle_frame_get(seq)) { + diff = SEQ_time_left_handle_frame_get(seq) - seq_content_end + 1; } *offset += diff; } @@ -791,8 +766,6 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even for (int i = 0; i < data->num_seq; i++) { Sequence *seq = data->seq_array[i]; SEQ_add_reload_new_file(bmain, scene, seq, false); - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); - SEQ_time_update_sequence(scene, seqbase, seq); } MEM_freeN(data->seq_array); @@ -1288,7 +1261,6 @@ static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op) last_seq->seq3 = seq3; int old_start = last_seq->start; - SEQ_time_update_recursive(scene, last_seq); SEQ_relations_invalidate_cache_preprocessed(scene, last_seq); SEQ_offset_animdata(scene, last_seq, (last_seq->start - old_start)); @@ -1446,13 +1418,15 @@ static int sequencer_split_exec(bContext *C, wmOperator *op) if (ignore_selection) { if (use_cursor_position) { LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { - if (seq->enddisp == split_frame && seq->machine == split_channel) { + if (SEQ_time_right_handle_frame_get(seq) == split_frame && + seq->machine == split_channel) { seq_selected = seq->flag & SEQ_ALLSEL; } } if (!seq_selected) { LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { - if (seq->startdisp == split_frame && seq->machine == split_channel) { + if (SEQ_time_left_handle_frame_get(seq) == split_frame && + seq->machine == split_channel) { seq->flag &= ~SEQ_ALLSEL; } } @@ -1463,20 +1437,18 @@ static int sequencer_split_exec(bContext *C, wmOperator *op) if (split_side != SEQ_SIDE_BOTH) { LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if (split_side == SEQ_SIDE_LEFT) { - if (seq->startdisp >= split_frame) { + if (SEQ_time_left_handle_frame_get(seq) >= split_frame) { seq->flag &= ~SEQ_ALLSEL; } } else { - if (seq->enddisp <= split_frame) { + if (SEQ_time_right_handle_frame_get(seq) <= split_frame) { seq->flag &= ~SEQ_ALLSEL; } } } } } - - SEQ_sort(SEQ_active_seqbase_get(ed)); } if (changed) { WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1791,8 +1763,6 @@ static int sequencer_offset_clear_exec(bContext *C, wmOperator *UNUSED(op)) /* Update lengths, etc. */ seq = ed->seqbasep->first; while (seq) { - ListBase *seqbase = SEQ_active_seqbase_get(ed); - SEQ_time_update_sequence(scene, seqbase, seq); SEQ_relations_invalidate_cache_preprocessed(scene, seq); seq = seq->next; } @@ -1883,8 +1853,6 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) BLI_strncpy(se_new->name, se->name, sizeof(se_new->name)); strip_new->stripdata = se_new; - SEQ_time_update_sequence(scene, seqbase, seq_new); - if (step > 1) { seq_new->flag &= ~SEQ_OVERLAP; if (SEQ_transform_test_overlap(seqbase, seq_new)) { @@ -1908,9 +1876,6 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) } SEQ_edit_remove_flagged_sequences(scene, seqbase); - - SEQ_sort(seqbase); - WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; @@ -2020,8 +1985,8 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op) BLI_addtail(&seqm->seqbase, seq); SEQ_relations_invalidate_cache_preprocessed(scene, seq); channel_max = max_ii(seq->machine, channel_max); - meta_start_frame = min_ii(seq->startdisp, meta_start_frame); - meta_end_frame = max_ii(seq->enddisp, meta_end_frame); + meta_start_frame = min_ii(SEQ_time_left_handle_frame_get(seq), meta_start_frame); + meta_end_frame = max_ii(SEQ_time_right_handle_frame_get(seq), meta_end_frame); } } @@ -2030,7 +1995,6 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op) SEQ_sequence_base_unique_name_recursive(scene, &ed->seqbase, seqm); seqm->start = meta_start_frame; seqm->len = meta_end_frame - meta_start_frame; - SEQ_time_update_sequence(scene, active_seqbase, seqm); SEQ_select_active_set(scene, seqm); if (SEQ_transform_test_overlap(active_seqbase, seqm)) { SEQ_transform_seqbase_shuffle(active_seqbase, seqm, scene); @@ -2098,7 +2062,6 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op)) } } - SEQ_sort(active_seqbase); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -2204,19 +2167,18 @@ static const EnumPropertyItem prop_side_lr_types[] = { static void swap_sequence(Scene *scene, Sequence *seqa, Sequence *seqb) { - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); - int gap = seqb->startdisp - seqa->enddisp; + int gap = SEQ_time_left_handle_frame_get(seqb) - SEQ_time_right_handle_frame_get(seqa); int seq_a_start; int seq_b_start; - seq_b_start = (seqb->start - seqb->startdisp) + seqa->startdisp; + seq_b_start = (seqb->start - SEQ_time_left_handle_frame_get(seqb)) + + SEQ_time_left_handle_frame_get(seqa); SEQ_transform_translate_sequence(scene, seqb, seq_b_start - seqb->start); - SEQ_time_update_sequence(scene, seqbase, seqb); SEQ_relations_invalidate_cache_preprocessed(scene, seqb); - seq_a_start = (seqa->start - seqa->startdisp) + seqb->enddisp + gap; + seq_a_start = (seqa->start - SEQ_time_left_handle_frame_get(seqa)) + + SEQ_time_right_handle_frame_get(seqb) + gap; SEQ_transform_translate_sequence(scene, seqa, seq_a_start - seqa->start); - SEQ_time_update_sequence(scene, seqbase, seqa); SEQ_relations_invalidate_cache_preprocessed(scene, seqa); } @@ -2241,13 +2203,13 @@ static Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, i switch (lr) { case SEQ_SIDE_LEFT: - if (seq->enddisp <= test->startdisp) { - dist = test->enddisp - seq->startdisp; + if (SEQ_time_right_handle_frame_get(seq) <= SEQ_time_left_handle_frame_get(test)) { + dist = SEQ_time_right_handle_frame_get(test) - SEQ_time_left_handle_frame_get(seq); } break; case SEQ_SIDE_RIGHT: - if (seq->startdisp >= test->enddisp) { - dist = seq->startdisp - test->enddisp; + if (SEQ_time_left_handle_frame_get(seq) >= SEQ_time_right_handle_frame_get(test)) { + dist = SEQ_time_left_handle_frame_get(seq) - SEQ_time_right_handle_frame_get(test); } break; } @@ -2307,14 +2269,6 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op) break; } - /* XXX: Should be a generic function. */ - for (iseq = seqbase->first; iseq; iseq = iseq->next) { - if ((iseq->type & SEQ_TYPE_EFFECT) && - (seq_is_parent(iseq, active_seq) || seq_is_parent(iseq, seq))) { - SEQ_time_update_sequence(scene, seqbase, iseq); - } - } - /* Do this in a new loop since both effects need to be calculated first. */ for (iseq = seqbase->first; iseq; iseq = iseq->next) { if ((iseq->type & SEQ_TYPE_EFFECT) && @@ -2326,10 +2280,7 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op) } } - SEQ_sort(SEQ_active_seqbase_get(ed)); - WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); - return OPERATOR_FINISHED; } @@ -2576,8 +2527,8 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op) else { int min_seq_startdisp = INT_MAX; LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) { - if (seq->startdisp < min_seq_startdisp) { - min_seq_startdisp = seq->startdisp; + if (SEQ_time_left_handle_frame_get(seq) < min_seq_startdisp) { + min_seq_startdisp = SEQ_time_left_handle_frame_get(seq); } } /* Paste strips relative to the current-frame. */ @@ -2608,13 +2559,17 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op) * in the new list. */ BLI_movelisttolist(ed->seqbasep, &nseqbase); + /* Make sure, that pasted strips have unique names. This has to be done immediately after adding + * strips to seqbase, for lookup cache to work correctly. */ + for (iseq = iseq_first; iseq; iseq = iseq->next) { + SEQ_ensure_unique_name(iseq, scene); + } + for (iseq = iseq_first; iseq; iseq = iseq->next) { if (SEQ_clipboard_pasted_seq_was_active(iseq)) { SEQ_select_active_set(scene, iseq); } - /* Make sure, that pasted strips have unique names. */ - SEQ_ensure_unique_name(iseq, scene); /* Translate after name has been changed, otherwise this will affect animdata of original * strip. */ SEQ_transform_translate_sequence(scene, iseq, ofs); @@ -2692,10 +2647,6 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op) seq_act->scene_sound = NULL; seq_other->scene_sound = NULL; - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); - SEQ_time_update_sequence(scene, seqbase, seq_act); - SEQ_time_update_sequence(scene, seqbase, seq_other); - if (seq_act->sound) { BKE_sound_add_scene_sound_defaults(scene, seq_act); } @@ -2938,9 +2889,6 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op) /* Correct start/end frames so we don't move. * Important not to set seq->len = len; allow the function to handle it. */ SEQ_add_reload_new_file(bmain, scene, seq, true); - - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); - SEQ_time_update_sequence(scene, seqbase, seq); } else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) { bSound *sound = seq->sound; @@ -3160,7 +3108,7 @@ static bool seq_get_text_strip_cb(Sequence *seq, void *user_data) ListBase *channels = SEQ_channels_displayed_get(ed); /* Only text strips that are not muted and don't end with negative frame. */ if ((seq->type == SEQ_TYPE_TEXT) && !SEQ_render_is_muted(channels, seq) && - (seq->enddisp > cd->scene->r.sfra)) { + (SEQ_time_right_handle_frame_get(seq) > cd->scene->r.sfra)) { BLI_addtail(cd->text_seq, MEM_dupallocN(seq)); } return true; @@ -3218,16 +3166,17 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op) char timecode_str_end[32]; /* Write time-code relative to start frame of scene. Don't allow negative time-codes. */ - BLI_timecode_string_from_time(timecode_str_start, - sizeof(timecode_str_start), - -2, - FRA2TIME(max_ii(seq->startdisp - scene->r.sfra, 0)), - FPS, - USER_TIMECODE_SUBRIP); + BLI_timecode_string_from_time( + timecode_str_start, + sizeof(timecode_str_start), + -2, + FRA2TIME(max_ii(SEQ_time_left_handle_frame_get(seq) - scene->r.sfra, 0)), + FPS, + USER_TIMECODE_SUBRIP); BLI_timecode_string_from_time(timecode_str_end, sizeof(timecode_str_end), -2, - FRA2TIME(seq->enddisp - scene->r.sfra), + FRA2TIME(SEQ_time_right_handle_frame_get(seq) - scene->r.sfra), FPS, USER_TIMECODE_SUBRIP); @@ -3295,8 +3244,8 @@ static int sequencer_set_range_to_strips_exec(bContext *C, wmOperator *op) for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT) { selected = true; - sfra = min_ii(sfra, seq->startdisp); - efra = max_ii(efra, seq->enddisp - 1); + sfra = min_ii(sfra, SEQ_time_left_handle_frame_get(seq)); + efra = max_ii(efra, SEQ_time_right_handle_frame_get(seq) - 1); } } diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index 074be0fd120..f237fbc0a12 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -116,13 +116,13 @@ static void select_active_side(ListBase *seqbase, int sel_side, int channel, int if (channel == seq->machine) { switch (sel_side) { case SEQ_SIDE_LEFT: - if (frame > (seq->startdisp)) { + if (frame > (SEQ_time_left_handle_frame_get(seq))) { seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL); seq->flag |= SELECT; } break; case SEQ_SIDE_RIGHT: - if (frame < (seq->startdisp)) { + if (frame < (SEQ_time_left_handle_frame_get(seq))) { seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL); seq->flag |= SELECT; } @@ -152,13 +152,13 @@ static void select_active_side_range(ListBase *seqbase, } switch (sel_side) { case SEQ_SIDE_LEFT: - if (frame > (seq->startdisp)) { + if (frame > (SEQ_time_left_handle_frame_get(seq))) { seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL); seq->flag |= SELECT; } break; case SEQ_SIDE_RIGHT: - if (frame < (seq->startdisp)) { + if (frame < (SEQ_time_left_handle_frame_get(seq))) { seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL); seq->flag |= SELECT; } @@ -179,8 +179,8 @@ static void select_linked_time(ListBase *seqbase, Sequence *seq_link) for (seq = seqbase->first; seq; seq = seq->next) { if (seq_link->machine != seq->machine) { - int left_match = (seq->startdisp == seq_link->startdisp) ? 1 : 0; - int right_match = (seq->enddisp == seq_link->enddisp) ? 1 : 0; + int left_match = (SEQ_time_left_handle_frame_get(seq) == seq_link->startdisp) ? 1 : 0; + int right_match = (SEQ_time_right_handle_frame_get(seq) == seq_link->enddisp) ? 1 : 0; if (left_match && right_match) { /* Direct match, copy the selection settings. */ @@ -247,8 +247,8 @@ void ED_sequencer_select_sequence_single(Scene *scene, Sequence *seq, bool desel void seq_rectf(Sequence *seq, rctf *rect) { - rect->xmin = seq->startdisp; - rect->xmax = seq->enddisp; + rect->xmin = SEQ_time_left_handle_frame_get(seq); + rect->xmax = SEQ_time_right_handle_frame_get(seq); rect->ymin = seq->machine + SEQ_STRIP_OFSBOTTOM; rect->ymax = seq->machine + SEQ_STRIP_OFSTOP; } @@ -273,12 +273,12 @@ Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int se (sel == 0 && (seq->flag & SELECT) == 0))) { switch (lr) { case SEQ_SIDE_LEFT: - if (test->startdisp == (seq->enddisp)) { + if (SEQ_time_left_handle_frame_get(test) == (SEQ_time_right_handle_frame_get(seq))) { return seq; } break; case SEQ_SIDE_RIGHT: - if (test->enddisp == (seq->startdisp)) { + if (SEQ_time_right_handle_frame_get(test) == (SEQ_time_left_handle_frame_get(seq))) { return seq; } break; @@ -311,13 +311,18 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[ while (seq) { if (seq->machine == (int)y) { /* Check for both normal strips, and strips that have been flipped horizontally. */ - if (((seq->startdisp < seq->enddisp) && (seq->startdisp <= x && seq->enddisp >= x)) || - ((seq->startdisp > seq->enddisp) && (seq->startdisp >= x && seq->enddisp <= x))) { + if (((SEQ_time_left_handle_frame_get(seq) < SEQ_time_right_handle_frame_get(seq)) && + (SEQ_time_left_handle_frame_get(seq) <= x && + SEQ_time_right_handle_frame_get(seq) >= x)) || + ((SEQ_time_left_handle_frame_get(seq) > SEQ_time_right_handle_frame_get(seq)) && + (SEQ_time_left_handle_frame_get(seq) >= x && + SEQ_time_right_handle_frame_get(seq) <= x))) { if (SEQ_transform_sequence_can_be_translated(seq)) { /* Clamp handles to defined size in pixel space. */ handsize = 2.0f * sequence_handle_size_get_clamped(seq, pixelx); - displen = (float)abs(seq->startdisp - seq->enddisp); + displen = (float)abs(SEQ_time_left_handle_frame_get(seq) - + SEQ_time_right_handle_frame_get(seq)); /* Don't even try to grab the handles of small strips. */ if (displen / pixelx > 16) { @@ -332,10 +337,10 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[ CLAMP(handsize, 7 * pixelx, 30 * pixelx); } - if (handsize + seq->startdisp >= x) { + if (handsize + SEQ_time_left_handle_frame_get(seq) >= x) { *hand = SEQ_SIDE_LEFT; } - else if (-handsize + seq->enddisp <= x) { + else if (-handsize + SEQ_time_right_handle_frame_get(seq) <= x) { *hand = SEQ_SIDE_RIGHT; } } @@ -578,8 +583,8 @@ static void sequencer_select_side_of_frame(const bContext *C, const float x = UI_view2d_region_to_view_x(v2d, mval[0]); LISTBASE_FOREACH (Sequence *, seq_iter, SEQ_active_seqbase_get(ed)) { - if (((x < CFRA) && (seq_iter->enddisp <= CFRA)) || - ((x >= CFRA) && (seq_iter->startdisp >= CFRA))) { + if (((x < CFRA) && (SEQ_time_right_handle_frame_get(seq_iter) <= CFRA)) || + ((x >= CFRA) && (SEQ_time_left_handle_frame_get(seq_iter) >= CFRA))) { /* Select left or right. */ seq_iter->flag |= SELECT; recurs_sel_seq(seq_iter); @@ -634,7 +639,8 @@ static void sequencer_select_linked_handle(const bContext *C, case SEQ_SIDE_LEFT: if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) { seq->flag |= SELECT; - select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp); + select_active_side( + ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, SEQ_time_left_handle_frame_get(seq)); } else { seq->flag |= SELECT; @@ -647,7 +653,8 @@ static void sequencer_select_linked_handle(const bContext *C, case SEQ_SIDE_RIGHT: if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) { seq->flag |= SELECT; - select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp); + select_active_side( + ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, SEQ_time_left_handle_frame_get(seq)); } else { seq->flag |= SELECT; @@ -661,7 +668,8 @@ static void sequencer_select_linked_handle(const bContext *C, } else { - select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp); + select_active_side( + ed->seqbasep, sel_side, seq->machine, SEQ_time_left_handle_frame_get(seq)); } } } @@ -1428,10 +1436,10 @@ static int sequencer_select_side_of_frame_exec(bContext *C, wmOperator *op) bool test = false; switch (side) { case -1: - test = (timeline_frame >= seq->enddisp); + test = (timeline_frame >= SEQ_time_right_handle_frame_get(seq)); break; case 1: - test = (timeline_frame <= seq->startdisp); + test = (timeline_frame <= SEQ_time_left_handle_frame_get(seq)); break; case 2: test = SEQ_time_strip_intersects_frame(seq, timeline_frame); @@ -1505,10 +1513,10 @@ static int sequencer_select_side_exec(bContext *C, wmOperator *op) if (seq->flag & SELECT) { selected = true; if (sel_side == SEQ_SIDE_LEFT) { - *frame_limit_p = max_ii(*frame_limit_p, seq->startdisp); + *frame_limit_p = max_ii(*frame_limit_p, SEQ_time_left_handle_frame_get(seq)); } else { - *frame_limit_p = min_ii(*frame_limit_p, seq->startdisp); + *frame_limit_p = min_ii(*frame_limit_p, SEQ_time_left_handle_frame_get(seq)); } } } @@ -1648,7 +1656,7 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op) float handsize = sequence_handle_size_get_clamped(seq, pixelx); /* Right handle. */ - if (rectf.xmax > (seq->enddisp - handsize)) { + if (rectf.xmax > (SEQ_time_right_handle_frame_get(seq) - handsize)) { if (select) { seq->flag |= SELECT | SEQ_RIGHTSEL; } @@ -1661,7 +1669,7 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op) } } /* Left handle. */ - if (rectf.xmin < (seq->startdisp + handsize)) { + if (rectf.xmin < (SEQ_time_left_handle_frame_get(seq) + handsize)) { if (select) { seq->flag |= SELECT | SEQ_LEFTSEL; } @@ -1953,7 +1961,8 @@ static bool select_grouped_time_overlap(SeqCollection *strips, Sequence *seq; SEQ_ITERATOR_FOREACH (seq, strips) { - if (seq->startdisp < actseq->enddisp && seq->enddisp > actseq->startdisp) { + if (SEQ_time_left_handle_frame_get(seq) < SEQ_time_right_handle_frame_get(actseq) && + SEQ_time_right_handle_frame_get(seq) > SEQ_time_left_handle_frame_get(actseq)) { seq->flag |= SELECT; changed = true; } @@ -1971,8 +1980,10 @@ static void query_lower_channel_strips(Sequence *seq_reference, if (seq_test->machine > seq_reference->machine) { continue; /* Not lower channel. */ } - if (seq_test->enddisp <= seq_reference->startdisp || - seq_test->startdisp >= seq_reference->enddisp) { + if (SEQ_time_right_handle_frame_get(seq_test) <= + SEQ_time_left_handle_frame_get(seq_reference) || + SEQ_time_left_handle_frame_get(seq_test) >= + SEQ_time_right_handle_frame_get(seq_reference)) { continue; /* Not intersecting in time. */ } SEQ_collection_append_strip(seq_test, collection); diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.c b/source/blender/editors/space_sequencer/sequencer_thumbnails.c index eab17d876f3..984d3b1f374 100644 --- a/source/blender/editors/space_sequencer/sequencer_thumbnails.c +++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.c @@ -74,10 +74,10 @@ static bool check_seq_need_thumbnails(Sequence *seq, rctf *view_area) if (!ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE)) { return false; } - if (min_ii(seq->startdisp, seq->start) > view_area->xmax) { + if (min_ii(SEQ_time_left_handle_frame_get(seq), seq->start) > view_area->xmax) { return false; } - if (max_ii(seq->enddisp, seq->start + seq->len) < view_area->xmin) { + if (max_ii(SEQ_time_right_handle_frame_get(seq), seq->start + seq->len) < view_area->xmin) { return false; } if (seq->machine + 1.0f < view_area->ymin) { @@ -206,7 +206,7 @@ static GHash *sequencer_thumbnail_ghash_init(const bContext *C, View2D *v2d, Edi else { if (val_need_update != NULL) { val_need_update->seq_dupli->start = seq->start; - val_need_update->seq_dupli->startdisp = seq->startdisp; + val_need_update->seq_dupli->startdisp = SEQ_time_left_handle_frame_get(seq); } } } @@ -363,15 +363,16 @@ static int sequencer_thumbnail_closest_previous_frame_get(int timeline_frame, static int sequencer_thumbnail_closest_guaranteed_frame_get(Sequence *seq, int timeline_frame) { - if (timeline_frame <= seq->startdisp) { - return seq->startdisp; + if (timeline_frame <= SEQ_time_left_handle_frame_get(seq)) { + return SEQ_time_left_handle_frame_get(seq); } /* Set of "guaranteed" thumbnails. */ - const int frame_index = timeline_frame - seq->startdisp; + const int frame_index = timeline_frame - SEQ_time_left_handle_frame_get(seq); const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(seq); const int relative_base_frame = round_fl_to_int((frame_index / (float)frame_step)) * frame_step; - const int nearest_guaranted_absolute_frame = relative_base_frame + seq->startdisp; + const int nearest_guaranted_absolute_frame = relative_base_frame + + SEQ_time_left_handle_frame_get(seq); return nearest_guaranted_absolute_frame; } @@ -444,10 +445,11 @@ void draw_seq_strip_thumbnail(View2D *v2d, float thumb_y_end = y1 + thumb_height; float cut_off = 0; - float upper_thumb_bound = SEQ_time_has_right_still_frames(seq) ? (seq->start + seq->len) : - seq->enddisp; + float upper_thumb_bound = SEQ_time_has_right_still_frames(seq) ? + (seq->start + seq->len) : + SEQ_time_right_handle_frame_get(seq); if (seq->type == SEQ_TYPE_IMAGE) { - upper_thumb_bound = seq->enddisp; + upper_thumb_bound = SEQ_time_right_handle_frame_get(seq); } float timeline_frame = SEQ_render_thumbnail_first_frame_get(seq, thumb_width, &v2d->cur); @@ -473,8 +475,8 @@ void draw_seq_strip_thumbnail(View2D *v2d, } /* Set the clipping bound to show the left handle moving over thumbs and not shift thumbs. */ - if (IN_RANGE_INCL(seq->startdisp, timeline_frame, thumb_x_end)) { - cut_off = seq->startdisp - timeline_frame; + if (IN_RANGE_INCL(SEQ_time_left_handle_frame_get(seq), timeline_frame, thumb_x_end)) { + cut_off = SEQ_time_left_handle_frame_get(seq) - timeline_frame; clipped = true; } diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c index 93641375d42..857ca6d989b 100644 --- a/source/blender/editors/space_sequencer/sequencer_view.c +++ b/source/blender/editors/space_sequencer/sequencer_view.c @@ -306,8 +306,8 @@ static void seq_view_collection_rect_timeline(Scene *scene, SeqCollection *strip int xmargin = FPS; SEQ_ITERATOR_FOREACH (seq, strips) { - xmin = min_ii(xmin, seq->startdisp); - xmax = max_ii(xmax, seq->enddisp); + xmin = min_ii(xmin, SEQ_time_left_handle_frame_get(seq)); + xmax = max_ii(xmax, SEQ_time_right_handle_frame_get(seq)); ymin = min_ii(ymin, seq->machine); ymax = max_ii(ymax, seq->machine); diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index a498e5e99cf..dd3aac1eae9 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -302,6 +302,7 @@ static float get_default_column_width(const ColumnValues &values) switch (values.type()) { case SPREADSHEET_VALUE_TYPE_BOOL: return 2.0f; + case SPREADSHEET_VALUE_TYPE_INT8: case SPREADSHEET_VALUE_TYPE_INT32: return float_width; case SPREADSHEET_VALUE_TYPE_FLOAT: diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc index a29aa1fd026..46e98acb8e8 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc @@ -23,6 +23,9 @@ eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type) if (type.is<bool>()) { return SPREADSHEET_VALUE_TYPE_BOOL; } + if (type.is<int8_t>()) { + return SPREADSHEET_VALUE_TYPE_INT8; + } if (type.is<int>()) { return SPREADSHEET_VALUE_TYPE_INT32; } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc index ac15b77fde0..f5315b616d0 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -512,7 +512,7 @@ class GeometryComponentCacheValue : public SpreadsheetCache::Value { public: /* Stores the result of fields evaluated on a geometry component. Without this, fields would have * to be reevaluated on every redraw. */ - Map<std::pair<AttributeDomain, GField>, GArray<>> arrays; + Map<std::pair<eAttrDomain, GField>, GArray<>> arrays; }; static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet, @@ -526,7 +526,7 @@ static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet, sspreadsheet->runtime->cache.lookup_or_add<GeometryComponentCacheValue>( std::make_unique<GeometryComponentCacheKey>(component)); - const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain; + const eAttrDomain domain = (eAttrDomain)sspreadsheet->attribute_domain; const int domain_num = component.attribute_domain_num(domain); for (const auto item : fields_to_show.items()) { StringRef name = item.key; @@ -550,7 +550,7 @@ static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet, std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object *object_eval) { SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); - const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain; + const eAttrDomain domain = (eAttrDomain)sspreadsheet->attribute_domain; const GeometryComponentType component_type = get_display_component_type(C, object_eval); GeometrySet geometry_set = spreadsheet_get_display_geometry_set(sspreadsheet, object_eval); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh index 8b281e5a558..04b4f6d8d06 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh @@ -40,7 +40,7 @@ class GeometryDataSource : public DataSource { Object *object_eval_; const GeometrySet geometry_set_; const GeometryComponent *component_; - AttributeDomain domain_; + eAttrDomain domain_; ExtraColumns extra_columns_; /* Some data is computed on the fly only when it is requested. Computing it does not change the @@ -53,7 +53,7 @@ class GeometryDataSource : public DataSource { GeometryDataSource(Object *object_eval, GeometrySet geometry_set, const GeometryComponentType component_type, - const AttributeDomain domain, + const eAttrDomain domain, ExtraColumns extra_columns) : object_eval_(object_eval), geometry_set_(std::move(geometry_set)), diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc index 724d0783707..ee22f4173ab 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc @@ -27,7 +27,7 @@ class GeometryDataSetTreeView; class GeometryDataSetTreeViewItem : public ui::AbstractTreeViewItem { GeometryComponentType component_type_; - std::optional<AttributeDomain> domain_; + std::optional<eAttrDomain> domain_; BIFIconID icon_; public: @@ -35,7 +35,7 @@ class GeometryDataSetTreeViewItem : public ui::AbstractTreeViewItem { StringRef label, BIFIconID icon); GeometryDataSetTreeViewItem(GeometryComponentType component_type, - AttributeDomain domain, + eAttrDomain domain, StringRef label, BIFIconID icon); @@ -113,7 +113,7 @@ GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType c this->set_collapsed(false); } GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType component_type, - AttributeDomain domain, + eAttrDomain domain, StringRef label, BIFIconID icon) : component_type_(component_type), domain_(domain), icon_(icon) diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc index d76bbbf3be6..166c5de9fc3 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc @@ -84,7 +84,7 @@ static int select_component_domain_invoke(bContext *C, { GeometryComponentType component_type = static_cast<GeometryComponentType>( RNA_int_get(op->ptr, "component_type")); - AttributeDomain attribute_domain = static_cast<AttributeDomain>( + eAttrDomain attribute_domain = static_cast<eAttrDomain>( RNA_int_get(op->ptr, "attribute_domain_type")); SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc index 91ce5c2f6ec..e1ff4b59b14 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc @@ -71,6 +71,35 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter, } } } + else if (column_data.type().is<int8_t>()) { + const int value = row_filter.value_int; + switch (row_filter.operation) { + case SPREADSHEET_ROW_FILTER_EQUAL: { + apply_filter_operation( + column_data.typed<int8_t>(), + [&](const int cell) { return cell == value; }, + prev_mask, + new_indices); + break; + } + case SPREADSHEET_ROW_FILTER_GREATER: { + apply_filter_operation( + column_data.typed<int8_t>(), + [value](const int cell) { return cell > value; }, + prev_mask, + new_indices); + break; + } + case SPREADSHEET_ROW_FILTER_LESS: { + apply_filter_operation( + column_data.typed<int8_t>(), + [&](const int cell) { return cell < value; }, + prev_mask, + new_indices); + break; + } + } + } else if (column_data.type().is<int>()) { const int value = row_filter.value_int; switch (row_filter.operation) { diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc index 7c1ac024c12..d42a371c666 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc @@ -63,6 +63,7 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter, const eSpreadsheetColumnValueType data_type) { switch (data_type) { + case SPREADSHEET_VALUE_TYPE_INT8: case SPREADSHEET_VALUE_TYPE_INT32: return std::to_string(row_filter.value_int); case SPREADSHEET_VALUE_TYPE_FLOAT: { @@ -200,6 +201,10 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel) } switch (static_cast<eSpreadsheetColumnValueType>(column->data_type)) { + case SPREADSHEET_VALUE_TYPE_INT8: + uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE); + uiItemR(layout, filter_ptr, "value_int8", 0, IFACE_("Value"), ICON_NONE); + break; case SPREADSHEET_VALUE_TYPE_INT32: uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE); uiItemR(layout, filter_ptr, "value_int", 0, IFACE_("Value"), ICON_NONE); diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 9267ef7407a..a837102226b 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -2886,6 +2886,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op) struct SelectPick_Params params = {0}; ED_select_pick_params_from_operator(op->ptr, ¶ms); + const bool vert_without_handles = RNA_boolean_get(op->ptr, "vert_without_handles"); bool center = RNA_boolean_get(op->ptr, "center"); bool enumerate = RNA_boolean_get(op->ptr, "enumerate"); /* Only force object select for edit-mode to support vertex parenting, @@ -2940,7 +2941,8 @@ static int view3d_select_exec(bContext *C, wmOperator *op) changed = ED_lattice_select_pick(C, mval, ¶ms); } else if (ELEM(obedit->type, OB_CURVES_LEGACY, OB_SURF)) { - changed = ED_curve_editnurb_select_pick(C, mval, ED_view3d_select_dist_px(), ¶ms); + changed = ED_curve_editnurb_select_pick( + C, mval, ED_view3d_select_dist_px(), vert_without_handles, ¶ms); } else if (obedit->type == OB_MBALL) { changed = ED_mball_select_pick(C, mval, ¶ms); @@ -3017,6 +3019,15 @@ void VIEW3D_OT_select(wmOperatorType *ot) prop = RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (edit mode only)"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* Needed for select-through to usefully drag handles, see: T98254. + * NOTE: this option may be removed and become default behavior, see design task: T98552. */ + prop = RNA_def_boolean(ot->srna, + "vert_without_handles", + 0, + "Control Point Without Handles", + "Only select the curve control point, not it's handles"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_int_vector(ot->srna, "location", 2, diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index a7e2f616c9e..f8793e2a747 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1786,13 +1786,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->launch_event = event ? WM_userdef_event_type_from_keymap_type(event->type) : -1; t->is_launch_event_drag = event ? (event->val == KM_CLICK_DRAG) : false; - /* XXX Remove this when wm_operator_call_internal doesn't use window->eventstate - * (which can have type = 0) */ - /* For gizmo only, so assume LEFTMOUSE. */ - if (t->launch_event == 0) { - t->launch_event = LEFTMOUSE; - } - unit_m3(t->spacemtx); initTransInfo(C, t, op, event); diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index 3735ff0727c..68f04aab969 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -278,8 +278,6 @@ static void seq_transform_cancel(TransInfo *t, SeqCollection *transformed_strips if (SEQ_transform_test_overlap(seqbase, seq)) { SEQ_transform_seqbase_shuffle(seqbase, seq, t->scene); } - - SEQ_time_update_sequence(t->scene, seqbase, seq); } } @@ -313,43 +311,19 @@ static SeqCollection *query_right_side_strips(ListBase *seqbase, SeqCollection * { Sequence *seq; SEQ_ITERATOR_FOREACH (seq, transformed_strips) { - minframe = min_ii(minframe, seq->startdisp); + minframe = min_ii(minframe, SEQ_time_left_handle_frame_get(seq)); } } SeqCollection *collection = SEQ_collection_create(__func__); LISTBASE_FOREACH (Sequence *, seq, seqbase) { - if ((seq->flag & SELECT) == 0 && seq->startdisp >= minframe) { + if ((seq->flag & SELECT) == 0 && SEQ_time_left_handle_frame_get(seq) >= minframe) { SEQ_collection_append_strip(seq, collection); } } return collection; } -static void seq_transform_update_effects(Scene *scene, - ListBase *seqbasep, - SeqCollection *collection) -{ - Sequence *seq; - SEQ_ITERATOR_FOREACH (seq, collection) { - if ((seq->type & SEQ_TYPE_EFFECT) && (seq->seq1 || seq->seq2 || seq->seq3)) { - SEQ_time_update_sequence(scene, seqbasep, seq); - } - } -} - -/* Check if effect strips with input are transformed. */ -static bool seq_transform_check_strip_effects(SeqCollection *transformed_strips) -{ - Sequence *seq; - SEQ_ITERATOR_FOREACH (seq, transformed_strips) { - if ((seq->type & SEQ_TYPE_EFFECT) && (seq->seq1 || seq->seq2 || seq->seq3)) { - return true; - } - } - return false; -} - static ListBase *seqbase_active_get(const TransInfo *t) { Editing *ed = SEQ_editing_get(t->scene); @@ -388,7 +362,6 @@ static void seq_transform_handle_expand_to_fit(Scene *scene, * SEQ_transform_handle_overlap. */ SEQ_transform_seqbase_shuffle_time( right_side_strips, seqbasep, scene, markers, use_sync_markers); - seq_transform_update_effects(scene, seqbasep, right_side_strips); SEQ_collection_free(right_side_strips); } @@ -434,16 +407,20 @@ typedef enum eOvelapDescrition { static eOvelapDescrition overlap_description_get(const Sequence *transformed, const Sequence *target) { - if (transformed->startdisp <= target->startdisp && transformed->enddisp >= target->enddisp) { + if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_left_handle_frame_get(target) && + SEQ_time_right_handle_frame_get(transformed) >= SEQ_time_right_handle_frame_get(target)) { return STRIP_OVERLAP_IS_FULL; } - if (transformed->startdisp > target->startdisp && transformed->enddisp < target->enddisp) { + if (SEQ_time_left_handle_frame_get(transformed) > SEQ_time_left_handle_frame_get(target) && + SEQ_time_right_handle_frame_get(transformed) < SEQ_time_right_handle_frame_get(target)) { return STRIP_OVERLAP_IS_INSIDE; } - if (transformed->startdisp <= target->startdisp && target->startdisp <= transformed->enddisp) { + if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_left_handle_frame_get(target) && + SEQ_time_left_handle_frame_get(target) <= SEQ_time_right_handle_frame_get(transformed)) { return STRIP_OVERLAP_LEFT_SIDE; } - if (transformed->startdisp <= target->enddisp && target->enddisp <= transformed->enddisp) { + if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_right_handle_frame_get(target) && + SEQ_time_right_handle_frame_get(target) <= SEQ_time_right_handle_frame_get(transformed)) { return STRIP_OVERLAP_RIGHT_SIDE; } return STRIP_OVERLAP_NONE; @@ -459,10 +436,20 @@ static void seq_transform_handle_overwrite_split(Scene *scene, * NULL here. */ Main *bmain = NULL; - Sequence *split_strip = SEQ_edit_strip_split( - bmain, scene, seqbasep, target, transformed->startdisp, SEQ_SPLIT_SOFT, NULL); - SEQ_edit_strip_split( - bmain, scene, seqbasep, split_strip, transformed->enddisp, SEQ_SPLIT_SOFT, NULL); + Sequence *split_strip = SEQ_edit_strip_split(bmain, + scene, + seqbasep, + target, + SEQ_time_left_handle_frame_get(transformed), + SEQ_SPLIT_SOFT, + NULL); + SEQ_edit_strip_split(bmain, + scene, + seqbasep, + split_strip, + SEQ_time_right_handle_frame_get(transformed), + SEQ_SPLIT_SOFT, + NULL); SEQ_edit_flag_for_removal(scene, seqbasep, split_strip); SEQ_edit_remove_flagged_sequences(scene, seqbasep); } @@ -489,14 +476,12 @@ static void seq_transform_handle_overwrite_trim(Scene *scene, continue; } if (overlap == STRIP_OVERLAP_LEFT_SIDE) { - SEQ_time_left_handle_frame_set(seq, transformed->enddisp); + SEQ_time_left_handle_frame_set(scene, seq, SEQ_time_right_handle_frame_get(transformed)); } else { BLI_assert(overlap == STRIP_OVERLAP_RIGHT_SIDE); - SEQ_time_right_handle_frame_set(seq, transformed->startdisp); + SEQ_time_right_handle_frame_set(scene, seq, SEQ_time_left_handle_frame_get(transformed)); } - - SEQ_time_update_sequence(scene, seqbasep, seq); } SEQ_collection_free(targets); } @@ -577,11 +562,6 @@ void SEQ_transform_handle_overlap(Scene *scene, break; } - if (seq_transform_check_strip_effects(transformed_strips)) { - /* Update effect strips based on strips just moved in time. */ - seq_transform_update_effects(scene, seqbasep, transformed_strips); - } - /* If any effects still overlap, we need to move them up. * In some cases other strips can be overlapping still, see T90646. */ Sequence *seq; @@ -635,10 +615,7 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c SEQ_transform_handle_overlap(scene, seqbasep, transformed_strips, use_sync_markers); } - seq_transform_update_effects(scene, seqbasep, transformed_strips); SEQ_collection_free(transformed_strips); - - SEQ_sort(ed->seqbasep); DEG_id_tag_update(&t->scene->id, ID_RECALC_SEQUENCER_STRIPS); free_transform_custom_data(custom_data); } @@ -662,7 +639,10 @@ typedef enum SeqInputSide { static Sequence *effect_input_get(Sequence *effect, SeqInputSide side) { Sequence *input = effect->seq1; - if (effect->seq2 && (effect->seq2->startdisp - effect->seq1->startdisp) * side > 0) { + if (effect->seq2 && (SEQ_time_left_handle_frame_get(effect->seq2) - + SEQ_time_left_handle_frame_get(effect->seq1)) * + side > + 0) { input = effect->seq2; } return input; @@ -825,23 +805,6 @@ void createTransSeqData(TransInfo *t) /** \name UVs Transform Flush * \{ */ -/* commented _only_ because the meta may have animation data which - * needs moving too T28158. */ - -BLI_INLINE void trans_update_seq(Scene *sce, Sequence *seq, int old_start, int sel_flag) -{ - /* Calculate this strip and all nested strips. - * Children are ALWAYS transformed first so we don't need to do this in another loop. - */ - - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(sce)); - SEQ_time_update_sequence(sce, seqbase, seq); - - if (sel_flag == SELECT) { - SEQ_offset_animdata(sce, seq, seq->start - old_start); - } -} - static void view2d_edge_pan_loc_compensate(TransInfo *t, float loc_in[2], float r_loc[2]) { TransSeq *ts = (TransSeq *)TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->custom.type.data; @@ -914,24 +877,24 @@ static void flushTransSeq(TransInfo *t) break; } case SEQ_LEFTSEL: { /* No vertical transform. */ - int old_startdisp = seq->startdisp; - SEQ_time_left_handle_frame_set(seq, new_frame); - SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); - SEQ_transform_fix_single_image_seq_offsets(seq); - SEQ_time_update_sequence(t->scene, seqbasep, seq); - if (abs(seq->startdisp - old_startdisp) > abs(max_offset)) { - max_offset = seq->startdisp - old_startdisp; + int old_startdisp = SEQ_time_left_handle_frame_get(seq); + SEQ_time_left_handle_frame_set(t->scene, seq, new_frame); + SEQ_transform_handle_xlimits( + t->scene, seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); + SEQ_transform_fix_single_image_seq_offsets(t->scene, seq); + if (abs(SEQ_time_left_handle_frame_get(seq) - old_startdisp) > abs(max_offset)) { + max_offset = SEQ_time_left_handle_frame_get(seq) - old_startdisp; } break; } case SEQ_RIGHTSEL: { /* No vertical transform. */ - int old_enddisp = seq->enddisp; - SEQ_time_right_handle_frame_set(seq, new_frame); - SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); - SEQ_transform_fix_single_image_seq_offsets(seq); - SEQ_time_update_sequence(t->scene, seqbasep, seq); - if (abs(seq->enddisp - old_enddisp) > abs(max_offset)) { - max_offset = seq->enddisp - old_enddisp; + int old_enddisp = SEQ_time_right_handle_frame_get(seq); + SEQ_time_right_handle_frame_set(t->scene, seq, new_frame); + SEQ_transform_handle_xlimits( + t->scene, seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); + SEQ_transform_fix_single_image_seq_offsets(t->scene, seq); + if (abs(SEQ_time_right_handle_frame_get(seq) - old_enddisp) > abs(max_offset)) { + max_offset = SEQ_time_right_handle_frame_get(seq) - old_enddisp; } break; } @@ -945,15 +908,6 @@ static void flushTransSeq(TransInfo *t) SEQ_offset_animdata(t->scene, seq, max_offset); } - /* Update effect length and position. */ - if (ELEM(t->mode, TFM_SEQ_SLIDE, TFM_TIME_TRANSLATE)) { - for (seq = seqbasep->first; seq; seq = seq->next) { - if (seq->seq1 || seq->seq2 || seq->seq3) { - SEQ_time_update_sequence(t->scene, seqbasep, seq); - } - } - } - /* need to do the overlap check in a new loop otherwise adjacent strips * will not be updated and we'll get false positives */ SeqCollection *transformed_strips = seq_transform_collection_from_transdata(tc); diff --git a/source/blender/editors/transform/transform_snap_sequencer.c b/source/blender/editors/transform/transform_snap_sequencer.c index 7dc361ff5bb..dbcae2b6320 100644 --- a/source/blender/editors/transform/transform_snap_sequencer.c +++ b/source/blender/editors/transform/transform_snap_sequencer.c @@ -25,6 +25,7 @@ #include "SEQ_relations.h" #include "SEQ_render.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" #include "transform.h" #include "transform_snap.h" @@ -65,14 +66,14 @@ static void seq_snap_source_points_build(TransSeqSnapData *snap_data, SeqCollect SEQ_ITERATOR_FOREACH (seq, snap_sources) { int left = 0, right = 0; if (seq->flag & SEQ_LEFTSEL) { - left = right = seq->startdisp; + left = right = SEQ_time_left_handle_frame_get(seq); } else if (seq->flag & SEQ_RIGHTSEL) { - left = right = seq->enddisp; + left = right = SEQ_time_right_handle_frame_get(seq); } else { - left = seq->startdisp; - right = seq->enddisp; + left = SEQ_time_left_handle_frame_get(seq); + right = SEQ_time_right_handle_frame_get(seq); } snap_data->source_snap_points[i] = left; @@ -193,21 +194,24 @@ static void seq_snap_target_points_build(Scene *scene, Sequence *seq; SEQ_ITERATOR_FOREACH (seq, snap_targets) { - snap_data->target_snap_points[i] = seq->startdisp; - snap_data->target_snap_points[i + 1] = seq->enddisp; + snap_data->target_snap_points[i] = SEQ_time_left_handle_frame_get(seq); + snap_data->target_snap_points[i + 1] = SEQ_time_right_handle_frame_get(seq); i += 2; if (snap_mode & SEQ_SNAP_TO_STRIP_HOLD) { - int content_start = min_ii(seq->enddisp, seq->start); - int content_end = max_ii(seq->startdisp, seq->start + seq->len); + int content_start = min_ii(SEQ_time_right_handle_frame_get(seq), seq->start); + int content_end = max_ii(SEQ_time_left_handle_frame_get(seq), seq->start + seq->len); /* Effects and single image strips produce incorrect content length. Skip these strips. */ if ((seq->type & SEQ_TYPE_EFFECT) != 0 || seq->len == 1) { - content_start = seq->startdisp; - content_end = seq->enddisp; + content_start = SEQ_time_left_handle_frame_get(seq); + content_end = SEQ_time_right_handle_frame_get(seq); } - CLAMP(content_start, seq->startdisp, seq->enddisp); - CLAMP(content_end, seq->startdisp, seq->enddisp); + CLAMP(content_start, + SEQ_time_left_handle_frame_get(seq), + SEQ_time_right_handle_frame_get(seq)); + CLAMP( + content_end, SEQ_time_left_handle_frame_get(seq), SEQ_time_right_handle_frame_get(seq)); snap_data->target_snap_points[i] = content_start; snap_data->target_snap_points[i + 1] = content_end; diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index ead017a91bf..cea2bb05547 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -2425,7 +2425,7 @@ static bool uv_mouse_select_multi(bContext *C, UvNearestHit hit = UV_NEAREST_HIT_INIT_DIST_PX(®ion->v2d, 75.0f); int selectmode, sticky; bool found_item = false; - /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ + /* 0 == don't flush, 1 == sel, -1 == deselect; only use when selection sync is enabled. */ int flush = 0; /* Penalty (in pixels) applied to elements that are already selected @@ -2514,8 +2514,15 @@ static bool uv_mouse_select_multi(bContext *C, else if (selectmode == UV_SELECT_EDGE) { is_selected = uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset); } - else { /* Vertex or island. */ - is_selected = uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset); + else { + /* Vertex or island. For island (if we were using #uv_find_nearest_face_multi_ex, see above), + * `hit.l` is NULL, use `hit.efa` instead. */ + if (hit.l != NULL) { + is_selected = uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset); + } + else { + is_selected = uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset); + } } } @@ -2728,7 +2735,7 @@ static int uv_mouse_select_loop_generic_multi(bContext *C, const ToolSettings *ts = scene->toolsettings; UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(®ion->v2d); bool found_item = false; - /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ + /* 0 == don't flush, 1 == sel, -1 == deselect; only use when selection sync is enabled. */ int flush = 0; /* Find edge. */ @@ -3282,8 +3289,6 @@ static void uv_select_flush_from_tag_face(const Scene *scene, Object *obedit, co BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (select) { @@ -3353,8 +3358,6 @@ static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, co /* now select tagged verts */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); @@ -3373,8 +3376,6 @@ static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, co } BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { - /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l, BM_ELEM_TAG)) { uv_select_flush_from_tag_sticky_loc_internal( diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index bacf321fce1..55e44607f6f 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -1716,7 +1716,7 @@ static void stitch_draw_vbo(GPUVertBuf *vbo, GPUPrimType prim_type, const float GPU_batch_discard(batch); } -/* TODO: make things pretier : store batches inside StitchPreviewer instead of the bare verts pos +/* TODO: make things prettier : store batches inside StitchPreviewer instead of the bare verts pos */ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg) { diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 84dca352c9f..cbc9b2a8d06 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -301,22 +301,19 @@ void ED_uvedit_get_aspect(Object *ob, float *r_aspx, float *r_aspy) static void construct_param_handle_face_add(ParamHandle *handle, const Scene *scene, BMFace *efa, - int face_index, + ParamKey face_index, const int cd_loop_uv_offset) { - ParamKey key; ParamKey *vkeys = BLI_array_alloca(vkeys, efa->len); - ParamBool *pin = BLI_array_alloca(pin, efa->len); - ParamBool *select = BLI_array_alloca(select, efa->len); - float **co = BLI_array_alloca(co, efa->len); + bool *pin = BLI_array_alloca(pin, efa->len); + bool *select = BLI_array_alloca(select, efa->len); + const float **co = BLI_array_alloca(co, efa->len); float **uv = BLI_array_alloca(uv, efa->len); int i; BMIter liter; BMLoop *l; - key = (ParamKey)face_index; - /* let parametrizer split the ngon, it can make better decisions * about which split is best for unwrapping than poly-fill. */ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { @@ -329,7 +326,7 @@ static void construct_param_handle_face_add(ParamHandle *handle, select[i] = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); } - GEO_uv_parametrizer_face_add(handle, key, i, vkeys, co, uv, pin, select); + GEO_uv_parametrizer_face_add(handle, face_index, i, vkeys, co, uv, pin, select); } /* See: construct_param_handle_multi to handle multiple objects at once. */ @@ -500,8 +497,8 @@ static void texface_from_original_index(const Scene *scene, BMFace *efa, int index, float **r_uv, - ParamBool *r_pin, - ParamBool *r_select) + bool *r_pin, + bool *r_select) { BMLoop *l; BMIter liter; @@ -633,8 +630,8 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene, /* Prepare and feed faces to the solver */ for (i = 0, mpoly = subsurfedPolys; i < numOfFaces; i++, mpoly++) { ParamKey key, vkeys[4]; - ParamBool pin[4], select[4]; - float *co[4]; + bool pin[4], select[4]; + const float *co[4]; float *uv[4]; BMFace *origFace = faceMap[i]; @@ -652,7 +649,7 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene, mloop = &subsurfedLoops[mpoly->loopstart]; - /* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */ + /* We will not check for v4 here. Sub-surface faces always have 4 vertices. */ BLI_assert(mpoly->totloop == 4); key = (ParamKey)i; vkeys[0] = (ParamKey)mloop[0].v; @@ -1245,7 +1242,7 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit) handle = construct_param_handle(scene, obedit, em->bm, &options, NULL); } - GEO_uv_parametrizer_lscm_begin(handle, PARAM_TRUE, abf); + GEO_uv_parametrizer_lscm_begin(handle, true, abf); /* Create or increase size of g_live_unwrap.handles array */ if (g_live_unwrap.handles == NULL) { @@ -1796,7 +1793,7 @@ static void uvedit_unwrap(const Scene *scene, handle = construct_param_handle(scene, obedit, em->bm, options, result_info); } - GEO_uv_parametrizer_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0); + GEO_uv_parametrizer_lscm_begin(handle, false, scene->toolsettings->unwrapper == 0); GEO_uv_parametrizer_lscm_solve(handle, result_info ? &result_info->count_changed : NULL, result_info ? &result_info->count_failed : NULL); |