static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
{
	Object *obedit = CTX_data_edit_object(C);
	Object *ob;
	bArmature *arm;
	EditBone *curbone, *pabone, *chbone;
	int direction = RNA_enum_get(op->ptr, "direction");
	int add_to_sel = RNA_boolean_get(op->ptr, "extend");
	
	ob = obedit;
	arm = (bArmature *)ob->data;
	
	for (curbone = arm->edbo->first; curbone; curbone = curbone->next) {
		/* only work on bone if it is visible and its selection can change */
		if (EBONE_SELECTABLE(arm, curbone)) {
			if (curbone == arm->act_edbone) {
				if (direction == BONE_SELECT_PARENT) {
					if (curbone->parent == NULL) continue;
					else pabone = curbone->parent;
					
					if (EBONE_VISIBLE(arm, pabone)) {
						pabone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
						arm->act_edbone = pabone;
						if (pabone->parent) pabone->parent->flag |= BONE_TIPSEL;
						
						if (!add_to_sel) curbone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
						break;
					}
					
				}
				else { // BONE_SELECT_CHILD
					chbone = editbone_get_child(arm, curbone, 1);
					if (chbone == NULL) continue;
					
					if (EBONE_SELECTABLE(arm, chbone)) {
						chbone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
						arm->act_edbone = chbone;
						
						if (!add_to_sel) {
							curbone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL);
							if (curbone->parent) curbone->parent->flag &= ~BONE_TIPSEL;
						}
						break;
					}
				}
			}
		}
	}
	
	ED_armature_sync_selection(arm->edbo);
	
	WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
	
	return OPERATOR_FINISHED;
}
static void select_similar_layer(bArmature *arm, EditBone *ebone_act)
{
	EditBone *ebone;

	for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
		if (EBONE_SELECTABLE(arm, ebone)) {
			if (ebone->layer & ebone_act->layer) {
				ED_armature_edit_bone_select(ebone);
			}
		}
	}
}
예제 #3
0
static void do_outliner_ebone_select_recursive(bArmature *arm, EditBone *ebone_parent, bool select)
{
	EditBone *ebone;
	for (ebone = ebone_parent->next; ebone; ebone = ebone->next) {
		if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) {
			if (select && EBONE_SELECTABLE(arm, ebone))
				ebone->flag |= BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL;
			else
				ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
		}
	}
}
void ED_armature_deselect_all_visible(Object *obedit)
{
	bArmature *arm = obedit->data;
	EditBone    *ebone;

	for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
		/* first and foremost, bone must be visible and selected */
		if (EBONE_SELECTABLE(arm, ebone)) {
			ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
		}
	}

	ED_armature_sync_selection(arm->edbo);
}
static void select_similar_direction(bArmature *arm, EditBone *ebone_act, const float thresh)
{
	EditBone *ebone;
	float dir_act[3];
	sub_v3_v3v3(dir_act, ebone_act->head, ebone_act->tail);

	for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
		if (EBONE_SELECTABLE(arm, ebone)) {
			float dir[3];
			sub_v3_v3v3(dir, ebone->head, ebone->tail);

			if (angle_v3v3(dir_act, dir) / (float)M_PI < thresh) {
				ED_armature_edit_bone_select(ebone);
			}
		}
	}
}
static void select_similar_length(bArmature *arm, EditBone *ebone_act, const float thresh)
{
	EditBone *ebone;

	/* thresh is always relative to current length */
	const float len_min = ebone_act->length / (1.0f + thresh);
	const float len_max = ebone_act->length * (1.0f + thresh);

	for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
		if (EBONE_SELECTABLE(arm, ebone)) {
			if ((ebone->length >= len_min) &&
			    (ebone->length <= len_max))
			{
				ED_armature_edit_bone_select(ebone);
			}
		}
	}
}
static void select_similar_suffix(bArmature *arm, EditBone *ebone_act)
{
	EditBone *ebone;

	char body_tmp[MAX_VGROUP_NAME];
	char suffix_act[MAX_VGROUP_NAME];

	BKE_deform_split_suffix(ebone_act->name, body_tmp, suffix_act);

	if (suffix_act[0] == '\0')
		return;

	/* Find matches */
	for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
		if (EBONE_SELECTABLE(arm, ebone)) {
			char suffix_other[MAX_VGROUP_NAME];
			BKE_deform_split_suffix(ebone->name, body_tmp, suffix_other);
			if (!strcmp(suffix_act, suffix_other)) {
				ED_armature_edit_bone_select(ebone);
			}
		}
	}
}
예제 #8
0
/**
 * near duplicate of #armature_duplicate_selected_exec,
 * except for parenting part (keep in sync)
 */
