Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2022-06-04 13:55:19 +0300
committerHans Goudey <h.goudey@me.com>2022-06-04 13:55:19 +0300
commit735cf5069c8e36b28f747b5b1a8fffe7505b0aa2 (patch)
treeb759966f323167c29cbb2d76b032f0cf857b10ce /source/blender/editors
parent5cbaf55fe60950c7e936f728bffbb2c68c80763e (diff)
parent9531eb24b3172d83660649cc0936c05f66aff79b (diff)
Merge branch 'master' into refactor-mesh-hide-generic
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/armature/armature_add.c9
-rw-r--r--source/blender/editors/armature/armature_naming.c9
-rw-r--r--source/blender/editors/armature/armature_relations.c27
-rw-r--r--source/blender/editors/armature/pose_select.c9
-rw-r--r--source/blender/editors/curve/editcurve.c39
-rw-r--r--source/blender/editors/curve/editcurve_pen.c4
-rw-r--r--source/blender/editors/curves/intern/curves_ops.cc262
-rw-r--r--source/blender/editors/geometry/geometry_attributes.cc49
-rw-r--r--source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c33
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c62
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h10
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c2
-rw-r--r--source/blender/editors/include/BIF_glutil.h20
-rw-r--r--source/blender/editors/include/ED_curve.h2
-rw-r--r--source/blender/editors/include/ED_geometry.h12
-rw-r--r--source/blender/editors/include/UI_interface.h2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c2
-rw-r--r--source/blender/editors/interface/interface_template_attribute_search.cc4
-rw-r--r--source/blender/editors/io/io_usd.c1
-rw-r--r--source/blender/editors/mesh/editface.cc2
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c2
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c4
-rw-r--r--source/blender/editors/object/object_add.cc13
-rw-r--r--source/blender/editors/object/object_bake.c20
-rw-r--r--source/blender/editors/object/object_bake_api.c18
-rw-r--r--source/blender/editors/object/object_constraint.c26
-rw-r--r--source/blender/editors/object/object_data_transfer.c4
-rw-r--r--source/blender/editors/object/object_ops.c12
-rw-r--r--source/blender/editors/object/object_vgroup.c26
-rw-r--r--source/blender/editors/screen/screen_edit.c4
-rw-r--r--source/blender/editors/screen/screen_ops.c4
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt2
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_add.cc69
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_brush.cc41
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_comb.cc95
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_delete.cc61
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc115
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_intern.hh34
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_ops.cc16
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_selection.cc105
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc393
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc103
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.cc4
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c15
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c9
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.cc40
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c21
-rw-r--r--source/blender/editors/space_file/filelist.c2
-rw-r--r--source/blender/editors/space_file/fsmenu.c2
-rw-r--r--source/blender/editors/space_image/image_buttons.c5
-rw-r--r--source/blender/editors/space_image/image_intern.h1
-rw-r--r--source/blender/editors/space_image/image_ops.c153
-rw-r--r--source/blender/editors/space_image/image_undo.c2
-rw-r--r--source/blender/editors/space_image/space_image.c1
-rw-r--r--source/blender/editors/space_nla/nla_edit.c6
-rw-r--r--source/blender/editors/space_node/node_draw.cc68
-rw-r--r--source/blender/editors/space_node/node_edit.cc26
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc10
-rw-r--r--source/blender/editors/space_node/node_relationships.cc4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c26
-rw-r--r--source/blender/editors/space_sequencer/sequencer_drag_drop.c5
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c108
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c151
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c69
-rw-r--r--source/blender/editors/space_sequencer/sequencer_thumbnails.c26
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c4
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc1
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.cc3
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc6
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh4
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc6
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_ops.cc2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc29
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc5
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c13
-rw-r--r--source/blender/editors/transform/transform.c7
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c134
-rw-r--r--source/blender/editors/transform/transform_snap_sequencer.c28
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c21
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c27
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, &params)) {
+ if (ED_curve_editnurb_select_pick(C, event->mval, threshold_dist_px, false, &params)) {
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, &params);
+ ED_curve_editnurb_select_pick(C, event->mval, threshold_dist_px, false, &params);
}
}
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, &params);
+ 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, &params);
}
else if (ELEM(obedit->type, OB_CURVES_LEGACY, OB_SURF)) {
- changed = ED_curve_editnurb_select_pick(C, mval, ED_view3d_select_dist_px(), &params);
+ changed = ED_curve_editnurb_select_pick(
+ C, mval, ED_view3d_select_dist_px(), vert_without_handles, &params);
}
else if (obedit->type == OB_MBALL) {
changed = ED_mball_select_pick(C, mval, &params);
@@ -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(&region->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(&region->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);