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