[Bf-blender-cvs] [cef2a25518d] blender2.8: Armature Edit Mode: improve box/lasso select

Campbell Barton noreply at git.blender.org
Thu Dec 13 11:11:30 CET 2018


Commit: cef2a25518dd41beb5335e73e5b765926b1eb387
Author: Campbell Barton
Date:   Thu Dec 13 19:05:11 2018 +1100
Branches: blender2.8
https://developer.blender.org/rBcef2a25518dd41beb5335e73e5b765926b1eb387

Armature Edit Mode: improve box/lasso select

Mostly rewrite logic which now matches (de)select picking,
share between both operators.

- Support all selection operations (eSelectOp), fixes T59255.

- Add function that selects using 'BONESEL_*' flags & eSelectOp.
  This avoids lasso & box select having to handle selection flushing.

- Fix strange behavior with lasso where selecting a bone in a chain
  would only select the tip (from 2.7x).

===================================================================

M	source/blender/editors/armature/armature_select.c
M	source/blender/editors/include/ED_armature.h
M	source/blender/editors/space_view3d/view3d_select.c

===================================================================

diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index d817fbf5229..830798fa737 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -732,6 +732,189 @@ bool ED_armature_edit_select_pick(bContext *C, const int mval[2], bool extend, b
 	return false;
 }
 
+/* -------------------------------------------------------------------- */
+/** \name Select Op From Tagged
+ *
+ * Implements #ED_armature_edit_select_op_from_tagged
+ * \{ */
+
+static bool armature_edit_select_op_apply(
+        bArmature *arm, EditBone *ebone, const eSelectOp sel_op, int is_ignore_flag, int is_inside_flag)
+{
+	BLI_assert(!(is_ignore_flag & ~(BONESEL_ROOT | BONESEL_TIP)));
+	BLI_assert(!(is_inside_flag & ~(BONESEL_ROOT | BONESEL_TIP | BONESEL_BONE)));
+	BLI_assert(EBONE_VISIBLE(arm, ebone));
+	bool changed = false;
+	bool is_point_done = false;
+	int points_proj_tot = 0;
+	BLI_assert(ebone->flag == ebone->temp.i);
+	const int ebone_flag_prev = ebone->flag;
+
+	if ((is_ignore_flag & BONE_ROOTSEL) == 0) {
+		points_proj_tot++;
+		const bool is_select = ebone->flag & BONE_ROOTSEL;
+		const bool is_inside = is_inside_flag & BONESEL_ROOT;
+		const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+		if (sel_op_result != -1) {
+			if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
+				SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_ROOTSEL);
+			}
+		}
+		is_point_done |= is_inside;
+	}
+
+	if ((is_ignore_flag & BONE_TIPSEL) == 0) {
+		points_proj_tot++;
+		const bool is_select = ebone->flag & BONE_TIPSEL;
+		const bool is_inside = is_inside_flag & BONESEL_TIP;
+		const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+		if (sel_op_result != -1) {
+			if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
+				SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_TIPSEL);
+			}
+		}
+		is_point_done |= is_inside;
+	}
+
+	/* if one of points selected, we skip the bone itself */
+	if ((is_point_done == false) && (points_proj_tot == 2)) {
+		const bool is_select = ebone->flag & BONE_SELECTED;
+		{
+			const bool is_inside = is_inside_flag & BONESEL_BONE;
+			const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+			if (sel_op_result != -1) {
+				if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
+					SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+				}
+			}
+		}
+
+		changed = true;
+	}
+	changed |= is_point_done;
+
+	if (ebone_flag_prev != ebone->flag) {
+		ebone->temp.i = ebone->flag;
+		ebone->flag = ebone_flag_prev;
+		ebone->flag = ebone_flag_prev | BONE_DONE;
+		changed = true;
+	}
+
+	return changed;
+}
+
+/**
+ * Perform a selection operation on elements which have been 'touched', use for lasso & border select
+ * but can be used elsewhere too.
+ *
+ * Tagging is done via #EditBone.temp.i using: #BONESEL_ROOT, #BONESEL_TIP, #BONESEL_BONE
+ * And optionally ignoring end-points using the #BONESEL_ROOT, #BONESEL_TIP right shifted 16 bits.
+ * (used when the values are clipped outside the view).
+ *
+ * \param sel_op: #eSelectOp type.
+ *
+ * \note Visibility checks must be done by the caller.
+ */
+bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
+{
+	bool changed = false;
+
+	/* Initialize flags. */
+	{
+		for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+
+			/* Flush the parent flag to this bone
+			 * so we don't need to check the parent when adjusting the selection. */
+			if ((ebone->flag & BONE_CONNECTED) && ebone->parent) {
+				if (ebone->parent->flag & BONE_TIPSEL) {
+					ebone->flag |= BONE_ROOTSEL;
+				}
+				else {
+					ebone->flag &= ~BONE_ROOTSEL;
+				}
+
+				/* Flush the 'temp.i' flag. */
+				if (ebone->parent->temp.i & BONESEL_TIP) {
+					ebone->temp.i |= BONESEL_ROOT;
+				}
+			}
+			ebone->flag &= ~BONE_DONE;
+		}
+	}
+
+	/* Apply selection from bone selection flags. */
+	for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+		if (ebone->temp.i != 0) {
+			int is_ignore_flag = ((ebone->temp.i << 16) & (BONESEL_ROOT | BONESEL_TIP));
+			int is_inside_flag = (ebone->temp.i & (BONESEL_ROOT | BONESEL_TIP | BONESEL_BONE));
+
+			/* Use as previous bone flag from now on. */
+			ebone->temp.i = ebone->flag;
+
+			/* When there is a partial selection without both endpoints, only select an endpoint. */
+			if ((is_inside_flag & BONESEL_BONE) &&
+			    (is_inside_flag & (BONESEL_ROOT | BONESEL_TIP)) &&
+			    ((is_inside_flag & (BONESEL_ROOT | BONESEL_TIP)) != (BONESEL_ROOT | BONESEL_TIP)))
+			{
+				is_inside_flag &= ~BONESEL_BONE;
+			}
+
+			changed |= armature_edit_select_op_apply(arm, ebone, sel_op, is_ignore_flag, is_inside_flag);
+		}
+	}
+
+	if (changed) {
+		/* Cleanup flags. */
+		for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+			if (ebone->flag & BONE_DONE) {
+				SWAP(int, ebone->temp.i, ebone->flag);
+				ebone->flag |= BONE_DONE;
+				if ((ebone->flag & BONE_CONNECTED) && ebone->parent) {
+					if ((ebone->parent->flag & BONE_DONE) == 0) {
+						/* Checked below. */
+						ebone->parent->temp.i = ebone->parent->flag;
+					}
+				}
+			}
+		}
+
+		for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+			if (ebone->flag & BONE_DONE) {
+				if ((ebone->flag & BONE_CONNECTED) && ebone->parent) {
+					bool is_parent_tip_changed = (ebone->parent->flag & BONE_TIPSEL) != (ebone->parent->temp.i & BONE_TIPSEL);
+					if ((ebone->temp.i & BONE_ROOTSEL) == 0) {
+						if ((ebone->flag & BONE_ROOTSEL) != 0) {
+							ebone->parent->flag |= BONE_TIPSEL;
+						}
+					}
+					else {
+						if ((ebone->flag & BONE_ROOTSEL) == 0) {
+							ebone->parent->flag &= ~BONE_TIPSEL;
+
+						}
+					}
+
+
+					if (is_parent_tip_changed == false) {
+						/* Keep tip selected if the parent remains selected. */
+						if (ebone->parent->flag & BONE_SELECTED) {
+							ebone->parent->flag |= BONE_TIPSEL;
+						}
+					}
+
+				}
+				ebone->flag &= ~BONE_DONE;
+			}
+		}
+
+		ED_armature_edit_sync_selection(arm->edbo);
+		ED_armature_edit_validate_active(arm);
+	}
+
+	return changed;
+}
+
+/** \} */
 
 /* ****************  Selections  ******************/
 
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 3131e5221d8..3306fa09f12 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -159,6 +159,10 @@ bool ED_armature_pose_select_pick_with_buffer(
         bool extend, bool deselect, bool toggle, bool do_nearest);
 bool ED_armature_edit_select_pick(
         struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+
+bool ED_armature_edit_select_op_from_tagged(
+        struct bArmature *arm, const int sel_op);
+
 int join_armature_exec(struct bContext *C, struct wmOperator *op);
 float ED_armature_ebone_roll_to_vector(const EditBone *bone, const float new_up_axis[3], const bool axis_only);
 EditBone *ED_armature_ebone_find_name(const struct ListBase *edbo, const char *name);
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index c740fa7814e..b3405b4659a 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -155,7 +155,7 @@ void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact)
 /** \} */
 
 /* -------------------------------------------------------------------- */
