1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17 * All rights reserved.
18 * Armature EditMode tools - transforms, chain based editing, and other settings
19 */
20
21 /** \file
22 * \ingroup edarmature
23 */
24
25 #include "DNA_armature_types.h"
26 #include "DNA_constraint_types.h"
27 #include "DNA_object_types.h"
28 #include "DNA_scene_types.h"
29
30 #include "MEM_guardedalloc.h"
31
32 #include "BLT_translation.h"
33
34 #include "BLI_blenlib.h"
35 #include "BLI_ghash.h"
36 #include "BLI_math.h"
37
38 #include "BKE_action.h"
39 #include "BKE_armature.h"
40 #include "BKE_constraint.h"
41 #include "BKE_context.h"
42 #include "BKE_global.h"
43 #include "BKE_layer.h"
44 #include "BKE_main.h"
45 #include "BKE_object.h"
46 #include "BKE_report.h"
47
48 #include "RNA_access.h"
49 #include "RNA_define.h"
50
51 #include "WM_api.h"
52 #include "WM_types.h"
53
54 #include "ED_armature.h"
55 #include "ED_outliner.h"
56 #include "ED_screen.h"
57 #include "ED_view3d.h"
58
59 #include "DEG_depsgraph.h"
60
61 #include "armature_intern.h"
62
63 /* -------------------------------------------------------------------- */
64 /** \name Object Tools Public API
65 * \{ */
66
67 /* NOTE: these functions are exported to the Object module to be called from the tools there */
68
69 /**
70 * See #BKE_armature_transform for object-mode transform.
71 */
ED_armature_edit_transform(bArmature * arm,const float mat[4][4],const bool do_props)72 void ED_armature_edit_transform(bArmature *arm, const float mat[4][4], const bool do_props)
73 {
74 EditBone *ebone;
75 float scale = mat4_to_scale(mat); /* store the scale of the matrix here to use on envelopes */
76 float mat3[3][3];
77
78 copy_m3_m4(mat3, mat);
79 normalize_m3(mat3);
80 /* Do the rotations */
81 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
82 float tmat[3][3];
83
84 /* find the current bone's roll matrix */
85 ED_armature_ebone_to_mat3(ebone, tmat);
86
87 /* transform the roll matrix */
88 mul_m3_m3m3(tmat, mat3, tmat);
89
90 /* transform the bone */
91 mul_m4_v3(mat, ebone->head);
92 mul_m4_v3(mat, ebone->tail);
93
94 /* apply the transformed roll back */
95 mat3_to_vec_roll(tmat, NULL, &ebone->roll);
96
97 if (do_props) {
98 ebone->rad_head *= scale;
99 ebone->rad_tail *= scale;
100 ebone->dist *= scale;
101
102 /* we could be smarter and scale by the matrix along the x & z axis */
103 ebone->xwidth *= scale;
104 ebone->zwidth *= scale;
105 }
106 }
107 }
108
ED_armature_transform(bArmature * arm,const float mat[4][4],const bool do_props)109 void ED_armature_transform(bArmature *arm, const float mat[4][4], const bool do_props)
110 {
111 if (arm->edbo) {
112 ED_armature_edit_transform(arm, mat, do_props);
113 }
114 else {
115 BKE_armature_transform(arm, mat, do_props);
116 }
117 }
118
119 /* exported for use in editors/object/ */
120 /* 0 == do center, 1 == center new, 2 == center cursor */
ED_armature_origin_set(Main * bmain,Object * ob,const float cursor[3],int centermode,int around)121 void ED_armature_origin_set(
122 Main *bmain, Object *ob, const float cursor[3], int centermode, int around)
123 {
124 const bool is_editmode = BKE_object_is_in_editmode(ob);
125 EditBone *ebone;
126 bArmature *arm = ob->data;
127 float cent[3];
128
129 /* Put the armature into editmode */
130 if (is_editmode == false) {
131 ED_armature_to_edit(arm);
132 }
133
134 /* Find the centerpoint */
135 if (centermode == 2) {
136 copy_v3_v3(cent, cursor);
137 invert_m4_m4(ob->imat, ob->obmat);
138 mul_m4_v3(ob->imat, cent);
139 }
140 else {
141 if (around == V3D_AROUND_CENTER_BOUNDS) {
142 float min[3], max[3];
143 INIT_MINMAX(min, max);
144 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
145 minmax_v3v3_v3(min, max, ebone->head);
146 minmax_v3v3_v3(min, max, ebone->tail);
147 }
148 mid_v3_v3v3(cent, min, max);
149 }
150 else { /* #V3D_AROUND_CENTER_MEDIAN. */
151 int total = 0;
152 zero_v3(cent);
153 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
154 total += 2;
155 add_v3_v3(cent, ebone->head);
156 add_v3_v3(cent, ebone->tail);
157 }
158 if (total) {
159 mul_v3_fl(cent, 1.0f / (float)total);
160 }
161 }
162 }
163
164 /* Do the adjustments */
165 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
166 sub_v3_v3(ebone->head, cent);
167 sub_v3_v3(ebone->tail, cent);
168 }
169
170 /* Turn the list into an armature */
171 if (is_editmode == false) {
172 ED_armature_from_edit(bmain, arm);
173 ED_armature_edit_free(arm);
174 }
175
176 /* Adjust object location for new centerpoint */
177 if (centermode && (is_editmode == false)) {
178 mul_mat3_m4_v3(ob->obmat, cent); /* omit translation part */
179 add_v3_v3(ob->loc, cent);
180 }
181 }
182
183 /** \} */
184
185 /* -------------------------------------------------------------------- */
186 /** \name Bone Roll Calculate Operator
187 * \{ */
188
189 /* adjust bone roll to align Z axis with vector
190 * vec is in local space and is normalized
191 */
ED_armature_ebone_roll_to_vector(const EditBone * bone,const float align_axis[3],const bool axis_only)192 float ED_armature_ebone_roll_to_vector(const EditBone *bone,
193 const float align_axis[3],
194 const bool axis_only)
195 {
196 float mat[3][3], nor[3];
197 float vec[3], align_axis_proj[3], roll = 0.0f;
198
199 BLI_ASSERT_UNIT_V3(align_axis);
200
201 sub_v3_v3v3(nor, bone->tail, bone->head);
202
203 /* If tail == head or the bone is aligned with the axis... */
204 if (normalize_v3(nor) <= FLT_EPSILON ||
205 (fabsf(dot_v3v3(align_axis, nor)) >= (1.0f - FLT_EPSILON))) {
206 return roll;
207 }
208
209 vec_roll_to_mat3_normalized(nor, 0.0f, mat);
210
211 /* project the new_up_axis along the normal */
212 project_v3_v3v3_normalized(vec, align_axis, nor);
213 sub_v3_v3v3(align_axis_proj, align_axis, vec);
214
215 if (axis_only) {
216 if (angle_v3v3(align_axis_proj, mat[2]) > (float)(M_PI_2)) {
217 negate_v3(align_axis_proj);
218 }
219 }
220
221 roll = angle_v3v3(align_axis_proj, mat[2]);
222
223 cross_v3_v3v3(vec, mat[2], align_axis_proj);
224
225 if (dot_v3v3(vec, nor) < 0.0f) {
226 return -roll;
227 }
228 return roll;
229 }
230
231 /* note, ranges arithmetic is used below */
232 typedef enum eCalcRollTypes {
233 /* pos */
234 CALC_ROLL_POS_X = 0,
235 CALC_ROLL_POS_Y,
236 CALC_ROLL_POS_Z,
237
238 CALC_ROLL_TAN_POS_X,
239 CALC_ROLL_TAN_POS_Z,
240
241 /* neg */
242 CALC_ROLL_NEG_X,
243 CALC_ROLL_NEG_Y,
244 CALC_ROLL_NEG_Z,
245
246 CALC_ROLL_TAN_NEG_X,
247 CALC_ROLL_TAN_NEG_Z,
248
249 /* no sign */
250 CALC_ROLL_ACTIVE,
251 CALC_ROLL_VIEW,
252 CALC_ROLL_CURSOR,
253 } eCalcRollTypes;
254
255 static const EnumPropertyItem prop_calc_roll_types[] = {
256 {0, "", 0, N_("Positive"), ""},
257 {CALC_ROLL_TAN_POS_X, "POS_X", 0, "Local +X Tangent", ""},
258 {CALC_ROLL_TAN_POS_Z, "POS_Z", 0, "Local +Z Tangent", ""},
259
260 {CALC_ROLL_POS_X, "GLOBAL_POS_X", 0, "Global +X Axis", ""},
261 {CALC_ROLL_POS_Y, "GLOBAL_POS_Y", 0, "Global +Y Axis", ""},
262 {CALC_ROLL_POS_Z, "GLOBAL_POS_Z", 0, "Global +Z Axis", ""},
263
264 {0, "", 0, N_("Negative"), ""},
265
266 {CALC_ROLL_TAN_NEG_X, "NEG_X", 0, "Local -X Tangent", ""},
267 {CALC_ROLL_TAN_NEG_Z, "NEG_Z", 0, "Local -Z Tangent", ""},
268
269 {CALC_ROLL_NEG_X, "GLOBAL_NEG_X", 0, "Global -X Axis", ""},
270 {CALC_ROLL_NEG_Y, "GLOBAL_NEG_Y", 0, "Global -Y Axis", ""},
271 {CALC_ROLL_NEG_Z, "GLOBAL_NEG_Z", 0, "Global -Z Axis", ""},
272
273 {0, "", 0, N_("Other"), ""},
274 {CALC_ROLL_ACTIVE, "ACTIVE", 0, "Active Bone", ""},
275 {CALC_ROLL_VIEW, "VIEW", 0, "View Axis", ""},
276 {CALC_ROLL_CURSOR, "CURSOR", 0, "Cursor", ""},
277 {0, NULL, 0, NULL, NULL},
278 };
279
armature_calc_roll_exec(bContext * C,wmOperator * op)280 static int armature_calc_roll_exec(bContext *C, wmOperator *op)
281 {
282 ViewLayer *view_layer = CTX_data_view_layer(C);
283 Object *ob_active = CTX_data_edit_object(C);
284 int ret = OPERATOR_FINISHED;
285
286 eCalcRollTypes type = RNA_enum_get(op->ptr, "type");
287 const bool axis_only = RNA_boolean_get(op->ptr, "axis_only");
288 /* axis_flip when matching the active bone never makes sense */
289 bool axis_flip = ((type >= CALC_ROLL_ACTIVE) ? RNA_boolean_get(op->ptr, "axis_flip") :
290 (type >= CALC_ROLL_TAN_NEG_X) ? true : false);
291
292 uint objects_len = 0;
293 Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
294 view_layer, CTX_wm_view3d(C), &objects_len);
295 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
296 Object *ob = objects[ob_index];
297 bArmature *arm = ob->data;
298 bool changed = false;
299
300 float imat[3][3];
301 EditBone *ebone;
302
303 if ((type >= CALC_ROLL_NEG_X) && (type <= CALC_ROLL_TAN_NEG_Z)) {
304 type -= (CALC_ROLL_ACTIVE - CALC_ROLL_NEG_X);
305 axis_flip = true;
306 }
307
308 copy_m3_m4(imat, ob->obmat);
309 invert_m3(imat);
310
311 if (type == CALC_ROLL_CURSOR) { /* Cursor */
312 Scene *scene = CTX_data_scene(C);
313 float cursor_local[3];
314 const View3DCursor *cursor = &scene->cursor;
315
316 invert_m4_m4(ob->imat, ob->obmat);
317 copy_v3_v3(cursor_local, cursor->location);
318 mul_m4_v3(ob->imat, cursor_local);
319
320 /* cursor */
321 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
322 if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
323 float cursor_rel[3];
324 sub_v3_v3v3(cursor_rel, cursor_local, ebone->head);
325 if (axis_flip) {
326 negate_v3(cursor_rel);
327 }
328 if (normalize_v3(cursor_rel) != 0.0f) {
329 ebone->roll = ED_armature_ebone_roll_to_vector(ebone, cursor_rel, axis_only);
330 changed = true;
331 }
332 }
333 }
334 }
335 else if (ELEM(type, CALC_ROLL_TAN_POS_X, CALC_ROLL_TAN_POS_Z)) {
336 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
337 if (ebone->parent) {
338 bool is_edit = (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone));
339 bool is_edit_parent = (EBONE_VISIBLE(arm, ebone->parent) &&
340 EBONE_EDITABLE(ebone->parent));
341
342 if (is_edit || is_edit_parent) {
343 EditBone *ebone_other = ebone->parent;
344 float dir_a[3];
345 float dir_b[3];
346 float vec[3];
347 bool is_vec_zero;
348
349 sub_v3_v3v3(dir_a, ebone->tail, ebone->head);
350 normalize_v3(dir_a);
351
352 /* find the first bone in the chain with a different direction */
353 do {
354 sub_v3_v3v3(dir_b, ebone_other->head, ebone_other->tail);
355 normalize_v3(dir_b);
356
357 if (type == CALC_ROLL_TAN_POS_Z) {
358 cross_v3_v3v3(vec, dir_a, dir_b);
359 }
360 else {
361 add_v3_v3v3(vec, dir_a, dir_b);
362 }
363 } while ((is_vec_zero = (normalize_v3(vec) < 0.00001f)) &&
364 (ebone_other = ebone_other->parent));
365
366 if (!is_vec_zero) {
367 if (axis_flip) {
368 negate_v3(vec);
369 }
370
371 if (is_edit) {
372 ebone->roll = ED_armature_ebone_roll_to_vector(ebone, vec, axis_only);
373 changed = true;
374 }
375
376 /* parentless bones use cross product with child */
377 if (is_edit_parent) {
378 if (ebone->parent->parent == NULL) {
379 ebone->parent->roll = ED_armature_ebone_roll_to_vector(
380 ebone->parent, vec, axis_only);
381 changed = true;
382 }
383 }
384 }
385 }
386 }
387 }
388 }
389 else {
390 float vec[3] = {0.0f, 0.0f, 0.0f};
391 if (type == CALC_ROLL_VIEW) { /* View */
392 RegionView3D *rv3d = CTX_wm_region_view3d(C);
393 if (rv3d == NULL) {
394 BKE_report(op->reports, RPT_ERROR, "No region view3d available");
395 ret = OPERATOR_CANCELLED;
396 goto cleanup;
397 }
398
399 copy_v3_v3(vec, rv3d->viewinv[2]);
400 mul_m3_v3(imat, vec);
401 }
402 else if (type == CALC_ROLL_ACTIVE) {
403 float mat[3][3];
404 bArmature *arm_active = ob_active->data;
405 ebone = (EditBone *)arm_active->act_edbone;
406 if (ebone == NULL) {
407 BKE_report(op->reports, RPT_ERROR, "No active bone set");
408 ret = OPERATOR_CANCELLED;
409 goto cleanup;
410 }
411
412 ED_armature_ebone_to_mat3(ebone, mat);
413 copy_v3_v3(vec, mat[2]);
414 }
415 else { /* Axis */
416 BLI_assert(type <= 5);
417 if (type < 3) {
418 vec[type] = 1.0f;
419 }
420 else {
421 vec[type - 2] = -1.0f;
422 }
423 mul_m3_v3(imat, vec);
424 normalize_v3(vec);
425 }
426
427 if (axis_flip) {
428 negate_v3(vec);
429 }
430
431 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
432 if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
433 /* roll func is a callback which assumes that all is well */
434 ebone->roll = ED_armature_ebone_roll_to_vector(ebone, vec, axis_only);
435 changed = true;
436 }
437 }
438 }
439
440 if (arm->flag & ARM_MIRROR_EDIT) {
441 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
442 if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
443 EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
444 if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
445 ebone->roll = -ebone_mirr->roll;
446 }
447 }
448 }
449 }
450
451 if (changed) {
452 /* note, notifier might evolve */
453 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
454 DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
455 }
456 }
457
458 cleanup:
459 MEM_freeN(objects);
460 return ret;
461 }
462
ARMATURE_OT_calculate_roll(wmOperatorType * ot)463 void ARMATURE_OT_calculate_roll(wmOperatorType *ot)
464 {
465 /* identifiers */
466 ot->name = "Recalculate Roll";
467 ot->idname = "ARMATURE_OT_calculate_roll";
468 ot->description = "Automatically fix alignment of select bones' axes";
469
470 /* api callbacks */
471 ot->invoke = WM_menu_invoke;
472 ot->exec = armature_calc_roll_exec;
473 ot->poll = ED_operator_editarmature;
474
475 /* flags */
476 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
477
478 /* properties */
479 ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, CALC_ROLL_TAN_POS_X, "Type", "");
480 RNA_def_boolean(ot->srna, "axis_flip", 0, "Flip Axis", "Negate the alignment axis");
481 RNA_def_boolean(ot->srna,
482 "axis_only",
483 0,
484 "Shortest Rotation",
485 "Ignore the axis direction, use the shortest rotation to align");
486 }
487
armature_roll_clear_exec(bContext * C,wmOperator * op)488 static int armature_roll_clear_exec(bContext *C, wmOperator *op)
489 {
490 ViewLayer *view_layer = CTX_data_view_layer(C);
491 const float roll = RNA_float_get(op->ptr, "roll");
492
493 uint objects_len = 0;
494 Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
495 view_layer, CTX_wm_view3d(C), &objects_len);
496 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
497 Object *ob = objects[ob_index];
498 bArmature *arm = ob->data;
499 bool changed = false;
500
501 LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
502 if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
503 /* Roll func is a callback which assumes that all is well. */
504 ebone->roll = roll;
505 changed = true;
506 }
507 }
508
509 if (arm->flag & ARM_MIRROR_EDIT) {
510 LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
511 if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
512 EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
513 if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
514 ebone->roll = -ebone_mirr->roll;
515 changed = true;
516 }
517 }
518 }
519 }
520
521 if (changed) {
522 /* Note, notifier might evolve. */
523 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
524 DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
525 }
526 }
527 MEM_freeN(objects);
528
529 return OPERATOR_FINISHED;
530 }
531
ARMATURE_OT_roll_clear(wmOperatorType * ot)532 void ARMATURE_OT_roll_clear(wmOperatorType *ot)
533 {
534 /* identifiers */
535 ot->name = "Clear Roll";
536 ot->idname = "ARMATURE_OT_roll_clear";
537 ot->description = "Clear roll for selected bones";
538
539 /* api callbacks */
540 ot->exec = armature_roll_clear_exec;
541 ot->poll = ED_operator_editarmature;
542
543 /* flags */
544 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
545
546 RNA_def_float_rotation(ot->srna,
547 "roll",
548 0,
549 NULL,
550 DEG2RADF(-360.0f),
551 DEG2RADF(360.0f),
552 "Roll",
553 "",
554 DEG2RADF(-360.0f),
555 DEG2RADF(360.0f));
556 }
557
558 /** \} */
559
560 /* -------------------------------------------------------------------- */
561 /** \name Chain-Based Tool Utilities
562 * \{ */
563
564 /* temporary data-structure for merge/fill bones */
565 typedef struct EditBonePoint {
566 struct EditBonePoint *next, *prev;
567
568 EditBone *head_owner; /* EditBone which uses this point as a 'head' point */
569 EditBone *tail_owner; /* EditBone which uses this point as a 'tail' point */
570
571 float vec[3]; /* the actual location of the point in local/EditMode space */
572 } EditBonePoint;
573
574 /* find chain-tips (i.e. bones without children) */
chains_find_tips(ListBase * edbo,ListBase * list)575 static void chains_find_tips(ListBase *edbo, ListBase *list)
576 {
577 EditBone *curBone, *ebo;
578 LinkData *ld;
579
580 /* note: this is potentially very slow ... there's got to be a better way */
581 for (curBone = edbo->first; curBone; curBone = curBone->next) {
582 short stop = 0;
583
584 /* is this bone contained within any existing chain? (skip if so) */
585 for (ld = list->first; ld; ld = ld->next) {
586 for (ebo = ld->data; ebo; ebo = ebo->parent) {
587 if (ebo == curBone) {
588 stop = 1;
589 break;
590 }
591 }
592
593 if (stop) {
594 break;
595 }
596 }
597 /* skip current bone if it is part of an existing chain */
598 if (stop) {
599 continue;
600 }
601
602 /* is any existing chain part of the chain formed by this bone? */
603 stop = 0;
604 for (ebo = curBone->parent; ebo; ebo = ebo->parent) {
605 for (ld = list->first; ld; ld = ld->next) {
606 if (ld->data == ebo) {
607 ld->data = curBone;
608 stop = 1;
609 break;
610 }
611 }
612
613 if (stop) {
614 break;
615 }
616 }
617 /* current bone has already been added to a chain? */
618 if (stop) {
619 continue;
620 }
621
622 /* add current bone to a new chain */
623 ld = MEM_callocN(sizeof(LinkData), "BoneChain");
624 ld->data = curBone;
625 BLI_addtail(list, ld);
626 }
627 }
628
629 /** \} */
630
631 /* -------------------------------------------------------------------- */
632 /** \name Fill Operator
633 * \{ */
634
fill_add_joint(EditBone * ebo,short eb_tail,ListBase * points)635 static void fill_add_joint(EditBone *ebo, short eb_tail, ListBase *points)
636 {
637 EditBonePoint *ebp;
638 float vec[3];
639 short found = 0;
640
641 if (eb_tail) {
642 copy_v3_v3(vec, ebo->tail);
643 }
644 else {
645 copy_v3_v3(vec, ebo->head);
646 }
647
648 for (ebp = points->first; ebp; ebp = ebp->next) {
649 if (equals_v3v3(ebp->vec, vec)) {
650 if (eb_tail) {
651 if ((ebp->head_owner) && (ebp->head_owner->parent == ebo)) {
652 /* so this bone's tail owner is this bone */
653 ebp->tail_owner = ebo;
654 found = 1;
655 break;
656 }
657 }
658 else {
659 if ((ebp->tail_owner) && (ebo->parent == ebp->tail_owner)) {
660 /* so this bone's head owner is this bone */
661 ebp->head_owner = ebo;
662 found = 1;
663 break;
664 }
665 }
666 }
667 }
668
669 /* allocate a new point if no existing point was related */
670 if (found == 0) {
671 ebp = MEM_callocN(sizeof(EditBonePoint), "EditBonePoint");
672
673 if (eb_tail) {
674 copy_v3_v3(ebp->vec, ebo->tail);
675 ebp->tail_owner = ebo;
676 }
677 else {
678 copy_v3_v3(ebp->vec, ebo->head);
679 ebp->head_owner = ebo;
680 }
681
682 BLI_addtail(points, ebp);
683 }
684 }
685
686 /* bone adding between selected joints */
armature_fill_bones_exec(bContext * C,wmOperator * op)687 static int armature_fill_bones_exec(bContext *C, wmOperator *op)
688 {
689 Scene *scene = CTX_data_scene(C);
690 View3D *v3d = CTX_wm_view3d(C);
691 ListBase points = {NULL, NULL};
692 EditBone *newbone = NULL;
693 int count;
694 bool mixed_object_error = false;
695
696 /* loop over all bones, and only consider if visible */
697 bArmature *arm = NULL;
698 CTX_DATA_BEGIN_WITH_ID (C, EditBone *, ebone, visible_bones, bArmature *, arm_iter) {
699 bool check = false;
700 if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL)) {
701 fill_add_joint(ebone, 0, &points);
702 check = true;
703 }
704 if (ebone->flag & BONE_TIPSEL) {
705 fill_add_joint(ebone, 1, &points);
706 check = true;
707 }
708
709 if (check) {
710 if (arm && (arm != arm_iter)) {
711 mixed_object_error = true;
712 }
713 arm = arm_iter;
714 }
715 }
716 CTX_DATA_END;
717
718 /* the number of joints determines how we fill:
719 * 1) between joint and cursor (joint=head, cursor=tail)
720 * 2) between the two joints (order is dependent on active-bone/hierarchy)
721 * 3+) error (a smarter method involving finding chains needs to be worked out
722 */
723 count = BLI_listbase_count(&points);
724
725 if (count == 0) {
726 BKE_report(op->reports, RPT_ERROR, "No joints selected");
727 return OPERATOR_CANCELLED;
728 }
729
730 if (mixed_object_error) {
731 BKE_report(op->reports, RPT_ERROR, "Bones for different objects selected");
732 BLI_freelistN(&points);
733 return OPERATOR_CANCELLED;
734 }
735
736 Object *obedit = NULL;
737 {
738 ViewLayer *view_layer = CTX_data_view_layer(C);
739 FOREACH_OBJECT_IN_EDIT_MODE_BEGIN (view_layer, v3d, ob_iter) {
740 if (ob_iter->data == arm) {
741 obedit = ob_iter;
742 }
743 }
744 FOREACH_OBJECT_IN_MODE_END;
745 }
746 BLI_assert(obedit != NULL);
747
748 if (count == 1) {
749 EditBonePoint *ebp;
750 float curs[3];
751
752 /* Get Points - selected joint */
753 ebp = points.first;
754
755 /* Get points - cursor (tail) */
756 invert_m4_m4(obedit->imat, obedit->obmat);
757 mul_v3_m4v3(curs, obedit->imat, scene->cursor.location);
758
759 /* Create a bone */
760 newbone = add_points_bone(obedit, ebp->vec, curs);
761 }
762 else if (count == 2) {
763 EditBonePoint *ebp_a, *ebp_b;
764 float head[3], tail[3];
765 short headtail = 0;
766
767 /* check that the points don't belong to the same bone */
768 ebp_a = (EditBonePoint *)points.first;
769 ebp_b = ebp_a->next;
770
771 if (((ebp_a->head_owner == ebp_b->tail_owner) && (ebp_a->head_owner != NULL)) ||
772 ((ebp_a->tail_owner == ebp_b->head_owner) && (ebp_a->tail_owner != NULL))) {
773 BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
774 BLI_freelistN(&points);
775 return OPERATOR_CANCELLED;
776 }
777
778 /* find which one should be the 'head' */
779 if ((ebp_a->head_owner && ebp_b->head_owner) || (ebp_a->tail_owner && ebp_b->tail_owner)) {
780 /* use active, nice predictable */
781 if (arm->act_edbone && ELEM(arm->act_edbone, ebp_a->head_owner, ebp_a->tail_owner)) {
782 headtail = 1;
783 }
784 else if (arm->act_edbone && ELEM(arm->act_edbone, ebp_b->head_owner, ebp_b->tail_owner)) {
785 headtail = 2;
786 }
787 else {
788 /* rule: whichever one is closer to 3d-cursor */
789 float curs[3];
790 float dist_sq_a, dist_sq_b;
791
792 /* get cursor location */
793 invert_m4_m4(obedit->imat, obedit->obmat);
794 mul_v3_m4v3(curs, obedit->imat, scene->cursor.location);
795
796 /* get distances */
797 dist_sq_a = len_squared_v3v3(ebp_a->vec, curs);
798 dist_sq_b = len_squared_v3v3(ebp_b->vec, curs);
799
800 /* compare distances - closer one therefore acts as direction for bone to go */
801 headtail = (dist_sq_a < dist_sq_b) ? 2 : 1;
802 }
803 }
804 else if (ebp_a->head_owner) {
805 headtail = 1;
806 }
807 else if (ebp_b->head_owner) {
808 headtail = 2;
809 }
810
811 /* assign head/tail combinations */
812 if (headtail == 2) {
813 copy_v3_v3(head, ebp_a->vec);
814 copy_v3_v3(tail, ebp_b->vec);
815 }
816 else if (headtail == 1) {
817 copy_v3_v3(head, ebp_b->vec);
818 copy_v3_v3(tail, ebp_a->vec);
819 }
820
821 /* add new bone and parent it to the appropriate end */
822 if (headtail) {
823 newbone = add_points_bone(obedit, head, tail);
824
825 /* do parenting (will need to set connected flag too) */
826 if (headtail == 2) {
827 /* ebp tail or head - tail gets priority */
828 if (ebp_a->tail_owner) {
829 newbone->parent = ebp_a->tail_owner;
830 }
831 else {
832 newbone->parent = ebp_a->head_owner;
833 }
834 }
835 else {
836 /* ebp_b tail or head - tail gets priority */
837 if (ebp_b->tail_owner) {
838 newbone->parent = ebp_b->tail_owner;
839 }
840 else {
841 newbone->parent = ebp_b->head_owner;
842 }
843 }
844
845 /* don't set for bone connecting two head points of bones */
846 if (ebp_a->tail_owner || ebp_b->tail_owner) {
847 newbone->flag |= BONE_CONNECTED;
848 }
849 }
850 }
851 else {
852 BKE_reportf(op->reports, RPT_ERROR, "Too many points selected: %d", count);
853 BLI_freelistN(&points);
854 return OPERATOR_CANCELLED;
855 }
856
857 if (newbone) {
858 ED_armature_edit_deselect_all(obedit);
859 arm->act_edbone = newbone;
860 newbone->flag |= BONE_TIPSEL;
861 }
862
863 /* updates */
864 ED_armature_edit_refresh_layer_used(arm);
865 WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
866 DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
867
868 /* free points */
869 BLI_freelistN(&points);
870
871 return OPERATOR_FINISHED;
872 }
873
ARMATURE_OT_fill(wmOperatorType * ot)874 void ARMATURE_OT_fill(wmOperatorType *ot)
875 {
876 /* identifiers */
877 ot->name = "Fill Between Joints";
878 ot->idname = "ARMATURE_OT_fill";
879 ot->description = "Add bone between selected joint(s) and/or 3D-Cursor";
880
881 /* callbacks */
882 ot->exec = armature_fill_bones_exec;
883 ot->poll = ED_operator_editarmature;
884
885 /* flags */
886 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
887 }
888
889 /** \} */
890
891 /* -------------------------------------------------------------------- */
892 /** \name Switch Direction Operator
893 *
894 * Currently, this does not use context loops, as context loops do not make it
895 * easy to retrieve any hierarchical/chain relationships which are necessary for
896 * this to be done easily.
897 * \{ */
898
899 /* helper to clear BONE_TRANSFORM flags */
armature_clear_swap_done_flags(bArmature * arm)900 static void armature_clear_swap_done_flags(bArmature *arm)
901 {
902 EditBone *ebone;
903
904 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
905 ebone->flag &= ~BONE_TRANSFORM;
906 }
907 }
908
armature_switch_direction_exec(bContext * C,wmOperator * UNUSED (op))909 static int armature_switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
910 {
911 ViewLayer *view_layer = CTX_data_view_layer(C);
912 uint objects_len = 0;
913 Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
914 view_layer, CTX_wm_view3d(C), &objects_len);
915
916 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
917 Object *ob = objects[ob_index];
918 bArmature *arm = ob->data;
919
920 ListBase chains = {NULL, NULL};
921 LinkData *chain;
922
923 /* get chains of bones (ends on chains) */
924 chains_find_tips(arm->edbo, &chains);
925 if (BLI_listbase_is_empty(&chains)) {
926 continue;
927 }
928
929 /* ensure that mirror bones will also be operated on */
930 armature_tag_select_mirrored(arm);
931
932 /* Clear BONE_TRANSFORM flags
933 * - Used to prevent duplicate/canceling operations from occurring T34123.
934 * - #BONE_DONE cannot be used here as that's already used for mirroring.
935 */
936 armature_clear_swap_done_flags(arm);
937
938 /* loop over chains, only considering selected and visible bones */
939 for (chain = chains.first; chain; chain = chain->next) {
940 EditBone *ebo, *child = NULL, *parent = NULL;
941
942 /* loop over bones in chain */
943 for (ebo = chain->data; ebo; ebo = parent) {
944 /* parent is this bone's original parent
945 * - we store this, as the next bone that is checked is this one
946 * but the value of ebo->parent may change here...
947 */
948 parent = ebo->parent;
949
950 /* skip bone if already handled, see T34123. */
951 if ((ebo->flag & BONE_TRANSFORM) == 0) {
952 /* only if selected and editable */
953 if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) {
954 /* swap head and tail coordinates */
955 swap_v3_v3(ebo->head, ebo->tail);
956
957 /* do parent swapping:
958 * - use 'child' as new parent
959 * - connected flag is only set if points are coincidental
960 */
961 ebo->parent = child;
962 if ((child) && equals_v3v3(ebo->head, child->tail)) {
963 ebo->flag |= BONE_CONNECTED;
964 }
965 else {
966 ebo->flag &= ~BONE_CONNECTED;
967 }
968
969 /* get next bones
970 * - child will become the new parent of next bone
971 */
972 child = ebo;
973 }
974 else {
975 /* not swapping this bone, however, if its 'parent' got swapped, unparent us from it
976 * as it will be facing in opposite direction
977 */
978 if ((parent) && (EBONE_VISIBLE(arm, parent) && EBONE_EDITABLE(parent))) {
979 ebo->parent = NULL;
980 ebo->flag &= ~BONE_CONNECTED;
981 }
982
983 /* get next bones
984 * - child will become new parent of next bone (not swapping occurred,
985 * so set to NULL to prevent infinite-loop)
986 */
987 child = NULL;
988 }
989
990 /* tag as done (to prevent double-swaps) */
991 ebo->flag |= BONE_TRANSFORM;
992 }
993 }
994 }
995
996 /* free chains */
997 BLI_freelistN(&chains);
998
999 /* clear temp flags */
1000 armature_clear_swap_done_flags(arm);
1001 armature_tag_unselect(arm);
1002
1003 /* note, notifier might evolve */
1004 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
1005 DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
1006 }
1007 MEM_freeN(objects);
1008
1009 return OPERATOR_FINISHED;
1010 }
1011
ARMATURE_OT_switch_direction(wmOperatorType * ot)1012 void ARMATURE_OT_switch_direction(wmOperatorType *ot)
1013 {
1014 /* identifiers */
1015 ot->name = "Switch Direction";
1016 ot->idname = "ARMATURE_OT_switch_direction";
1017 ot->description = "Change the direction that a chain of bones points in (head <-> tail swap)";
1018
1019 /* api callbacks */
1020 ot->exec = armature_switch_direction_exec;
1021 ot->poll = ED_operator_editarmature;
1022
1023 /* flags */
1024 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1025 }
1026
1027 /** \} */
1028
1029 /* -------------------------------------------------------------------- */
1030 /** \name Align Operator
1031 * \{ */
1032
1033 /* helper to fix a ebone position if its parent has moved due to alignment*/
fix_connected_bone(EditBone * ebone)1034 static void fix_connected_bone(EditBone *ebone)
1035 {
1036 float diff[3];
1037
1038 if (!(ebone->parent) || !(ebone->flag & BONE_CONNECTED) ||
1039 equals_v3v3(ebone->parent->tail, ebone->head)) {
1040 return;
1041 }
1042
1043 /* if the parent has moved we translate child's head and tail accordingly */
1044 sub_v3_v3v3(diff, ebone->parent->tail, ebone->head);
1045 add_v3_v3(ebone->head, diff);
1046 add_v3_v3(ebone->tail, diff);
1047 }
1048
1049 /* helper to recursively find chains of connected bones starting at ebone and fix their position */
fix_editbone_connected_children(ListBase * edbo,EditBone * ebone)1050 static void fix_editbone_connected_children(ListBase *edbo, EditBone *ebone)
1051 {
1052 EditBone *selbone;
1053
1054 for (selbone = edbo->first; selbone; selbone = selbone->next) {
1055 if ((selbone->parent) && (selbone->parent == ebone) && (selbone->flag & BONE_CONNECTED)) {
1056 fix_connected_bone(selbone);
1057 fix_editbone_connected_children(edbo, selbone);
1058 }
1059 }
1060 }
1061
bone_align_to_bone(ListBase * edbo,EditBone * selbone,EditBone * actbone)1062 static void bone_align_to_bone(ListBase *edbo, EditBone *selbone, EditBone *actbone)
1063 {
1064 float selboneaxis[3], actboneaxis[3], length;
1065
1066 sub_v3_v3v3(actboneaxis, actbone->tail, actbone->head);
1067 normalize_v3(actboneaxis);
1068
1069 sub_v3_v3v3(selboneaxis, selbone->tail, selbone->head);
1070 length = len_v3(selboneaxis);
1071
1072 mul_v3_fl(actboneaxis, length);
1073 add_v3_v3v3(selbone->tail, selbone->head, actboneaxis);
1074 selbone->roll = actbone->roll;
1075
1076 /* if the bone being aligned has connected descendants they must be moved
1077 * according to their parent new position, otherwise they would be left
1078 * in an inconsistent state: connected but away from the parent*/
1079 fix_editbone_connected_children(edbo, selbone);
1080 }
1081
armature_align_bones_exec(bContext * C,wmOperator * op)1082 static int armature_align_bones_exec(bContext *C, wmOperator *op)
1083 {
1084 Object *ob = CTX_data_edit_object(C);
1085 bArmature *arm = (bArmature *)ob->data;
1086 EditBone *actbone = CTX_data_active_bone(C);
1087 EditBone *actmirb = NULL;
1088 int num_selected_bones;
1089
1090 /* there must be an active bone */
1091 if (actbone == NULL) {
1092 BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
1093 return OPERATOR_CANCELLED;
1094 }
1095
1096 if (arm->flag & ARM_MIRROR_EDIT) {
1097 /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
1098 * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone
1099 * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
1100 * This is useful for arm-chains, for example parenting lower arm to upper arm
1101 * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
1102 * then just use actbone. Useful when doing upper arm to spine.
1103 */
1104 actmirb = ED_armature_ebone_get_mirrored(arm->edbo, actbone);
1105 if (actmirb == NULL) {
1106 actmirb = actbone;
1107 }
1108 }
1109
1110 /* if there is only 1 selected bone, we assume that that is the active bone,
1111 * since a user will need to have clicked on a bone (thus selecting it) to make it active
1112 */
1113 num_selected_bones = CTX_DATA_COUNT(C, selected_editable_bones);
1114 if (num_selected_bones <= 1) {
1115 /* When only the active bone is selected, and it has a parent,
1116 * align it to the parent, as that is the only possible outcome.
1117 */
1118 if (actbone->parent) {
1119 bone_align_to_bone(arm->edbo, actbone, actbone->parent);
1120
1121 if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent)) {
1122 bone_align_to_bone(arm->edbo, actmirb, actmirb->parent);
1123 }
1124
1125 BKE_reportf(op->reports, RPT_INFO, "Aligned bone '%s' to parent", actbone->name);
1126 }
1127 }
1128 else {
1129 /* Align 'selected' bones to the active one
1130 * - the context iterator contains both selected bones and their mirrored copies,
1131 * so we assume that unselected bones are mirrored copies of some selected bone
1132 * - since the active one (and/or its mirror) will also be selected, we also need
1133 * to check that we are not trying to operate on them, since such an operation
1134 * would cause errors
1135 */
1136
1137 /* align selected bones to the active one */
1138 CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones) {
1139 if (ELEM(ebone, actbone, actmirb) == 0) {
1140 if (ebone->flag & BONE_SELECTED) {
1141 bone_align_to_bone(arm->edbo, ebone, actbone);
1142 }
1143 else {
1144 bone_align_to_bone(arm->edbo, ebone, actmirb);
1145 }
1146 }
1147 }
1148 CTX_DATA_END;
1149
1150 BKE_reportf(
1151 op->reports, RPT_INFO, "%d bones aligned to bone '%s'", num_selected_bones, actbone->name);
1152 }
1153
1154 /* note, notifier might evolve */
1155 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
1156 DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
1157
1158 return OPERATOR_FINISHED;
1159 }
1160
ARMATURE_OT_align(wmOperatorType * ot)1161 void ARMATURE_OT_align(wmOperatorType *ot)
1162 {
1163 /* identifiers */
1164 ot->name = "Align Bones";
1165 ot->idname = "ARMATURE_OT_align";
1166 ot->description = "Align selected bones to the active bone (or to their parent)";
1167
1168 /* api callbacks */
1169 ot->exec = armature_align_bones_exec;
1170 ot->poll = ED_operator_editarmature;
1171
1172 /* flags */
1173 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1174 }
1175
1176 /** \} */
1177
1178 /* -------------------------------------------------------------------- */
1179 /** \name Split Operator
1180 * \{ */
1181
armature_split_exec(bContext * C,wmOperator * UNUSED (op))1182 static int armature_split_exec(bContext *C, wmOperator *UNUSED(op))
1183 {
1184 ViewLayer *view_layer = CTX_data_view_layer(C);
1185
1186 uint objects_len = 0;
1187 Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
1188 view_layer, CTX_wm_view3d(C), &objects_len);
1189 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1190 Object *ob = objects[ob_index];
1191 bArmature *arm = ob->data;
1192
1193 LISTBASE_FOREACH (EditBone *, bone, arm->edbo) {
1194 if (bone->parent && (bone->flag & BONE_SELECTED) != (bone->parent->flag & BONE_SELECTED)) {
1195 bone->parent = NULL;
1196 bone->flag &= ~BONE_CONNECTED;
1197 }
1198 }
1199 LISTBASE_FOREACH (EditBone *, bone, arm->edbo) {
1200 ED_armature_ebone_select_set(bone, (bone->flag & BONE_SELECTED) != 0);
1201 }
1202
1203 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
1204 DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
1205 }
1206
1207 MEM_freeN(objects);
1208 return OPERATOR_FINISHED;
1209 }
1210
ARMATURE_OT_split(wmOperatorType * ot)1211 void ARMATURE_OT_split(wmOperatorType *ot)
1212 {
1213 /* identifiers */
1214 ot->name = "Split";
1215 ot->idname = "ARMATURE_OT_split";
1216 ot->description = "Split off selected bones from connected unselected bones";
1217
1218 /* api callbacks */
1219 ot->exec = armature_split_exec;
1220 ot->poll = ED_operator_editarmature;
1221
1222 /* flags */
1223 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1224 }
1225
1226 /** \} */
1227
1228 /* -------------------------------------------------------------------- */
1229 /** \name Delete Operator
1230 * \{ */
1231
armature_delete_ebone_cb(const char * bone_name,void * arm_p)1232 static bool armature_delete_ebone_cb(const char *bone_name, void *arm_p)
1233 {
1234 bArmature *arm = arm_p;
1235 EditBone *ebone;
1236
1237 ebone = ED_armature_ebone_find_name(arm->edbo, bone_name);
1238 return (ebone && (ebone->flag & BONE_SELECTED) && (arm->layer & ebone->layer));
1239 }
1240
1241 /* previously delete_armature */
1242 /* only editmode! */
armature_delete_selected_exec(bContext * C,wmOperator * UNUSED (op))1243 static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
1244 {
1245 EditBone *curBone, *ebone_next;
1246 bool changed_multi = false;
1247
1248 /* cancel if nothing selected */
1249 if (CTX_DATA_COUNT(C, selected_bones) == 0) {
1250 return OPERATOR_CANCELLED;
1251 }
1252
1253 ViewLayer *view_layer = CTX_data_view_layer(C);
1254 uint objects_len = 0;
1255 Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
1256 view_layer, CTX_wm_view3d(C), &objects_len);
1257 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1258 Object *obedit = objects[ob_index];
1259 bArmature *arm = obedit->data;
1260 bool changed = false;
1261
1262 armature_select_mirrored(arm);
1263
1264 BKE_pose_channels_remove(obedit, armature_delete_ebone_cb, arm);
1265
1266 for (curBone = arm->edbo->first; curBone; curBone = ebone_next) {
1267 ebone_next = curBone->next;
1268 if (arm->layer & curBone->layer) {
1269 if (curBone->flag & BONE_SELECTED) {
1270 if (curBone == arm->act_edbone) {
1271 arm->act_edbone = NULL;
1272 }
1273 ED_armature_ebone_remove(arm, curBone);
1274 changed = true;
1275 }
1276 }
1277 }
1278
1279 if (changed) {
1280 changed_multi = true;
1281
1282 ED_armature_edit_sync_selection(arm->edbo);
1283 ED_armature_edit_refresh_layer_used(arm);
1284 BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose);
1285 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
1286 DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
1287 ED_outliner_select_sync_from_edit_bone_tag(C);
1288 }
1289 }
1290 MEM_freeN(objects);
1291
1292 if (!changed_multi) {
1293 return OPERATOR_CANCELLED;
1294 }
1295
1296 return OPERATOR_FINISHED;
1297 }
1298
ARMATURE_OT_delete(wmOperatorType * ot)1299 void ARMATURE_OT_delete(wmOperatorType *ot)
1300 {
1301 /* identifiers */
1302 ot->name = "Delete Selected Bone(s)";
1303 ot->idname = "ARMATURE_OT_delete";
1304 ot->description = "Remove selected bones from the armature";
1305
1306 /* api callbacks */
1307 ot->invoke = WM_operator_confirm;
1308 ot->exec = armature_delete_selected_exec;
1309 ot->poll = ED_operator_editarmature;
1310
1311 /* flags */
1312 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1313 }
1314
armature_dissolve_ebone_cb(const char * bone_name,void * arm_p)1315 static bool armature_dissolve_ebone_cb(const char *bone_name, void *arm_p)
1316 {
1317 bArmature *arm = arm_p;
1318 EditBone *ebone;
1319
1320 ebone = ED_armature_ebone_find_name(arm->edbo, bone_name);
1321 return (ebone && (ebone->flag & BONE_DONE));
1322 }
1323
armature_dissolve_selected_exec(bContext * C,wmOperator * UNUSED (op))1324 static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op))
1325 {
1326 ViewLayer *view_layer = CTX_data_view_layer(C);
1327 EditBone *ebone, *ebone_next;
1328 bool changed_multi = false;
1329
1330 uint objects_len = 0;
1331 Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
1332 view_layer, CTX_wm_view3d(C), &objects_len);
1333 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1334 Object *obedit = objects[ob_index];
1335 bArmature *arm = obedit->data;
1336 bool changed = false;
1337
1338 /* store for mirror */
1339 GHash *ebone_flag_orig = NULL;
1340 int ebone_num = 0;
1341
1342 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
1343 ebone->temp.p = NULL;
1344 ebone->flag &= ~BONE_DONE;
1345 ebone_num++;
1346 }
1347
1348 if (arm->flag & ARM_MIRROR_EDIT) {
1349 GHashIterator gh_iter;
1350
1351 ebone_flag_orig = BLI_ghash_ptr_new_ex(__func__, ebone_num);
1352 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
1353 union {
1354 int flag;
1355 void *p;
1356 } val = {0};
1357 val.flag = ebone->flag;
1358 BLI_ghash_insert(ebone_flag_orig, ebone, val.p);
1359 }
1360
1361 armature_select_mirrored_ex(arm, BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
1362
1363 GHASH_ITER (gh_iter, ebone_flag_orig) {
1364 union {
1365 int flag;
1366 void *p;
1367 } *val_p = (void *)BLI_ghashIterator_getValue_p(&gh_iter);
1368 ebone = BLI_ghashIterator_getKey(&gh_iter);
1369 val_p->flag = ebone->flag & ~val_p->flag;
1370 }
1371 }
1372
1373 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
1374 if (ebone->parent && ebone->flag & BONE_CONNECTED) {
1375 if (ebone->parent->temp.ebone == ebone->parent) {
1376 /* ignore */
1377 }
1378 else if (ebone->parent->temp.ebone) {
1379 /* set ignored */
1380 ebone->parent->temp.ebone = ebone->parent;
1381 }
1382 else {
1383 /* set child */
1384 ebone->parent->temp.ebone = ebone;
1385 }
1386 }
1387 }
1388
1389 /* cleanup multiple used bones */
1390 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
1391 if (ebone->temp.ebone == ebone) {
1392 ebone->temp.ebone = NULL;
1393 }
1394 }
1395
1396 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
1397 /* break connections for unseen bones */
1398 if (((arm->layer & ebone->layer) &&
1399 ((ED_armature_ebone_selectflag_get(ebone) & (BONE_TIPSEL | BONE_SELECTED)))) == 0) {
1400 ebone->temp.ebone = NULL;
1401 }
1402
1403 if (((arm->layer & ebone->layer) &&
1404 ((ED_armature_ebone_selectflag_get(ebone) & (BONE_ROOTSEL | BONE_SELECTED)))) == 0) {
1405 if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1406 ebone->parent->temp.ebone = NULL;
1407 }
1408 }
1409 }
1410
1411 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
1412
1413 if (ebone->parent && (ebone->parent->temp.ebone == ebone)) {
1414 ebone->flag |= BONE_DONE;
1415 }
1416 }
1417
1418 BKE_pose_channels_remove(obedit, armature_dissolve_ebone_cb, arm);
1419
1420 for (ebone = arm->edbo->first; ebone; ebone = ebone_next) {
1421 ebone_next = ebone->next;
1422
1423 if (ebone->flag & BONE_DONE) {
1424 copy_v3_v3(ebone->parent->tail, ebone->tail);
1425 ebone->parent->rad_tail = ebone->rad_tail;
1426 SET_FLAG_FROM_TEST(ebone->parent->flag, ebone->flag & BONE_TIPSEL, BONE_TIPSEL);
1427
1428 ED_armature_ebone_remove_ex(arm, ebone, false);
1429 changed = true;
1430 }
1431 }
1432
1433 if (changed) {
1434 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
1435 if (ebone->parent && ebone->parent->temp.ebone && (ebone->flag & BONE_CONNECTED)) {
1436 ebone->rad_head = ebone->parent->rad_tail;
1437 }
1438 }
1439
1440 if (arm->flag & ARM_MIRROR_EDIT) {
1441 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
1442 union {
1443 int flag;
1444 void *p;
1445 } *val_p = (void *)BLI_ghash_lookup_p(ebone_flag_orig, ebone);
1446 if (val_p && val_p->flag) {
1447 ebone->flag &= ~val_p->flag;
1448 }
1449 }
1450 }
1451 }
1452
1453 if (arm->flag & ARM_MIRROR_EDIT) {
1454 BLI_ghash_free(ebone_flag_orig, NULL, NULL);
1455 }
1456
1457 if (changed) {
1458 changed_multi = true;
1459 ED_armature_edit_sync_selection(arm->edbo);
1460 ED_armature_edit_refresh_layer_used(arm);
1461 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
1462 DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
1463 ED_outliner_select_sync_from_edit_bone_tag(C);
1464 }
1465 }
1466 MEM_freeN(objects);
1467
1468 if (!changed_multi) {
1469 return OPERATOR_CANCELLED;
1470 }
1471
1472 return OPERATOR_FINISHED;
1473 }
1474
ARMATURE_OT_dissolve(wmOperatorType * ot)1475 void ARMATURE_OT_dissolve(wmOperatorType *ot)
1476 {
1477 /* identifiers */
1478 ot->name = "Dissolve Selected Bone(s)";
1479 ot->idname = "ARMATURE_OT_dissolve";
1480 ot->description = "Dissolve selected bones from the armature";
1481
1482 /* api callbacks */
1483 ot->exec = armature_dissolve_selected_exec;
1484 ot->poll = ED_operator_editarmature;
1485
1486 /* flags */
1487 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1488 }
1489
1490 /** \} */
1491
1492 /* -------------------------------------------------------------------- */
1493 /** \name Hide Operator
1494 * \{ */
1495
armature_hide_exec(bContext * C,wmOperator * op)1496 static int armature_hide_exec(bContext *C, wmOperator *op)
1497 {
1498 ViewLayer *view_layer = CTX_data_view_layer(C);
1499 const int invert = RNA_boolean_get(op->ptr, "unselected") ? BONE_SELECTED : 0;
1500
1501 /* cancel if nothing selected */
1502 if (CTX_DATA_COUNT(C, selected_bones) == 0) {
1503 return OPERATOR_CANCELLED;
1504 }
1505
1506 uint objects_len = 0;
1507 Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
1508 view_layer, CTX_wm_view3d(C), &objects_len);
1509 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1510 Object *obedit = objects[ob_index];
1511 bArmature *arm = obedit->data;
1512 bool changed = false;
1513
1514 LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
1515 if (EBONE_VISIBLE(arm, ebone)) {
1516 if ((ebone->flag & BONE_SELECTED) != invert) {
1517 ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
1518 ebone->flag |= BONE_HIDDEN_A;
1519 changed = true;
1520 }
1521 }
1522 }
1523
1524 if (!changed) {
1525 continue;
1526 }
1527 ED_armature_edit_validate_active(arm);
1528 ED_armature_edit_sync_selection(arm->edbo);
1529
1530 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
1531 DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
1532 }
1533 MEM_freeN(objects);
1534 return OPERATOR_FINISHED;
1535 }
1536
ARMATURE_OT_hide(wmOperatorType * ot)1537 void ARMATURE_OT_hide(wmOperatorType *ot)
1538 {
1539 /* identifiers */
1540 ot->name = "Hide Selected";
1541 ot->idname = "ARMATURE_OT_hide";
1542 ot->description = "Tag selected bones to not be visible in Edit Mode";
1543
1544 /* api callbacks */
1545 ot->exec = armature_hide_exec;
1546 ot->poll = ED_operator_editarmature;
1547
1548 /* flags */
1549 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1550
1551 /* props */
1552 RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
1553 }
1554
1555 /** \} */
1556
1557 /* -------------------------------------------------------------------- */
1558 /** \name Reveal Operator
1559 * \{ */
1560
armature_reveal_exec(bContext * C,wmOperator * op)1561 static int armature_reveal_exec(bContext *C, wmOperator *op)
1562 {
1563 ViewLayer *view_layer = CTX_data_view_layer(C);
1564 const bool select = RNA_boolean_get(op->ptr, "select");
1565 uint objects_len = 0;
1566 Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
1567 view_layer, CTX_wm_view3d(C), &objects_len);
1568 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1569 Object *obedit = objects[ob_index];
1570 bArmature *arm = obedit->data;
1571 bool changed = false;
1572
1573 LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
1574 if (arm->layer & ebone->layer) {
1575 if (ebone->flag & BONE_HIDDEN_A) {
1576 if (!(ebone->flag & BONE_UNSELECTABLE)) {
1577 SET_FLAG_FROM_TEST(ebone->flag, select, (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL));
1578 }
1579 ebone->flag &= ~BONE_HIDDEN_A;
1580 changed = true;
1581 }
1582 }
1583 }
1584
1585 if (changed) {
1586 ED_armature_edit_validate_active(arm);
1587 ED_armature_edit_sync_selection(arm->edbo);
1588
1589 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
1590 DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
1591 }
1592 }
1593 MEM_freeN(objects);
1594 return OPERATOR_FINISHED;
1595 }
1596
ARMATURE_OT_reveal(wmOperatorType * ot)1597 void ARMATURE_OT_reveal(wmOperatorType *ot)
1598 {
1599 /* identifiers */
1600 ot->name = "Reveal Hidden";
1601 ot->idname = "ARMATURE_OT_reveal";
1602 ot->description = "Reveal all bones hidden in Edit Mode";
1603
1604 /* api callbacks */
1605 ot->exec = armature_reveal_exec;
1606 ot->poll = ED_operator_editarmature;
1607
1608 /* flags */
1609 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1610
1611 RNA_def_boolean(ot->srna, "select", true, "Select", "");
1612 }
1613
1614 /** \} */
1615