static int armature_symmetrize_exec(bContext *C, wmOperator *op)
{
	bArmature *arm;
	EditBone *ebone_iter;
	EditBone *ebone_first_dupe = NULL;  /* The beginning of the duplicated mirrored bones in the edbo list */

	Object *obedit = CTX_data_edit_object(C);
	const int direction = RNA_enum_get(op->ptr, "direction");
	const int axis = 0;

	arm = obedit->data;

	/* cancel if nothing selected */
	if (CTX_DATA_COUNT(C, selected_bones) == 0)
		return OPERATOR_CANCELLED;

	ED_armature_sync_selection(arm->edbo); // XXX why is this needed?

	preEditBoneDuplicate(arm->edbo);

	/* Select mirrored bones */
	for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
		if (EBONE_VISIBLE(arm, ebone_iter) &&
		    (ebone_iter->flag & BONE_SELECTED))
		{
			char name_flip[MAX_VGROUP_NAME];

			BKE_deform_flip_side_name(name_flip, ebone_iter->name, false);

			if (STREQ(name_flip, ebone_iter->name)) {
				/* if the name matches, we don't have the potential to be mirrored, just skip */
				ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
			}
			else {
				EditBone *ebone = ED_armature_bone_find_name(arm->edbo, name_flip);

				if (ebone) {
					if ((ebone->flag & BONE_SELECTED) == 0) {
						/* simple case, we're selected, the other bone isn't! */
						ebone_iter->temp.ebone = ebone;
					}
					else {
						/* complicated - choose which direction to copy */
						float axis_delta;

						axis_delta = ebone->head[axis] - ebone_iter->head[axis];
						if (axis_delta == 0.0f) {
							axis_delta = ebone->tail[axis] - ebone_iter->tail[axis];
						}

						if (axis_delta == 0.0f) {
							/* both mirrored bones exist and point to eachother and overlap exactly.
							 *
							 * in this case theres no well defined solution, so de-select both and skip.
							 */
							ebone->flag      &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
							ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
						}
						else {
							EditBone *ebone_src, *ebone_dst;
							if (((axis_delta < 0.0f) ? -1 : 1) == direction) {
								ebone_src = ebone;
								ebone_dst = ebone_iter;
							}
							else {
								ebone_src = ebone_iter;
								ebone_dst = ebone;
							}

							ebone_src->temp.ebone = ebone_dst;
							ebone_dst->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
						}
					}
				}
			}
		}
	}

	/*	Find the selected bones and duplicate them as needed, with mirrored name */
	for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
		if (EBONE_VISIBLE(arm, ebone_iter) &&
		    (ebone_iter->flag & BONE_SELECTED) &&
		    /* will be set if the mirror bone already exists (no need to make a new one) */
		    (ebone_iter->temp.ebone == NULL))
		{
			char name_flip[MAX_VGROUP_NAME];

			BKE_deform_flip_side_name(name_flip, ebone_iter->name, false);

			/* bones must have a side-suffix */
			if (!STREQ(name_flip, ebone_iter->name)) {
				EditBone *ebone;

				ebone = duplicateEditBone(ebone_iter, name_flip, arm->edbo, obedit);

				if (!ebone_first_dupe) {
					ebone_first_dupe = ebone;
				}
			}
		}
	}

	/*	Run through the list and fix the pointers */
	for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
		if (ebone_iter->temp.ebone) {
			/* copy all flags except for ... */
			const int flag_copy = ((int)~0) & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);

			EditBone *ebone = ebone_iter->temp.ebone;

			/* copy flags incase bone is pre-existing data */
			ebone->flag = (ebone->flag & ~flag_copy) | (ebone_iter->flag & flag_copy);

			if (ebone_iter->parent == NULL) {
				/* If this bone has no parent,
				 * Set the duplicate->parent to NULL
				 */
				ebone->parent = NULL;
				ebone->flag &= ~BONE_CONNECTED;
			}
			else {
				/* the parent may have been duplicated, if not lookup the mirror parent */
				EditBone *ebone_parent =
				        (ebone_iter->parent->temp.ebone ?
				         ebone_iter->parent->temp.ebone : ED_armature_bone_get_mirrored(arm->edbo, ebone_iter->parent));

				if (ebone_parent == NULL) {
					/* If the mirror lookup failed, (but the current bone has a parent)
					 * then we can assume the parent has no L/R but is a center bone.
					 * So just use the same parent for both.
					 */
					ebone_parent = ebone_iter->parent;
					ebone->flag &= ~BONE_CONNECTED;
				}

				ebone->parent = ebone_parent;
			}

			/* Lets try to fix any constraint subtargets that might
			 * have been duplicated
			 */
			updateDuplicateSubtarget(ebone, arm->edbo, obedit);
		}
	}

	transform_armature_mirror_update(obedit);

	/* Selected bones now have their 'temp' pointer set,
	 * so we don't need this anymore */

	/* Deselect the old bones and select the new ones */
	for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
		if (EBONE_VISIBLE(arm, ebone_iter)) {
			ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
		}
	}

	/* New bones will be selected, but some of the bones may already exist */
	for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
		EditBone *ebone = ebone_iter->temp.ebone;
		if (ebone && EBONE_SELECTABLE(arm, ebone)) {
			ED_armature_ebone_select_set(ebone, true);
		}
	}

	/* correct the active bone */
	if (arm->act_edbone && arm->act_edbone->temp.ebone) {
		arm->act_edbone = arm->act_edbone->temp.ebone;
	}

	postEditBoneDuplicate(arm->edbo, obedit);

	ED_armature_validate_active(arm);

	WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);

	return OPERATOR_FINISHED;
}