-/** \name Internal Utilities
+/** \name Internal Object Utilities
  * \{ */
 
 static void object_deselect_all_visible(ViewLayer *view_layer, View3D *v3d)
@@ -180,6 +180,12 @@ static void object_deselect_all_except(ViewLayer *view_layer, Base *b)   /* dese
 	}
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Edit-Mesh Utilities
+ * \{ */
+
 static void edbm_backbuf_check_and_select_verts(BMEditMesh *em, const eSelectOp sel_op)
 {
 	BMVert *eve;
@@ -766,61 +772,46 @@ static void do_lasso_select_lattice(ViewContext *vc, const int mcords[][2], shor
 	lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
 }
 
-static void do_lasso_select_armature__doSelectBone(void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
+static void do_lasso_select_armature__doSelectBone(
+        void *userData, EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
 {
 	LassoSelectUserData *data = userData;
 	bArmature *arm = data->vc->obedit->data;
 	if (EBONE_VISIBLE(arm, ebone)) {
-		bool is_point_done = false;
-		int points_proj_tot = 0;
+		int is_ignore_flag = 0;
+		int is_inside_flag = 0;
 
-		/* project head location to screenspace */
 		if (screen_co_a[0] != IS_CLIPPED) {
-			points_proj_tot++;
-			const bool is_select = ebone->flag & BONE_ROOTSEL;
-			const bool is_inside = (
-			        BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) &&
-			        BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX));
-			const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
-			if (sel_op_result != -1) {
-				if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
-					SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_ROOTSEL);
-				}
+			if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) &&
+			    BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX))
+			{
+				is_inside_flag |= BONESEL_ROOT;
 			}
-			is_point_done |= is_inside;
+		}
+		else {
+			is_ignore_flag |= BONESEL_ROOT;
 		}
 
-		/* project tail location to screenspace */
 		if (screen_co_b[0] != IS_CLIPPED) {
-			points_proj_tot++;
-			const bool is_select = ebone->flag & BONE_TIPSEL;
-			const bool is_inside = (
-			        BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) &&
-			        BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX));
-			const in

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list