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  * API's and Operators for selecting armature bones in EditMode
19  */
20 
21 /** \file
22  * \ingroup edarmature
23  */
24 
25 #include "MEM_guardedalloc.h"
26 
27 #include "DNA_armature_types.h"
28 #include "DNA_object_types.h"
29 #include "DNA_scene_types.h"
30 
31 #include "BLI_blenlib.h"
32 #include "BLI_math.h"
33 #include "BLI_rect.h"
34 #include "BLI_string_utils.h"
35 
36 #include "BKE_action.h"
37 #include "BKE_armature.h"
38 #include "BKE_context.h"
39 #include "BKE_layer.h"
40 #include "BKE_object.h"
41 #include "BKE_report.h"
42 
43 #include "RNA_access.h"
44 #include "RNA_define.h"
45 
46 #include "WM_api.h"
47 #include "WM_types.h"
48 
49 #include "ED_armature.h"
50 #include "ED_object.h"
51 #include "ED_outliner.h"
52 #include "ED_screen.h"
53 #include "ED_select_utils.h"
54 #include "ED_view3d.h"
55 
56 #include "DEG_depsgraph.h"
57 
58 #include "armature_intern.h"
59 
60 /* utility macros for storing a temp int in the bone (selection flag) */
61 #define EBONE_PREV_FLAG_GET(ebone) ((void)0, (ebone)->temp.i)
62 #define EBONE_PREV_FLAG_SET(ebone, val) ((ebone)->temp.i = val)
63 
64 /* -------------------------------------------------------------------- */
65 /** \name Select Buffer Queries for PoseMode & EditMode
66  * \{ */
67 
ED_armature_base_and_ebone_from_select_buffer(Base ** bases,uint bases_len,int hit,EditBone ** r_ebone)68 Base *ED_armature_base_and_ebone_from_select_buffer(Base **bases,
69                                                     uint bases_len,
70                                                     int hit,
71                                                     EditBone **r_ebone)
72 {
73   const uint hit_object = hit & 0xFFFF;
74   Base *base = NULL;
75   EditBone *ebone = NULL;
76   /* TODO(campbell): optimize, eg: sort & binary search. */
77   for (uint base_index = 0; base_index < bases_len; base_index++) {
78     if (bases[base_index]->object->runtime.select_id == hit_object) {
79       base = bases[base_index];
80       break;
81     }
82   }
83   if (base != NULL) {
84     const uint hit_bone = (hit & ~BONESEL_ANY) >> 16;
85     bArmature *arm = base->object->data;
86     ebone = BLI_findlink(arm->edbo, hit_bone);
87   }
88   *r_ebone = ebone;
89   return base;
90 }
91 
ED_armature_object_and_ebone_from_select_buffer(Object ** objects,uint objects_len,int hit,EditBone ** r_ebone)92 Object *ED_armature_object_and_ebone_from_select_buffer(Object **objects,
93                                                         uint objects_len,
94                                                         int hit,
95                                                         EditBone **r_ebone)
96 {
97   const uint hit_object = hit & 0xFFFF;
98   Object *ob = NULL;
99   EditBone *ebone = NULL;
100   /* TODO(campbell): optimize, eg: sort & binary search. */
101   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
102     if (objects[ob_index]->runtime.select_id == hit_object) {
103       ob = objects[ob_index];
104       break;
105     }
106   }
107   if (ob != NULL) {
108     const uint hit_bone = (hit & ~BONESEL_ANY) >> 16;
109     bArmature *arm = ob->data;
110     ebone = BLI_findlink(arm->edbo, hit_bone);
111   }
112   *r_ebone = ebone;
113   return ob;
114 }
115 
ED_armature_base_and_pchan_from_select_buffer(Base ** bases,uint bases_len,int hit,bPoseChannel ** r_pchan)116 Base *ED_armature_base_and_pchan_from_select_buffer(Base **bases,
117                                                     uint bases_len,
118                                                     int hit,
119                                                     bPoseChannel **r_pchan)
120 {
121   const uint hit_object = hit & 0xFFFF;
122   Base *base = NULL;
123   bPoseChannel *pchan = NULL;
124   /* TODO(campbell): optimize, eg: sort & binary search. */
125   for (uint base_index = 0; base_index < bases_len; base_index++) {
126     if (bases[base_index]->object->runtime.select_id == hit_object) {
127       base = bases[base_index];
128       break;
129     }
130   }
131   if (base != NULL) {
132     if (base->object->pose != NULL) {
133       const uint hit_bone = (hit & ~BONESEL_ANY) >> 16;
134       /* pchan may be NULL. */
135       pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone);
136     }
137   }
138   *r_pchan = pchan;
139   return base;
140 }
141 
142 /* For callers that don't need the pose channel. */
ED_armature_base_and_bone_from_select_buffer(Base ** bases,uint bases_len,int hit,Bone ** r_bone)143 Base *ED_armature_base_and_bone_from_select_buffer(Base **bases,
144                                                    uint bases_len,
145                                                    int hit,
146                                                    Bone **r_bone)
147 {
148   bPoseChannel *pchan = NULL;
149   Base *base = ED_armature_base_and_pchan_from_select_buffer(bases, bases_len, hit, &pchan);
150   *r_bone = pchan ? pchan->bone : NULL;
151   return base;
152 }
153 
154 /** \} */
155 
156 /* -------------------------------------------------------------------- */
157 /** \name Cursor Pick from Select Buffer API
158  *
159  * Internal #ed_armature_pick_bone_from_selectbuffer_impl is exposed as:
160  * - #ED_armature_pick_ebone_from_selectbuffer
161  * - #ED_armature_pick_pchan_from_selectbuffer
162  * - #ED_armature_pick_bone_from_selectbuffer
163  * \{ */
164 
165 /* See if there are any selected bones in this buffer */
166 /* only bones from base are checked on */
ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode,Base ** bases,uint bases_len,const uint * buffer,short hits,bool findunsel,bool do_nearest,Base ** r_base)167 static void *ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode,
168                                                           Base **bases,
169                                                           uint bases_len,
170                                                           const uint *buffer,
171                                                           short hits,
172                                                           bool findunsel,
173                                                           bool do_nearest,
174                                                           Base **r_base)
175 {
176   bPoseChannel *pchan;
177   EditBone *ebone;
178   void *firstunSel = NULL, *firstSel = NULL, *data;
179   Base *firstunSel_base = NULL, *firstSel_base = NULL;
180   uint hitresult;
181   bool takeNext = false;
182   int minsel = 0xffffffff, minunsel = 0xffffffff;
183 
184   for (short i = 0; i < hits; i++) {
185     hitresult = buffer[3 + (i * 4)];
186 
187     if (hitresult & BONESEL_ANY) { /* to avoid including objects in selection */
188       Base *base = NULL;
189       bool sel;
190 
191       hitresult &= ~BONESEL_ANY;
192       /* Determine what the current bone is */
193       if (is_editmode == false) {
194         base = ED_armature_base_and_pchan_from_select_buffer(bases, bases_len, hitresult, &pchan);
195         if (pchan != NULL) {
196           if (findunsel) {
197             sel = (pchan->bone->flag & BONE_SELECTED);
198           }
199           else {
200             sel = !(pchan->bone->flag & BONE_SELECTED);
201           }
202 
203           data = pchan;
204         }
205         else {
206           data = NULL;
207           sel = 0;
208         }
209       }
210       else {
211         base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone);
212         if (findunsel) {
213           sel = (ebone->flag & BONE_SELECTED);
214         }
215         else {
216           sel = !(ebone->flag & BONE_SELECTED);
217         }
218 
219         data = ebone;
220       }
221 
222       if (data) {
223         if (sel) {
224           if (do_nearest) {
225             if (minsel > buffer[4 * i + 1]) {
226               firstSel = data;
227               firstSel_base = base;
228               minsel = buffer[4 * i + 1];
229             }
230           }
231           else {
232             if (!firstSel) {
233               firstSel = data;
234               firstSel_base = base;
235             }
236             takeNext = 1;
237           }
238         }
239         else {
240           if (do_nearest) {
241             if (minunsel > buffer[4 * i + 1]) {
242               firstunSel = data;
243               firstunSel_base = base;
244               minunsel = buffer[4 * i + 1];
245             }
246           }
247           else {
248             if (!firstunSel) {
249               firstunSel = data;
250               firstunSel_base = base;
251             }
252             if (takeNext) {
253               *r_base = base;
254               return data;
255             }
256           }
257         }
258       }
259     }
260   }
261 
262   if (firstunSel) {
263     *r_base = firstunSel_base;
264     return firstunSel;
265   }
266   *r_base = firstSel_base;
267   return firstSel;
268 }
269 
ED_armature_pick_ebone_from_selectbuffer(Base ** bases,uint bases_len,const uint * buffer,short hits,bool findunsel,bool do_nearest,Base ** r_base)270 EditBone *ED_armature_pick_ebone_from_selectbuffer(Base **bases,
271                                                    uint bases_len,
272                                                    const uint *buffer,
273                                                    short hits,
274                                                    bool findunsel,
275                                                    bool do_nearest,
276                                                    Base **r_base)
277 {
278   const bool is_editmode = true;
279   return ed_armature_pick_bone_from_selectbuffer_impl(
280       is_editmode, bases, bases_len, buffer, hits, findunsel, do_nearest, r_base);
281 }
282 
ED_armature_pick_pchan_from_selectbuffer(Base ** bases,uint bases_len,const uint * buffer,short hits,bool findunsel,bool do_nearest,Base ** r_base)283 bPoseChannel *ED_armature_pick_pchan_from_selectbuffer(Base **bases,
284                                                        uint bases_len,
285                                                        const uint *buffer,
286                                                        short hits,
287                                                        bool findunsel,
288                                                        bool do_nearest,
289                                                        Base **r_base)
290 {
291   const bool is_editmode = false;
292   return ed_armature_pick_bone_from_selectbuffer_impl(
293       is_editmode, bases, bases_len, buffer, hits, findunsel, do_nearest, r_base);
294 }
295 
ED_armature_pick_bone_from_selectbuffer(Base ** bases,uint bases_len,const uint * buffer,short hits,bool findunsel,bool do_nearest,Base ** r_base)296 Bone *ED_armature_pick_bone_from_selectbuffer(Base **bases,
297                                               uint bases_len,
298                                               const uint *buffer,
299                                               short hits,
300                                               bool findunsel,
301                                               bool do_nearest,
302                                               Base **r_base)
303 {
304   bPoseChannel *pchan = ED_armature_pick_pchan_from_selectbuffer(
305       bases, bases_len, buffer, hits, findunsel, do_nearest, r_base);
306   return pchan ? pchan->bone : NULL;
307 }
308 
309 /** \} */
310 
311 /* -------------------------------------------------------------------- */
312 /** \name Cursor Pick API
313  *
314  * Internal #ed_armature_pick_bone_impl is exposed as:
315  * - #ED_armature_pick_ebone
316  * - #ED_armature_pick_pchan
317  * - #ED_armature_pick_bone
318  * \{ */
319 
320 /**
321  * \param xy: Cursor coordinates (area space).
322  * \return An #EditBone when is_editmode, otherwise a #bPoseChannel.
323  * \note Only checks objects in the current mode (edit-mode or pose-mode).
324  */
ed_armature_pick_bone_impl(const bool is_editmode,bContext * C,const int xy[2],bool findunsel,Base ** r_base)325 static void *ed_armature_pick_bone_impl(
326     const bool is_editmode, bContext *C, const int xy[2], bool findunsel, Base **r_base)
327 {
328   Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
329   ViewContext vc;
330   rcti rect;
331   uint buffer[MAXPICKBUF];
332   short hits;
333 
334   ED_view3d_viewcontext_init(C, &vc, depsgraph);
335   BLI_assert((vc.obedit != NULL) == is_editmode);
336 
337   BLI_rcti_init_pt_radius(&rect, xy, 0);
338 
339   /* Don't use hits with this ID, (armature drawing uses this). */
340   const int select_id_ignore = -1;
341 
342   hits = view3d_opengl_select_with_id_filter(&vc,
343                                              buffer,
344                                              MAXPICKBUF,
345                                              &rect,
346                                              VIEW3D_SELECT_PICK_NEAREST,
347                                              VIEW3D_SELECT_FILTER_NOP,
348                                              select_id_ignore);
349 
350   *r_base = NULL;
351 
352   if (hits > 0) {
353     uint bases_len = 0;
354     Base **bases;
355 
356     if (vc.obedit != NULL) {
357       bases = BKE_view_layer_array_from_bases_in_mode(vc.view_layer,
358                                                       vc.v3d,
359                                                       &bases_len,
360                                                       {
361                                                           .object_mode = OB_MODE_EDIT,
362                                                       });
363     }
364     else {
365       bases = BKE_object_pose_base_array_get(vc.view_layer, vc.v3d, &bases_len);
366     }
367 
368     void *bone = ed_armature_pick_bone_from_selectbuffer_impl(
369         is_editmode, bases, bases_len, buffer, hits, findunsel, true, r_base);
370 
371     MEM_freeN(bases);
372 
373     return bone;
374   }
375   return NULL;
376 }
377 
ED_armature_pick_ebone(bContext * C,const int xy[2],bool findunsel,Base ** r_base)378 EditBone *ED_armature_pick_ebone(bContext *C, const int xy[2], bool findunsel, Base **r_base)
379 {
380   const bool is_editmode = true;
381   return ed_armature_pick_bone_impl(is_editmode, C, xy, findunsel, r_base);
382 }
383 
ED_armature_pick_pchan(bContext * C,const int xy[2],bool findunsel,Base ** r_base)384 bPoseChannel *ED_armature_pick_pchan(bContext *C, const int xy[2], bool findunsel, Base **r_base)
385 {
386   const bool is_editmode = false;
387   return ed_armature_pick_bone_impl(is_editmode, C, xy, findunsel, r_base);
388 }
389 
ED_armature_pick_bone(bContext * C,const int xy[2],bool findunsel,Base ** r_base)390 Bone *ED_armature_pick_bone(bContext *C, const int xy[2], bool findunsel, Base **r_base)
391 {
392   bPoseChannel *pchan = ED_armature_pick_pchan(C, xy, findunsel, r_base);
393   return pchan ? pchan->bone : NULL;
394 }
395 
396 /** \} */
397 
398 /* -------------------------------------------------------------------- */
399 /** \name Select Linked Implementation
400  *
401  * Shared logic for select linked all/pick.
402  *
403  * Use #BONE_DONE flag to select linked.
404  * \{ */
405 
406 /**
407  * \param all_forks: Control how chains are stepped over.
408  * true: select all connected bones traveling up & down forks.
409  * false: select all parents and all children, but not the children of the root bone.
410  */
armature_select_linked_impl(Object * ob,const bool select,const bool all_forks)411 static bool armature_select_linked_impl(Object *ob, const bool select, const bool all_forks)
412 {
413   bool changed = false;
414   bArmature *arm = ob->data;
415 
416   /* Implementation note, this flood-fills selected bones with the 'TOUCH' flag,
417    * even though this is a loop-within a loop, walking up the parent chain only touches new bones.
418    * Bones that have been touched are skipped, so the complexity is OK. */
419 
420   enum {
421     /* Bone has been walked over, its LINK value can be read. */
422     TOUCH = (1 << 0),
423     /* When TOUCH has been set, this flag can be checked to see if the bone is connected. */
424     LINK = (1 << 1),
425   };
426 
427 #define CHECK_PARENT(ebone) \
428   (((ebone)->flag & BONE_CONNECTED) && \
429    ((ebone)->parent ? EBONE_SELECTABLE(arm, (ebone)->parent) : false))
430 
431   LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
432     ebone->temp.i = 0;
433   }
434 
435   /* Select parents. */
436   LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
437     if (ebone_iter->temp.i & TOUCH) {
438       continue;
439     }
440     if ((ebone_iter->flag & BONE_DONE) == 0) {
441       continue;
442     }
443 
444     ebone_iter->temp.i |= TOUCH | LINK;
445 
446     /* We have an un-touched link. */
447     for (EditBone *ebone = ebone_iter; ebone; ebone = CHECK_PARENT(ebone) ? ebone->parent : NULL) {
448       ED_armature_ebone_select_set(ebone, select);
449       changed = true;
450 
451       if (all_forks) {
452         ebone->temp.i |= (TOUCH | LINK);
453       }
454       else {
455         ebone->temp.i |= TOUCH;
456       }
457       /* Don't walk onto links (messes up 'all_forks' logic). */
458       if (ebone->parent && ebone->parent->temp.i & LINK) {
459         break;
460       }
461     }
462   }
463 
464   /* Select children. */
465   LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
466     /* No need to 'touch' this bone as it won't be walked over when scanning up the chain. */
467     if (!CHECK_PARENT(ebone_iter)) {
468       continue;
469     }
470     if (ebone_iter->temp.i & TOUCH) {
471       continue;
472     }
473 
474     /* First check if we're marked. */
475     EditBone *ebone_touched_parent = NULL;
476     for (EditBone *ebone = ebone_iter; ebone; ebone = CHECK_PARENT(ebone) ? ebone->parent : NULL) {
477       if (ebone->temp.i & TOUCH) {
478         ebone_touched_parent = ebone;
479         break;
480       }
481       ebone->temp.i |= TOUCH;
482     }
483 
484     if ((ebone_touched_parent != NULL) && (ebone_touched_parent->temp.i & LINK)) {
485       for (EditBone *ebone = ebone_iter; ebone != ebone_touched_parent; ebone = ebone->parent) {
486         if ((ebone->temp.i & LINK) == 0) {
487           ebone->temp.i |= LINK;
488           ED_armature_ebone_select_set(ebone, select);
489           changed = true;
490         }
491       }
492     }
493   }
494 
495 #undef CHECK_PARENT
496 
497   if (changed) {
498     ED_armature_edit_sync_selection(arm->edbo);
499     DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
500     WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, ob);
501   }
502 
503   return changed;
504 }
505 
506 /** \} */
507 
508 /* -------------------------------------------------------------------- */
509 /** \name Select Linked Operator
510  * \{ */
511 
armature_select_linked_exec(bContext * C,wmOperator * op)512 static int armature_select_linked_exec(bContext *C, wmOperator *op)
513 {
514   const bool all_forks = RNA_boolean_get(op->ptr, "all_forks");
515 
516   bool changed_multi = false;
517   ViewLayer *view_layer = CTX_data_view_layer(C);
518   uint objects_len = 0;
519   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
520       view_layer, CTX_wm_view3d(C), &objects_len);
521   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
522     Object *ob = objects[ob_index];
523     bArmature *arm = ob->data;
524 
525     bool found = false;
526     LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
527       if (EBONE_VISIBLE(arm, ebone) &&
528           (ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL))) {
529         ebone->flag |= BONE_DONE;
530         found = true;
531       }
532       else {
533         ebone->flag &= ~BONE_DONE;
534       }
535     }
536 
537     if (found) {
538       if (armature_select_linked_impl(ob, true, all_forks)) {
539         changed_multi = true;
540       }
541     }
542   }
543   MEM_freeN(objects);
544 
545   if (changed_multi) {
546     ED_outliner_select_sync_from_edit_bone_tag(C);
547   }
548   return OPERATOR_FINISHED;
549 }
550 
ARMATURE_OT_select_linked(wmOperatorType * ot)551 void ARMATURE_OT_select_linked(wmOperatorType *ot)
552 {
553   /* identifiers */
554   ot->name = "Select Linked All";
555   ot->idname = "ARMATURE_OT_select_linked";
556   ot->description = "Select all bones linked by parent/child connections to the current selection";
557 
558   /* api callbacks */
559   ot->exec = armature_select_linked_exec;
560   ot->poll = ED_operator_editarmature;
561 
562   /* flags */
563   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
564 
565   /* Leave disabled by default as this matches pose mode. */
566   RNA_def_boolean(ot->srna, "all_forks", 0, "All Forks", "Follow forks in the parents chain");
567 }
568 
569 /** \} */
570 
571 /* -------------------------------------------------------------------- */
572 /** \name Select Linked (Cursor Pick) Operator
573  * \{ */
574 
armature_select_linked_pick_invoke(bContext * C,wmOperator * op,const wmEvent * event)575 static int armature_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
576 {
577   const bool select = !RNA_boolean_get(op->ptr, "deselect");
578   const bool all_forks = RNA_boolean_get(op->ptr, "all_forks");
579 
580   view3d_operator_needs_opengl(C);
581   BKE_object_update_select_id(CTX_data_main(C));
582 
583   Base *base = NULL;
584   EditBone *ebone_active = ED_armature_pick_ebone(C, event->mval, true, &base);
585 
586   if (ebone_active == NULL) {
587     return OPERATOR_CANCELLED;
588   }
589 
590   bArmature *arm = base->object->data;
591   if (!EBONE_SELECTABLE(arm, ebone_active)) {
592     return OPERATOR_CANCELLED;
593   }
594 
595   /* Initialize flags. */
596   LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
597     ebone->flag &= ~BONE_DONE;
598   }
599   ebone_active->flag |= BONE_DONE;
600 
601   if (armature_select_linked_impl(base->object, select, all_forks)) {
602     ED_outliner_select_sync_from_edit_bone_tag(C);
603   }
604 
605   return OPERATOR_FINISHED;
606 }
607 
armature_select_linked_pick_poll(bContext * C)608 static bool armature_select_linked_pick_poll(bContext *C)
609 {
610   return (ED_operator_view3d_active(C) && ED_operator_editarmature(C));
611 }
612 
ARMATURE_OT_select_linked_pick(wmOperatorType * ot)613 void ARMATURE_OT_select_linked_pick(wmOperatorType *ot)
614 {
615   /* identifiers */
616   ot->name = "Select Linked";
617   ot->idname = "ARMATURE_OT_select_linked_pick";
618   ot->description = "(De)select bones linked by parent/child connections under the mouse cursor";
619 
620   /* api callbacks */
621   /* leave 'exec' unset */
622   ot->invoke = armature_select_linked_pick_invoke;
623   ot->poll = armature_select_linked_pick_poll;
624 
625   /* flags */
626   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
627 
628   RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
629   /* Leave disabled by default as this matches pose mode. */
630   RNA_def_boolean(ot->srna, "all_forks", 0, "All Forks", "Follow forks in the parents chain");
631 }
632 
633 /** \} */
634 
635 /* -------------------------------------------------------------------- */
636 /** \name Select Buffer Queries EditMode
637  * \{ */
638 
639 /* utility function for get_nearest_editbonepoint */
selectbuffer_ret_hits_12(uint * UNUSED (buffer),const int hits12)640 static int selectbuffer_ret_hits_12(uint *UNUSED(buffer), const int hits12)
641 {
642   return hits12;
643 }
644 
selectbuffer_ret_hits_5(uint * buffer,const int hits12,const int hits5)645 static int selectbuffer_ret_hits_5(uint *buffer, const int hits12, const int hits5)
646 {
647   const int offs = 4 * hits12;
648   memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(uint));
649   return hits5;
650 }
651 
652 /* does bones and points */
653 /* note that BONE ROOT only gets drawn for root bones (or without IK) */
get_nearest_editbonepoint(ViewContext * vc,bool findunsel,bool use_cycle,Base ** r_base,int * r_selmask)654 static EditBone *get_nearest_editbonepoint(
655     ViewContext *vc, bool findunsel, bool use_cycle, Base **r_base, int *r_selmask)
656 {
657   uint buffer[MAXPICKBUF];
658   struct {
659     uint hitresult;
660     Base *base;
661     EditBone *ebone;
662   } *result = NULL,
663 
664     result_cycle = {.hitresult = -1, .base = NULL, .ebone = NULL},
665     result_bias = {.hitresult = -1, .base = NULL, .ebone = NULL};
666 
667   /* find the bone after the current active bone, so as to bump up its chances in selection.
668    * this way overlapping bones will cycle selection state as with objects. */
669   Object *obedit_orig = vc->obedit;
670   EditBone *ebone_active_orig = ((bArmature *)obedit_orig->data)->act_edbone;
671   if (ebone_active_orig == NULL) {
672     use_cycle = false;
673   }
674 
675   if (use_cycle) {
676     static int last_mval[2] = {-100, -100};
677     if ((len_manhattan_v2v2_int(vc->mval, last_mval) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) == 0) {
678       use_cycle = false;
679     }
680     copy_v2_v2_int(last_mval, vc->mval);
681   }
682 
683   const bool do_nearest = !(XRAY_ACTIVE(vc->v3d) || use_cycle);
684 
685   /* matching logic from 'mixed_bones_object_selectbuffer' */
686   int hits = 0;
687   /* Don't use hits with this ID, (armature drawing uses this). */
688   const int select_id_ignore = -1;
689 
690   /* we _must_ end cache before return, use 'goto cache_end' */
691   view3d_opengl_select_cache_begin();
692 
693   {
694     const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
695     const eV3DSelectObjectFilter select_filter = VIEW3D_SELECT_FILTER_NOP;
696 
697     rcti rect;
698     BLI_rcti_init_pt_radius(&rect, vc->mval, 12);
699     const int hits12 = view3d_opengl_select_with_id_filter(
700         vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter, select_id_ignore);
701 
702     if (hits12 == 1) {
703       hits = selectbuffer_ret_hits_12(buffer, hits12);
704       goto cache_end;
705     }
706     else if (hits12 > 0) {
707       int offs;
708 
709       offs = 4 * hits12;
710       BLI_rcti_init_pt_radius(&rect, vc->mval, 5);
711       const int hits5 = view3d_opengl_select_with_id_filter(vc,
712                                                             buffer + offs,
713                                                             MAXPICKBUF - offs,
714                                                             &rect,
715                                                             select_mode,
716                                                             select_filter,
717                                                             select_id_ignore);
718 
719       if (hits5 == 1) {
720         hits = selectbuffer_ret_hits_5(buffer, hits12, hits5);
721         goto cache_end;
722       }
723 
724       if (hits5 > 0) {
725         hits = selectbuffer_ret_hits_5(buffer, hits12, hits5);
726         goto cache_end;
727       }
728       else {
729         hits = selectbuffer_ret_hits_12(buffer, hits12);
730         goto cache_end;
731       }
732     }
733   }
734 
735 cache_end:
736   view3d_opengl_select_cache_end();
737 
738   uint bases_len;
739   Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
740       vc->view_layer, vc->v3d, &bases_len);
741 
742   /* See if there are any selected bones in this group */
743   if (hits > 0) {
744     if (hits == 1) {
745       result_bias.hitresult = buffer[3];
746       result_bias.base = ED_armature_base_and_ebone_from_select_buffer(
747           bases, bases_len, result_bias.hitresult, &result_bias.ebone);
748     }
749     else {
750       int bias_max = INT_MIN;
751 
752       /* Track Cycle Variables
753        * - Offset is always set to the active bone.
754        * - The object & bone indices subtracted by the 'offset.as_u32' value.
755        *   Unsigned subtraction wrapping means we always select the next bone in the cycle.
756        */
757       struct {
758         union {
759           uint32_t as_u32;
760           struct {
761 #ifdef __BIG_ENDIAN__
762             uint16_t ob;
763             uint16_t bone;
764 #else
765             uint16_t bone;
766             uint16_t ob;
767 #endif
768           };
769         } offset, test, best;
770       } cycle_order;
771 
772       if (use_cycle) {
773         bArmature *arm = obedit_orig->data;
774         int ob_index = obedit_orig->runtime.select_id & 0xFFFF;
775         int bone_index = BLI_findindex(arm->edbo, ebone_active_orig);
776         /* Offset from the current active bone, so we cycle onto the next. */
777         cycle_order.offset.ob = ob_index;
778         cycle_order.offset.bone = bone_index;
779         /* The value of the active bone (with offset subtracted, a signal to always overwrite). */
780         cycle_order.best.as_u32 = 0;
781       }
782 
783       for (int i = 0; i < hits; i++) {
784         const uint hitresult = buffer[3 + (i * 4)];
785 
786         Base *base = NULL;
787         EditBone *ebone;
788         base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone);
789         /* If this fails, selection code is setting the selection ID's incorrectly. */
790         BLI_assert(base && ebone);
791 
792         /* Prioritized selection. */
793         {
794           int bias;
795           /* clicks on bone points get advantage */
796           if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) {
797             /* but also the unselected one */
798             if (findunsel) {
799               if ((hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0) {
800                 bias = 4;
801               }
802               else if ((hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0) {
803                 bias = 4;
804               }
805               else {
806                 bias = 3;
807               }
808             }
809             else {
810               bias = 4;
811             }
812           }
813           else {
814             /* bone found */
815             if (findunsel) {
816               if ((ebone->flag & BONE_SELECTED) == 0) {
817                 bias = 2;
818               }
819               else {
820                 bias = 1;
821               }
822             }
823             else {
824               bias = 2;
825             }
826           }
827 
828           if (bias > bias_max) {
829             bias_max = bias;
830 
831             result_bias.hitresult = hitresult;
832             result_bias.base = base;
833             result_bias.ebone = ebone;
834           }
835         }
836 
837         /* Cycle selected items (objects & bones). */
838         if (use_cycle) {
839           cycle_order.test.ob = hitresult & 0xFFFF;
840           cycle_order.test.bone = (hitresult & ~BONESEL_ANY) >> 16;
841           if (ebone == ebone_active_orig) {
842             BLI_assert(cycle_order.test.ob == cycle_order.offset.ob);
843             BLI_assert(cycle_order.test.bone == cycle_order.offset.bone);
844           }
845           /* Subtraction as a single value is needed to support cycling through bones
846            * from multiple objects. So once the last bone is selected,
847            * the bits for the bone index wrap into the object,
848            * causing the next object to be stepped onto. */
849           cycle_order.test.as_u32 -= cycle_order.offset.as_u32;
850 
851           /* Even though this logic avoids stepping onto the active bone,
852            * always set the 'best' value for the first time.
853            * Otherwise ensure the value is the smallest it can be,
854            * relative to the active bone, as long as it's not the active bone. */
855           if ((cycle_order.best.as_u32 == 0) ||
856               (cycle_order.test.as_u32 && (cycle_order.test.as_u32 < cycle_order.best.as_u32))) {
857             cycle_order.best = cycle_order.test;
858             result_cycle.hitresult = hitresult;
859             result_cycle.base = base;
860             result_cycle.ebone = ebone;
861           }
862         }
863       }
864     }
865 
866     result = (use_cycle && result_cycle.ebone) ? &result_cycle : &result_bias;
867 
868     if (result->hitresult != -1) {
869       *r_base = result->base;
870 
871       *r_selmask = 0;
872       if (result->hitresult & BONESEL_ROOT) {
873         *r_selmask |= BONE_ROOTSEL;
874       }
875       if (result->hitresult & BONESEL_TIP) {
876         *r_selmask |= BONE_TIPSEL;
877       }
878       if (result->hitresult & BONESEL_BONE) {
879         *r_selmask |= BONE_SELECTED;
880       }
881       MEM_freeN(bases);
882       return result->ebone;
883     }
884   }
885   *r_selmask = 0;
886   *r_base = NULL;
887   MEM_freeN(bases);
888   return NULL;
889 }
890 
891 /** \} */
892 
893 /* -------------------------------------------------------------------- */
894 /** \name Select Utility Functions
895  * \{ */
896 
ED_armature_edit_deselect_all(Object * obedit)897 bool ED_armature_edit_deselect_all(Object *obedit)
898 {
899   bArmature *arm = obedit->data;
900   bool changed = false;
901   LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
902     if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
903       ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
904       changed = true;
905     }
906   }
907   return changed;
908 }
909 
ED_armature_edit_deselect_all_visible(Object * obedit)910 bool ED_armature_edit_deselect_all_visible(Object *obedit)
911 {
912   bArmature *arm = obedit->data;
913   bool changed = false;
914   LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
915     /* first and foremost, bone must be visible and selected */
916     if (EBONE_VISIBLE(arm, ebone)) {
917       if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
918         ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
919         changed = true;
920       }
921     }
922   }
923 
924   if (changed) {
925     ED_armature_edit_sync_selection(arm->edbo);
926   }
927   return changed;
928 }
929 
ED_armature_edit_deselect_all_multi_ex(struct Base ** bases,uint bases_len)930 bool ED_armature_edit_deselect_all_multi_ex(struct Base **bases, uint bases_len)
931 {
932   bool changed_multi = false;
933   for (uint base_index = 0; base_index < bases_len; base_index++) {
934     Object *obedit = bases[base_index]->object;
935     changed_multi |= ED_armature_edit_deselect_all(obedit);
936   }
937   return changed_multi;
938 }
939 
ED_armature_edit_deselect_all_visible_multi_ex(struct Base ** bases,uint bases_len)940 bool ED_armature_edit_deselect_all_visible_multi_ex(struct Base **bases, uint bases_len)
941 {
942   bool changed_multi = false;
943   for (uint base_index = 0; base_index < bases_len; base_index++) {
944     Object *obedit = bases[base_index]->object;
945     changed_multi |= ED_armature_edit_deselect_all_visible(obedit);
946   }
947   return changed_multi;
948 }
949 
ED_armature_edit_deselect_all_visible_multi(bContext * C)950 bool ED_armature_edit_deselect_all_visible_multi(bContext *C)
951 {
952   Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
953   ViewContext vc;
954   ED_view3d_viewcontext_init(C, &vc, depsgraph);
955   uint bases_len = 0;
956   Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
957       vc.view_layer, vc.v3d, &bases_len);
958   bool changed_multi = ED_armature_edit_deselect_all_multi_ex(bases, bases_len);
959   MEM_freeN(bases);
960   return changed_multi;
961 }
962 
963 /** \} */
964 
965 /* -------------------------------------------------------------------- */
966 /** \name Select Cursor Pick API
967  * \{ */
968 
969 /* context: editmode armature in view3d */
ED_armature_edit_select_pick(bContext * C,const int mval[2],bool extend,bool deselect,bool toggle)970 bool ED_armature_edit_select_pick(
971     bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
972 {
973   Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
974   ViewContext vc;
975   EditBone *nearBone = NULL;
976   int selmask;
977   Base *basact = NULL;
978 
979   ED_view3d_viewcontext_init(C, &vc, depsgraph);
980   vc.mval[0] = mval[0];
981   vc.mval[1] = mval[1];
982 
983   nearBone = get_nearest_editbonepoint(&vc, true, true, &basact, &selmask);
984   if (nearBone) {
985     ED_view3d_viewcontext_init_object(&vc, basact->object);
986     bArmature *arm = vc.obedit->data;
987 
988     if (!EBONE_SELECTABLE(arm, nearBone)) {
989       return false;
990     }
991 
992     if (!extend && !deselect && !toggle) {
993       uint bases_len = 0;
994       Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
995           vc.view_layer, vc.v3d, &bases_len);
996       ED_armature_edit_deselect_all_multi_ex(bases, bases_len);
997       MEM_freeN(bases);
998     }
999 
1000     /* by definition the non-root connected bones have no root point drawn,
1001      * so a root selection needs to be delivered to the parent tip */
1002 
1003     if (selmask & BONE_SELECTED) {
1004       if (nearBone->parent && (nearBone->flag & BONE_CONNECTED)) {
1005         /* click in a chain */
1006         if (extend) {
1007           /* select this bone */
1008           nearBone->flag |= BONE_TIPSEL;
1009           nearBone->parent->flag |= BONE_TIPSEL;
1010         }
1011         else if (deselect) {
1012           /* deselect this bone */
1013           nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
1014           /* only deselect parent tip if it is not selected */
1015           if (!(nearBone->parent->flag & BONE_SELECTED)) {
1016             nearBone->parent->flag &= ~BONE_TIPSEL;
1017           }
1018         }
1019         else if (toggle) {
1020           /* hold shift inverts this bone's selection */
1021           if (nearBone->flag & BONE_SELECTED) {
1022             /* deselect this bone */
1023             nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
1024             /* only deselect parent tip if it is not selected */
1025             if (!(nearBone->parent->flag & BONE_SELECTED)) {
1026               nearBone->parent->flag &= ~BONE_TIPSEL;
1027             }
1028           }
1029           else {
1030             /* select this bone */
1031             nearBone->flag |= BONE_TIPSEL;
1032             nearBone->parent->flag |= BONE_TIPSEL;
1033           }
1034         }
1035         else {
1036           /* select this bone */
1037           nearBone->flag |= BONE_TIPSEL;
1038           nearBone->parent->flag |= BONE_TIPSEL;
1039         }
1040       }
1041       else {
1042         if (extend) {
1043           nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
1044         }
1045         else if (deselect) {
1046           nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
1047         }
1048         else if (toggle) {
1049           /* hold shift inverts this bone's selection */
1050           if (nearBone->flag & BONE_SELECTED) {
1051             nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
1052           }
1053           else {
1054             nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
1055           }
1056         }
1057         else {
1058           nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
1059         }
1060       }
1061     }
1062     else {
1063       if (extend) {
1064         nearBone->flag |= selmask;
1065       }
1066       else if (deselect) {
1067         nearBone->flag &= ~selmask;
1068       }
1069       else if (toggle && (nearBone->flag & selmask)) {
1070         nearBone->flag &= ~selmask;
1071       }
1072       else {
1073         nearBone->flag |= selmask;
1074       }
1075     }
1076 
1077     ED_armature_edit_sync_selection(arm->edbo);
1078 
1079     /* then now check for active status */
1080     if (ED_armature_ebone_selectflag_get(nearBone)) {
1081       arm->act_edbone = nearBone;
1082     }
1083 
1084     if (vc.view_layer->basact != basact) {
1085       ED_object_base_activate(C, basact);
1086     }
1087 
1088     WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
1089     DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
1090     return true;
1091   }
1092 
1093   return false;
1094 }
1095 
1096 /** \} */
1097 
1098 /* -------------------------------------------------------------------- */
1099 /** \name Select Op From Tagged
1100  *
1101  * Implements #ED_armature_edit_select_op_from_tagged
1102  * \{ */
1103 
armature_edit_select_op_apply(bArmature * arm,EditBone * ebone,const eSelectOp sel_op,int is_ignore_flag,int is_inside_flag)1104 static bool armature_edit_select_op_apply(bArmature *arm,
1105                                           EditBone *ebone,
1106                                           const eSelectOp sel_op,
1107                                           int is_ignore_flag,
1108                                           int is_inside_flag)
1109 {
1110   BLI_assert(!(is_ignore_flag & ~(BONESEL_ROOT | BONESEL_TIP)));
1111   BLI_assert(!(is_inside_flag & ~(BONESEL_ROOT | BONESEL_TIP | BONESEL_BONE)));
1112   BLI_assert(EBONE_VISIBLE(arm, ebone));
1113   bool changed = false;
1114   bool is_point_done = false;
1115   int points_proj_tot = 0;
1116   BLI_assert(ebone->flag == ebone->temp.i);
1117   const int ebone_flag_prev = ebone->flag;
1118 
1119   if ((is_ignore_flag & BONE_ROOTSEL) == 0) {
1120     points_proj_tot++;
1121     const bool is_select = ebone->flag & BONE_ROOTSEL;
1122     const bool is_inside = is_inside_flag & BONESEL_ROOT;
1123     const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
1124     if (sel_op_result != -1) {
1125       if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
1126         SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_ROOTSEL);
1127       }
1128     }
1129     is_point_done |= is_inside;
1130   }
1131 
1132   if ((is_ignore_flag & BONE_TIPSEL) == 0) {
1133     points_proj_tot++;
1134     const bool is_select = ebone->flag & BONE_TIPSEL;
1135     const bool is_inside = is_inside_flag & BONESEL_TIP;
1136     const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
1137     if (sel_op_result != -1) {
1138       if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
1139         SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_TIPSEL);
1140       }
1141     }
1142     is_point_done |= is_inside;
1143   }
1144 
1145   /* if one of points selected, we skip the bone itself */
1146   if ((is_point_done == false) && (points_proj_tot == 2)) {
1147     const bool is_select = ebone->flag & BONE_SELECTED;
1148     {
1149       const bool is_inside = is_inside_flag & BONESEL_BONE;
1150       const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
1151       if (sel_op_result != -1) {
1152         if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
1153           SET_FLAG_FROM_TEST(
1154               ebone->flag, sel_op_result, BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
1155         }
1156       }
1157     }
1158 
1159     changed = true;
1160   }
1161   changed |= is_point_done;
1162 
1163   if (ebone_flag_prev != ebone->flag) {
1164     ebone->temp.i = ebone->flag;
1165     ebone->flag = ebone_flag_prev;
1166     ebone->flag = ebone_flag_prev | BONE_DONE;
1167     changed = true;
1168   }
1169 
1170   return changed;
1171 }
1172 
1173 /**
1174  * Perform a selection operation on elements which have been 'touched',
1175  * use for lasso & border select but can be used elsewhere too.
1176  *
1177  * Tagging is done via #EditBone.temp.i using: #BONESEL_ROOT, #BONESEL_TIP, #BONESEL_BONE
1178  * And optionally ignoring end-points using the #BONESEL_ROOT, #BONESEL_TIP right shifted 16 bits.
1179  * (used when the values are clipped outside the view).
1180  *
1181  * \param sel_op: #eSelectOp type.
1182  *
1183  * \note Visibility checks must be done by the caller.
1184  */
ED_armature_edit_select_op_from_tagged(bArmature * arm,const int sel_op)1185 bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
1186 {
1187   bool changed = false;
1188 
1189   /* Initialize flags. */
1190   {
1191     LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
1192 
1193       /* Flush the parent flag to this bone
1194        * so we don't need to check the parent when adjusting the selection. */
1195       if ((ebone->flag & BONE_CONNECTED) && ebone->parent) {
1196         if (ebone->parent->flag & BONE_TIPSEL) {
1197           ebone->flag |= BONE_ROOTSEL;
1198         }
1199         else {
1200           ebone->flag &= ~BONE_ROOTSEL;
1201         }
1202 
1203         /* Flush the 'temp.i' flag. */
1204         if (ebone->parent->temp.i & BONESEL_TIP) {
1205           ebone->temp.i |= BONESEL_ROOT;
1206         }
1207       }
1208       ebone->flag &= ~BONE_DONE;
1209     }
1210   }
1211 
1212   /* Apply selection from bone selection flags. */
1213   LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
1214     if (ebone->temp.i != 0) {
1215       int is_ignore_flag = ((ebone->temp.i << 16) & (BONESEL_ROOT | BONESEL_TIP));
1216       int is_inside_flag = (ebone->temp.i & (BONESEL_ROOT | BONESEL_TIP | BONESEL_BONE));
1217 
1218       /* Use as previous bone flag from now on. */
1219       ebone->temp.i = ebone->flag;
1220 
1221       /* When there is a partial selection without both endpoints, only select an endpoint. */
1222       if ((is_inside_flag & BONESEL_BONE) &&
1223           ELEM(is_inside_flag & (BONESEL_ROOT | BONESEL_TIP), BONESEL_ROOT, BONESEL_TIP)) {
1224         is_inside_flag &= ~BONESEL_BONE;
1225       }
1226 
1227       changed |= armature_edit_select_op_apply(arm, ebone, sel_op, is_ignore_flag, is_inside_flag);
1228     }
1229   }
1230 
1231   if (changed) {
1232     /* Cleanup flags. */
1233     LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
1234       if (ebone->flag & BONE_DONE) {
1235         SWAP(int, ebone->temp.i, ebone->flag);
1236         ebone->flag |= BONE_DONE;
1237         if ((ebone->flag & BONE_CONNECTED) && ebone->parent) {
1238           if ((ebone->parent->flag & BONE_DONE) == 0) {
1239             /* Checked below. */
1240             ebone->parent->temp.i = ebone->parent->flag;
1241           }
1242         }
1243       }
1244     }
1245 
1246     LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
1247       if (ebone->flag & BONE_DONE) {
1248         if ((ebone->flag & BONE_CONNECTED) && ebone->parent) {
1249           bool is_parent_tip_changed = (ebone->parent->flag & BONE_TIPSEL) !=
1250                                        (ebone->parent->temp.i & BONE_TIPSEL);
1251           if ((ebone->temp.i & BONE_ROOTSEL) == 0) {
1252             if ((ebone->flag & BONE_ROOTSEL) != 0) {
1253               ebone->parent->flag |= BONE_TIPSEL;
1254             }
1255           }
1256           else {
1257             if ((ebone->flag & BONE_ROOTSEL) == 0) {
1258               ebone->parent->flag &= ~BONE_TIPSEL;
1259             }
1260           }
1261 
1262           if (is_parent_tip_changed == false) {
1263             /* Keep tip selected if the parent remains selected. */
1264             if (ebone->parent->flag & BONE_SELECTED) {
1265               ebone->parent->flag |= BONE_TIPSEL;
1266             }
1267           }
1268         }
1269         ebone->flag &= ~BONE_DONE;
1270       }
1271     }
1272 
1273     ED_armature_edit_sync_selection(arm->edbo);
1274     ED_armature_edit_validate_active(arm);
1275   }
1276 
1277   return changed;
1278 }
1279 
1280 /** \} */
1281 
1282 /* -------------------------------------------------------------------- */
1283 /** \name (De)Select All Operator
1284  * \{ */
1285 
armature_de_select_all_exec(bContext * C,wmOperator * op)1286 static int armature_de_select_all_exec(bContext *C, wmOperator *op)
1287 {
1288   int action = RNA_enum_get(op->ptr, "action");
1289 
1290   if (action == SEL_TOGGLE) {
1291     /* Determine if there are any selected bones
1292      * And therefore whether we are selecting or deselecting */
1293     action = SEL_SELECT;
1294     CTX_DATA_BEGIN (C, EditBone *, ebone, visible_bones) {
1295       if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
1296         action = SEL_DESELECT;
1297         break;
1298       }
1299     }
1300     CTX_DATA_END;
1301   }
1302 
1303   /* Set the flags. */
1304   CTX_DATA_BEGIN (C, EditBone *, ebone, visible_bones) {
1305     /* ignore bone if selection can't change */
1306     switch (action) {
1307       case SEL_SELECT:
1308         if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
1309           ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
1310           if (ebone->parent) {
1311             ebone->parent->flag |= BONE_TIPSEL;
1312           }
1313         }
1314         break;
1315       case SEL_DESELECT:
1316         ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
1317         break;
1318       case SEL_INVERT:
1319         if (ebone->flag & BONE_SELECTED) {
1320           ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
1321         }
1322         else {
1323           if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
1324             ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
1325             if (ebone->parent) {
1326               ebone->parent->flag |= BONE_TIPSEL;
1327             }
1328           }
1329         }
1330         break;
1331     }
1332   }
1333   CTX_DATA_END;
1334 
1335   ED_outliner_select_sync_from_edit_bone_tag(C);
1336 
1337   WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
1338 
1339   /* Tagging only one object to refresh drawing. */
1340   Object *obedit = CTX_data_edit_object(C);
1341   DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT);
1342 
1343   return OPERATOR_FINISHED;
1344 }
1345 
ARMATURE_OT_select_all(wmOperatorType * ot)1346 void ARMATURE_OT_select_all(wmOperatorType *ot)
1347 {
1348   /* identifiers */
1349   ot->name = "(De)select All";
1350   ot->idname = "ARMATURE_OT_select_all";
1351   ot->description = "Toggle selection status of all bones";
1352 
1353   /* api callbacks */
1354   ot->exec = armature_de_select_all_exec;
1355   ot->poll = ED_operator_editarmature;
1356 
1357   /* flags */
1358   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1359 
1360   WM_operator_properties_select_all(ot);
1361 }
1362 
1363 /** \} */
1364 
1365 /* -------------------------------------------------------------------- */
1366 /** \name Select More/Less Implementation
1367  * \{ */
1368 
armature_select_more(bArmature * arm,EditBone * ebone)1369 static void armature_select_more(bArmature *arm, EditBone *ebone)
1370 {
1371   if ((EBONE_PREV_FLAG_GET(ebone) & (BONE_ROOTSEL | BONE_TIPSEL)) != 0) {
1372     if (EBONE_SELECTABLE(arm, ebone)) {
1373       ED_armature_ebone_select_set(ebone, true);
1374     }
1375   }
1376 
1377   if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1378     /* to parent */
1379     if ((EBONE_PREV_FLAG_GET(ebone) & BONE_ROOTSEL) != 0) {
1380       if (EBONE_SELECTABLE(arm, ebone->parent)) {
1381         ED_armature_ebone_selectflag_enable(ebone->parent,
1382                                             (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL));
1383       }
1384     }
1385 
1386     /* from parent (difference from select less) */
1387     if ((EBONE_PREV_FLAG_GET(ebone->parent) & BONE_TIPSEL) != 0) {
1388       if (EBONE_SELECTABLE(arm, ebone)) {
1389         ED_armature_ebone_selectflag_enable(ebone, (BONE_SELECTED | BONE_ROOTSEL));
1390       }
1391     }
1392   }
1393 }
1394 
armature_select_less(bArmature * UNUSED (arm),EditBone * ebone)1395 static void armature_select_less(bArmature *UNUSED(arm), EditBone *ebone)
1396 {
1397   if ((EBONE_PREV_FLAG_GET(ebone) & (BONE_ROOTSEL | BONE_TIPSEL)) !=
1398       (BONE_ROOTSEL | BONE_TIPSEL)) {
1399     ED_armature_ebone_select_set(ebone, false);
1400   }
1401 
1402   if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1403     /* to parent */
1404     if ((EBONE_PREV_FLAG_GET(ebone) & BONE_SELECTED) == 0) {
1405       ED_armature_ebone_selectflag_disable(ebone->parent, (BONE_SELECTED | BONE_TIPSEL));
1406     }
1407 
1408     /* from parent (difference from select more) */
1409     if ((EBONE_PREV_FLAG_GET(ebone->parent) & BONE_SELECTED) == 0) {
1410       ED_armature_ebone_selectflag_disable(ebone, (BONE_SELECTED | BONE_ROOTSEL));
1411     }
1412   }
1413 }
1414 
armature_select_more_less(Object * ob,bool more)1415 static void armature_select_more_less(Object *ob, bool more)
1416 {
1417   bArmature *arm = (bArmature *)ob->data;
1418   EditBone *ebone;
1419 
1420   /* XXX, eventually we shouldn't need this - campbell */
1421   ED_armature_edit_sync_selection(arm->edbo);
1422 
1423   /* count bones & store selection state */
1424   for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
1425     EBONE_PREV_FLAG_SET(ebone, ED_armature_ebone_selectflag_get(ebone));
1426   }
1427 
1428   /* do selection */
1429   for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
1430     if (EBONE_VISIBLE(arm, ebone)) {
1431       if (more) {
1432         armature_select_more(arm, ebone);
1433       }
1434       else {
1435         armature_select_less(arm, ebone);
1436       }
1437     }
1438   }
1439 
1440   for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
1441     if (EBONE_VISIBLE(arm, ebone)) {
1442       if (more == false) {
1443         if (ebone->flag & BONE_SELECTED) {
1444           ED_armature_ebone_select_set(ebone, true);
1445         }
1446       }
1447     }
1448     ebone->temp.p = NULL;
1449   }
1450 
1451   ED_armature_edit_sync_selection(arm->edbo);
1452 }
1453 
1454 /** \} */
1455 
1456 /* -------------------------------------------------------------------- */
1457 /** \name Select More Operator
1458  * \{ */
1459 
armature_de_select_more_exec(bContext * C,wmOperator * UNUSED (op))1460 static int armature_de_select_more_exec(bContext *C, wmOperator *UNUSED(op))
1461 {
1462   ViewLayer *view_layer = CTX_data_view_layer(C);
1463   uint objects_len = 0;
1464   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
1465       view_layer, CTX_wm_view3d(C), &objects_len);
1466   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1467     Object *ob = objects[ob_index];
1468     armature_select_more_less(ob, true);
1469     WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
1470     DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
1471   }
1472   MEM_freeN(objects);
1473 
1474   ED_outliner_select_sync_from_edit_bone_tag(C);
1475   return OPERATOR_FINISHED;
1476 }
1477 
ARMATURE_OT_select_more(wmOperatorType * ot)1478 void ARMATURE_OT_select_more(wmOperatorType *ot)
1479 {
1480   /* identifiers */
1481   ot->name = "Select More";
1482   ot->idname = "ARMATURE_OT_select_more";
1483   ot->description = "Select those bones connected to the initial selection";
1484 
1485   /* api callbacks */
1486   ot->exec = armature_de_select_more_exec;
1487   ot->poll = ED_operator_editarmature;
1488 
1489   /* flags */
1490   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1491 }
1492 
1493 /** \} */
1494 
1495 /* -------------------------------------------------------------------- */
1496 /** \name Select Less Operator
1497  * \{ */
1498 
armature_de_select_less_exec(bContext * C,wmOperator * UNUSED (op))1499 static int armature_de_select_less_exec(bContext *C, wmOperator *UNUSED(op))
1500 {
1501   ViewLayer *view_layer = CTX_data_view_layer(C);
1502   uint objects_len = 0;
1503   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
1504       view_layer, CTX_wm_view3d(C), &objects_len);
1505   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1506     Object *ob = objects[ob_index];
1507     armature_select_more_less(ob, false);
1508     WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
1509     DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
1510   }
1511   MEM_freeN(objects);
1512 
1513   ED_outliner_select_sync_from_edit_bone_tag(C);
1514   return OPERATOR_FINISHED;
1515 }
1516 
ARMATURE_OT_select_less(wmOperatorType * ot)1517 void ARMATURE_OT_select_less(wmOperatorType *ot)
1518 {
1519   /* identifiers */
1520   ot->name = "Select Less";
1521   ot->idname = "ARMATURE_OT_select_less";
1522   ot->description = "Deselect those bones at the boundary of each selection region";
1523 
1524   /* api callbacks */
1525   ot->exec = armature_de_select_less_exec;
1526   ot->poll = ED_operator_editarmature;
1527 
1528   /* flags */
1529   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1530 }
1531 
1532 /** \} */
1533 
1534 /* -------------------------------------------------------------------- */
1535 /** \name Select Similar
1536  * \{ */
1537 
1538 enum {
1539   SIMEDBONE_CHILDREN = 1,
1540   SIMEDBONE_CHILDREN_IMMEDIATE,
1541   SIMEDBONE_SIBLINGS,
1542   SIMEDBONE_LENGTH,
1543   SIMEDBONE_DIRECTION,
1544   SIMEDBONE_PREFIX,
1545   SIMEDBONE_SUFFIX,
1546   SIMEDBONE_LAYER,
1547   SIMEDBONE_GROUP,
1548   SIMEDBONE_SHAPE,
1549 };
1550 
1551 static const EnumPropertyItem prop_similar_types[] = {
1552     {SIMEDBONE_CHILDREN, "CHILDREN", 0, "Children", ""},
1553     {SIMEDBONE_CHILDREN_IMMEDIATE, "CHILDREN_IMMEDIATE", 0, "Immediate children", ""},
1554     {SIMEDBONE_SIBLINGS, "SIBLINGS", 0, "Siblings", ""},
1555     {SIMEDBONE_LENGTH, "LENGTH", 0, "Length", ""},
1556     {SIMEDBONE_DIRECTION, "DIRECTION", 0, "Direction (Y axis)", ""},
1557     {SIMEDBONE_PREFIX, "PREFIX", 0, "Prefix", ""},
1558     {SIMEDBONE_SUFFIX, "SUFFIX", 0, "Suffix", ""},
1559     {SIMEDBONE_LAYER, "LAYER", 0, "Layer", ""},
1560     {SIMEDBONE_GROUP, "GROUP", 0, "Group", ""},
1561     {SIMEDBONE_SHAPE, "SHAPE", 0, "Shape", ""},
1562     {0, NULL, 0, NULL, NULL},
1563 };
1564 
bone_length_squared_worldspace_get(Object * ob,EditBone * ebone)1565 static float bone_length_squared_worldspace_get(Object *ob, EditBone *ebone)
1566 {
1567   float v1[3], v2[3];
1568   mul_v3_mat3_m4v3(v1, ob->obmat, ebone->head);
1569   mul_v3_mat3_m4v3(v2, ob->obmat, ebone->tail);
1570   return len_squared_v3v3(v1, v2);
1571 }
1572 
select_similar_length(bContext * C,const float thresh)1573 static void select_similar_length(bContext *C, const float thresh)
1574 {
1575   ViewLayer *view_layer = CTX_data_view_layer(C);
1576   Object *ob_act = CTX_data_edit_object(C);
1577   EditBone *ebone_act = CTX_data_active_bone(C);
1578 
1579   /* Thresh is always relative to current length. */
1580   const float len = bone_length_squared_worldspace_get(ob_act, ebone_act);
1581   const float len_min = len / (1.0f + (thresh - FLT_EPSILON));
1582   const float len_max = len * (1.0f + (thresh + FLT_EPSILON));
1583 
1584   uint objects_len = 0;
1585   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
1586       view_layer, CTX_wm_view3d(C), &objects_len);
1587   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1588     Object *ob = objects[ob_index];
1589     bArmature *arm = ob->data;
1590     bool changed = false;
1591 
1592     LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
1593       if (EBONE_SELECTABLE(arm, ebone)) {
1594         const float len_iter = bone_length_squared_worldspace_get(ob, ebone);
1595         if ((len_iter > len_min) && (len_iter < len_max)) {
1596           ED_armature_ebone_select_set(ebone, true);
1597           changed = true;
1598         }
1599       }
1600     }
1601 
1602     if (changed) {
1603       WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
1604       DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
1605     }
1606   }
1607   MEM_freeN(objects);
1608 }
1609 
bone_direction_worldspace_get(Object * ob,EditBone * ebone,float * r_dir)1610 static void bone_direction_worldspace_get(Object *ob, EditBone *ebone, float *r_dir)
1611 {
1612   float v1[3], v2[3];
1613   copy_v3_v3(v1, ebone->head);
1614   copy_v3_v3(v2, ebone->tail);
1615 
1616   mul_m4_v3(ob->obmat, v1);
1617   mul_m4_v3(ob->obmat, v2);
1618 
1619   sub_v3_v3v3(r_dir, v1, v2);
1620   normalize_v3(r_dir);
1621 }
1622 
select_similar_direction(bContext * C,const float thresh)1623 static void select_similar_direction(bContext *C, const float thresh)
1624 {
1625   ViewLayer *view_layer = CTX_data_view_layer(C);
1626   Object *ob_act = CTX_data_edit_object(C);
1627   EditBone *ebone_act = CTX_data_active_bone(C);
1628 
1629   float dir_act[3];
1630   bone_direction_worldspace_get(ob_act, ebone_act, dir_act);
1631 
1632   uint objects_len = 0;
1633   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
1634       view_layer, CTX_wm_view3d(C), &objects_len);
1635   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1636     Object *ob = objects[ob_index];
1637     bArmature *arm = ob->data;
1638     bool changed = false;
1639 
1640     LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
1641       if (EBONE_SELECTABLE(arm, ebone)) {
1642         float dir[3];
1643         bone_direction_worldspace_get(ob, ebone, dir);
1644 
1645         if (angle_v3v3(dir_act, dir) / (float)M_PI < (thresh + FLT_EPSILON)) {
1646           ED_armature_ebone_select_set(ebone, true);
1647           changed = true;
1648         }
1649       }
1650     }
1651 
1652     if (changed) {
1653       WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
1654       DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
1655       DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
1656     }
1657   }
1658   MEM_freeN(objects);
1659 }
1660 
select_similar_layer(bContext * C)1661 static void select_similar_layer(bContext *C)
1662 {
1663   ViewLayer *view_layer = CTX_data_view_layer(C);
1664   EditBone *ebone_act = CTX_data_active_bone(C);
1665 
1666   uint objects_len = 0;
1667   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
1668       view_layer, CTX_wm_view3d(C), &objects_len);
1669   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1670     Object *ob = objects[ob_index];
1671     bArmature *arm = ob->data;
1672     bool changed = false;
1673 
1674     LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
1675       if (EBONE_SELECTABLE(arm, ebone)) {
1676         if (ebone->layer & ebone_act->layer) {
1677           ED_armature_ebone_select_set(ebone, true);
1678           changed = true;
1679         }
1680       }
1681     }
1682 
1683     if (changed) {
1684       WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
1685       DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
1686     }
1687   }
1688   MEM_freeN(objects);
1689 }
1690 
select_similar_prefix(bContext * C)1691 static void select_similar_prefix(bContext *C)
1692 {
1693   ViewLayer *view_layer = CTX_data_view_layer(C);
1694   EditBone *ebone_act = CTX_data_active_bone(C);
1695 
1696   char body_tmp[MAXBONENAME];
1697   char prefix_act[MAXBONENAME];
1698 
1699   BLI_string_split_prefix(ebone_act->name, prefix_act, body_tmp, sizeof(ebone_act->name));
1700 
1701   if (prefix_act[0] == '\0') {
1702     return;
1703   }
1704 
1705   uint objects_len = 0;
1706   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
1707       view_layer, CTX_wm_view3d(C), &objects_len);
1708   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1709     Object *ob = objects[ob_index];
1710     bArmature *arm = ob->data;
1711     bool changed = false;
1712 
1713     /* Find matches */
1714     LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
1715       if (EBONE_SELECTABLE(arm, ebone)) {
1716         char prefix_other[MAXBONENAME];
1717         BLI_string_split_prefix(ebone->name, prefix_other, body_tmp, sizeof(ebone->name));
1718         if (STREQ(prefix_act, prefix_other)) {
1719           ED_armature_ebone_select_set(ebone, true);
1720           changed = true;
1721         }
1722       }
1723     }
1724 
1725     if (changed) {
1726       WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
1727       DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
1728     }
1729   }
1730   MEM_freeN(objects);
1731 }
1732 
select_similar_suffix(bContext * C)1733 static void select_similar_suffix(bContext *C)
1734 {
1735   ViewLayer *view_layer = CTX_data_view_layer(C);
1736   EditBone *ebone_act = CTX_data_active_bone(C);
1737 
1738   char body_tmp[MAXBONENAME];
1739   char suffix_act[MAXBONENAME];
1740 
1741   BLI_string_split_suffix(ebone_act->name, body_tmp, suffix_act, sizeof(ebone_act->name));
1742 
1743   if (suffix_act[0] == '\0') {
1744     return;
1745   }
1746 
1747   uint objects_len = 0;
1748   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
1749       view_layer, CTX_wm_view3d(C), &objects_len);
1750   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1751     Object *ob = objects[ob_index];
1752     bArmature *arm = ob->data;
1753     bool changed = false;
1754 
1755     /* Find matches */
1756     LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
1757       if (EBONE_SELECTABLE(arm, ebone)) {
1758         char suffix_other[MAXBONENAME];
1759         BLI_string_split_suffix(ebone->name, body_tmp, suffix_other, sizeof(ebone->name));
1760         if (STREQ(suffix_act, suffix_other)) {
1761           ED_armature_ebone_select_set(ebone, true);
1762           changed = true;
1763         }
1764       }
1765     }
1766 
1767     if (changed) {
1768       WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
1769       DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
1770     }
1771   }
1772   MEM_freeN(objects);
1773 }
1774 
1775 /** Use for matching any pose channel data. */
select_similar_data_pchan(bContext * C,const size_t bytes_size,const int offset)1776 static void select_similar_data_pchan(bContext *C, const size_t bytes_size, const int offset)
1777 {
1778   Object *obedit = CTX_data_edit_object(C);
1779   bArmature *arm = obedit->data;
1780   EditBone *ebone_act = CTX_data_active_bone(C);
1781 
1782   const bPoseChannel *pchan_active = BKE_pose_channel_find_name(obedit->pose, ebone_act->name);
1783 
1784   /* This will mostly happen for corner cases where the user tried to access this
1785    * before having any valid pose data for the armature. */
1786   if (pchan_active == NULL) {
1787     return;
1788   }
1789 
1790   const char *data_active = (const char *)POINTER_OFFSET(pchan_active, offset);
1791   LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
1792     if (EBONE_SELECTABLE(arm, ebone)) {
1793       const bPoseChannel *pchan = BKE_pose_channel_find_name(obedit->pose, ebone->name);
1794       if (pchan) {
1795         const char *data_test = (const char *)POINTER_OFFSET(pchan, offset);
1796         if (memcmp(data_active, data_test, bytes_size) == 0) {
1797           ED_armature_ebone_select_set(ebone, true);
1798         }
1799       }
1800     }
1801   }
1802 
1803   WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
1804   DEG_id_tag_update(&obedit->id, ID_RECALC_COPY_ON_WRITE);
1805 }
1806 
is_ancestor(EditBone * bone,EditBone * ancestor)1807 static void is_ancestor(EditBone *bone, EditBone *ancestor)
1808 {
1809   if (bone->temp.ebone == ancestor || bone->temp.ebone == NULL) {
1810     return;
1811   }
1812 
1813   if (bone->temp.ebone->temp.ebone != NULL && bone->temp.ebone->temp.ebone != ancestor) {
1814     is_ancestor(bone->temp.ebone, ancestor);
1815   }
1816 
1817   bone->temp.ebone = bone->temp.ebone->temp.ebone;
1818 }
1819 
select_similar_children(bContext * C)1820 static void select_similar_children(bContext *C)
1821 {
1822   Object *obedit = CTX_data_edit_object(C);
1823   bArmature *arm = obedit->data;
1824   EditBone *ebone_act = CTX_data_active_bone(C);
1825 
1826   LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
1827     ebone_iter->temp.ebone = ebone_iter->parent;
1828   }
1829 
1830   LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
1831     is_ancestor(ebone_iter, ebone_act);
1832 
1833     if (ebone_iter->temp.ebone == ebone_act && EBONE_SELECTABLE(arm, ebone_iter)) {
1834       ED_armature_ebone_select_set(ebone_iter, true);
1835     }
1836   }
1837 
1838   WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
1839   DEG_id_tag_update(&obedit->id, ID_RECALC_COPY_ON_WRITE);
1840 }
1841 
select_similar_children_immediate(bContext * C)1842 static void select_similar_children_immediate(bContext *C)
1843 {
1844   Object *obedit = CTX_data_edit_object(C);
1845   bArmature *arm = obedit->data;
1846   EditBone *ebone_act = CTX_data_active_bone(C);
1847 
1848   LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
1849     if (ebone_iter->parent == ebone_act && EBONE_SELECTABLE(arm, ebone_iter)) {
1850       ED_armature_ebone_select_set(ebone_iter, true);
1851     }
1852   }
1853 
1854   WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
1855   DEG_id_tag_update(&obedit->id, ID_RECALC_COPY_ON_WRITE);
1856 }
1857 
select_similar_siblings(bContext * C)1858 static void select_similar_siblings(bContext *C)
1859 {
1860   Object *obedit = CTX_data_edit_object(C);
1861   bArmature *arm = obedit->data;
1862   EditBone *ebone_act = CTX_data_active_bone(C);
1863 
1864   if (ebone_act->parent == NULL) {
1865     return;
1866   }
1867 
1868   LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
1869     if (ebone_iter->parent == ebone_act->parent && EBONE_SELECTABLE(arm, ebone_iter)) {
1870       ED_armature_ebone_select_set(ebone_iter, true);
1871     }
1872   }
1873 
1874   WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
1875   DEG_id_tag_update(&obedit->id, ID_RECALC_COPY_ON_WRITE);
1876 }
1877 
armature_select_similar_exec(bContext * C,wmOperator * op)1878 static int armature_select_similar_exec(bContext *C, wmOperator *op)
1879 {
1880   /* Get props */
1881   int type = RNA_enum_get(op->ptr, "type");
1882   float thresh = RNA_float_get(op->ptr, "threshold");
1883 
1884   /* Check for active bone */
1885   if (CTX_data_active_bone(C) == NULL) {
1886     BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
1887     return OPERATOR_CANCELLED;
1888   }
1889 
1890 #define STRUCT_SIZE_AND_OFFSET(_struct, _member) \
1891   sizeof(((_struct *)NULL)->_member), offsetof(_struct, _member)
1892 
1893   switch (type) {
1894     case SIMEDBONE_CHILDREN:
1895       select_similar_children(C);
1896       break;
1897     case SIMEDBONE_CHILDREN_IMMEDIATE:
1898       select_similar_children_immediate(C);
1899       break;
1900     case SIMEDBONE_SIBLINGS:
1901       select_similar_siblings(C);
1902       break;
1903     case SIMEDBONE_LENGTH:
1904       select_similar_length(C, thresh);
1905       break;
1906     case SIMEDBONE_DIRECTION:
1907       select_similar_direction(C, thresh);
1908       break;
1909     case SIMEDBONE_PREFIX:
1910       select_similar_prefix(C);
1911       break;
1912     case SIMEDBONE_SUFFIX:
1913       select_similar_suffix(C);
1914       break;
1915     case SIMEDBONE_LAYER:
1916       select_similar_layer(C);
1917       break;
1918     case SIMEDBONE_GROUP:
1919       select_similar_data_pchan(C, STRUCT_SIZE_AND_OFFSET(bPoseChannel, agrp_index));
1920       break;
1921     case SIMEDBONE_SHAPE:
1922       select_similar_data_pchan(C, STRUCT_SIZE_AND_OFFSET(bPoseChannel, custom));
1923       break;
1924   }
1925 
1926 #undef STRUCT_SIZE_AND_OFFSET
1927 
1928   ED_outliner_select_sync_from_edit_bone_tag(C);
1929 
1930   return OPERATOR_FINISHED;
1931 }
1932 
ARMATURE_OT_select_similar(wmOperatorType * ot)1933 void ARMATURE_OT_select_similar(wmOperatorType *ot)
1934 {
1935   /* identifiers */
1936   ot->name = "Select Similar";
1937   ot->idname = "ARMATURE_OT_select_similar";
1938 
1939   /* callback functions */
1940   ot->invoke = WM_menu_invoke;
1941   ot->exec = armature_select_similar_exec;
1942   ot->poll = ED_operator_editarmature;
1943   ot->description = "Select similar bones by property types";
1944 
1945   /* flags */
1946   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1947 
1948   /* properties */
1949   ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMEDBONE_LENGTH, "Type", "");
1950   RNA_def_float(ot->srna, "threshold", 0.1f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
1951 }
1952 
1953 /** \} */
1954 
1955 /* -------------------------------------------------------------------- */
1956 /** \name Select Hierarchy Operator
1957  * \{ */
1958 
1959 /* No need to convert to multi-objects. Just like we keep the non-active bones
1960  * selected we then keep the non-active objects untouched (selected/unselected). */
armature_select_hierarchy_exec(bContext * C,wmOperator * op)1961 static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
1962 {
1963   Object *ob = CTX_data_edit_object(C);
1964   EditBone *ebone_active;
1965   int direction = RNA_enum_get(op->ptr, "direction");
1966   const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
1967   bool changed = false;
1968   bArmature *arm = (bArmature *)ob->data;
1969 
1970   ebone_active = arm->act_edbone;
1971   if (ebone_active == NULL) {
1972     return OPERATOR_CANCELLED;
1973   }
1974 
1975   if (direction == BONE_SELECT_PARENT) {
1976     if (ebone_active->parent) {
1977       EditBone *ebone_parent;
1978 
1979       ebone_parent = ebone_active->parent;
1980 
1981       if (EBONE_SELECTABLE(arm, ebone_parent)) {
1982         arm->act_edbone = ebone_parent;
1983 
1984         if (!add_to_sel) {
1985           ED_armature_ebone_select_set(ebone_active, false);
1986         }
1987         ED_armature_ebone_select_set(ebone_parent, true);
1988 
1989         changed = true;
1990       }
1991     }
1992   }
1993   else { /* BONE_SELECT_CHILD */
1994     EditBone *ebone_iter, *ebone_child = NULL;
1995     int pass;
1996 
1997     /* first pass, only connected bones (the logical direct child) */
1998     for (pass = 0; pass < 2 && (ebone_child == NULL); pass++) {
1999       for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
2000         /* possible we have multiple children, some invisible */
2001         if (EBONE_SELECTABLE(arm, ebone_iter)) {
2002           if (ebone_iter->parent == ebone_active) {
2003             if ((pass == 1) || (ebone_iter->flag & BONE_CONNECTED)) {
2004               ebone_child = ebone_iter;
2005               break;
2006             }
2007           }
2008         }
2009       }
2010     }
2011 
2012     if (ebone_child) {
2013       arm->act_edbone = ebone_child;
2014 
2015       if (!add_to_sel) {
2016         ED_armature_ebone_select_set(ebone_active, false);
2017       }
2018       ED_armature_ebone_select_set(ebone_child, true);
2019 
2020       changed = true;
2021     }
2022   }
2023 
2024   if (changed == false) {
2025     return OPERATOR_CANCELLED;
2026   }
2027 
2028   ED_outliner_select_sync_from_edit_bone_tag(C);
2029 
2030   ED_armature_edit_sync_selection(arm->edbo);
2031 
2032   WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
2033   DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
2034 
2035   return OPERATOR_FINISHED;
2036 }
2037 
ARMATURE_OT_select_hierarchy(wmOperatorType * ot)2038 void ARMATURE_OT_select_hierarchy(wmOperatorType *ot)
2039 {
2040   static const EnumPropertyItem direction_items[] = {
2041       {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
2042       {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
2043       {0, NULL, 0, NULL, NULL},
2044   };
2045 
2046   /* identifiers */
2047   ot->name = "Select Hierarchy";
2048   ot->idname = "ARMATURE_OT_select_hierarchy";
2049   ot->description = "Select immediate parent/children of selected bones";
2050 
2051   /* api callbacks */
2052   ot->exec = armature_select_hierarchy_exec;
2053   ot->poll = ED_operator_editarmature;
2054 
2055   /* flags */
2056   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2057 
2058   /* props */
2059   RNA_def_enum(ot->srna, "direction", direction_items, BONE_SELECT_PARENT, "Direction", "");
2060   RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
2061 }
2062 
2063 /** \} */
2064 
2065 /* -------------------------------------------------------------------- */
2066 /** \name Select Mirror Operator
2067  * \{ */
2068 
2069 /**
2070  * \note clone of #pose_select_mirror_exec keep in sync
2071  */
armature_select_mirror_exec(bContext * C,wmOperator * op)2072 static int armature_select_mirror_exec(bContext *C, wmOperator *op)
2073 {
2074   ViewLayer *view_layer = CTX_data_view_layer(C);
2075   const bool active_only = RNA_boolean_get(op->ptr, "only_active");
2076   const bool extend = RNA_boolean_get(op->ptr, "extend");
2077 
2078   uint objects_len = 0;
2079   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
2080       view_layer, CTX_wm_view3d(C), &objects_len);
2081   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2082     Object *ob = objects[ob_index];
2083     bArmature *arm = ob->data;
2084 
2085     EditBone *ebone, *ebone_mirror_act = NULL;
2086 
2087     for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
2088       const int flag = ED_armature_ebone_selectflag_get(ebone);
2089       EBONE_PREV_FLAG_SET(ebone, flag);
2090     }
2091 
2092     for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
2093       if (EBONE_SELECTABLE(arm, ebone)) {
2094         EditBone *ebone_mirror;
2095         int flag_new = extend ? EBONE_PREV_FLAG_GET(ebone) : 0;
2096 
2097         if ((ebone_mirror = ED_armature_ebone_get_mirrored(arm->edbo, ebone)) &&
2098             (EBONE_VISIBLE(arm, ebone_mirror))) {
2099           const int flag_mirror = EBONE_PREV_FLAG_GET(ebone_mirror);
2100           flag_new |= flag_mirror;
2101 
2102           if (ebone == arm->act_edbone) {
2103             ebone_mirror_act = ebone_mirror;
2104           }
2105 
2106           /* skip all but the active or its mirror */
2107           if (active_only && !ELEM(arm->act_edbone, ebone, ebone_mirror)) {
2108             continue;
2109           }
2110         }
2111 
2112         ED_armature_ebone_selectflag_set(ebone, flag_new);
2113       }
2114     }
2115 
2116     if (ebone_mirror_act) {
2117       arm->act_edbone = ebone_mirror_act;
2118     }
2119 
2120     ED_outliner_select_sync_from_edit_bone_tag(C);
2121 
2122     ED_armature_edit_sync_selection(arm->edbo);
2123 
2124     WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
2125     DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
2126   }
2127   MEM_freeN(objects);
2128 
2129   return OPERATOR_FINISHED;
2130 }
2131 
ARMATURE_OT_select_mirror(wmOperatorType * ot)2132 void ARMATURE_OT_select_mirror(wmOperatorType *ot)
2133 {
2134   /* identifiers */
2135   ot->name = "Flip Active/Selected Bone";
2136   ot->idname = "ARMATURE_OT_select_mirror";
2137   ot->description = "Mirror the bone selection";
2138 
2139   /* api callbacks */
2140   ot->exec = armature_select_mirror_exec;
2141   ot->poll = ED_operator_editarmature;
2142 
2143   /* flags */
2144   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2145 
2146   /* properties */
2147   RNA_def_boolean(
2148       ot->srna, "only_active", false, "Active Only", "Only operate on the active bone");
2149   RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
2150 }
2151 
2152 /** \} */
2153 
2154 /* -------------------------------------------------------------------- */
2155 /** \name Select Path Operator
2156  * \{ */
2157 
armature_shortest_path_select(bArmature * arm,EditBone * ebone_parent,EditBone * ebone_child,bool use_parent,bool is_test)2158 static bool armature_shortest_path_select(
2159     bArmature *arm, EditBone *ebone_parent, EditBone *ebone_child, bool use_parent, bool is_test)
2160 {
2161   do {
2162 
2163     if (!use_parent && (ebone_child == ebone_parent)) {
2164       break;
2165     }
2166 
2167     if (is_test) {
2168       if (!EBONE_SELECTABLE(arm, ebone_child)) {
2169         return false;
2170       }
2171     }
2172     else {
2173       ED_armature_ebone_selectflag_set(ebone_child, (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL));
2174     }
2175 
2176     if (ebone_child == ebone_parent) {
2177       break;
2178     }
2179 
2180     ebone_child = ebone_child->parent;
2181   } while (true);
2182 
2183   return true;
2184 }
2185 
armature_shortest_path_pick_invoke(bContext * C,wmOperator * op,const wmEvent * event)2186 static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2187 {
2188   Object *obedit = CTX_data_edit_object(C);
2189   bArmature *arm = obedit->data;
2190   EditBone *ebone_src, *ebone_dst;
2191   EditBone *ebone_isect_parent = NULL;
2192   EditBone *ebone_isect_child[2];
2193   bool changed;
2194   Base *base_dst = NULL;
2195 
2196   view3d_operator_needs_opengl(C);
2197   BKE_object_update_select_id(CTX_data_main(C));
2198 
2199   ebone_src = arm->act_edbone;
2200   ebone_dst = ED_armature_pick_ebone(C, event->mval, false, &base_dst);
2201 
2202   /* fallback to object selection */
2203   if (ELEM(NULL, ebone_src, ebone_dst) || (ebone_src == ebone_dst)) {
2204     return OPERATOR_PASS_THROUGH;
2205   }
2206 
2207   if (base_dst && base_dst->object != obedit) {
2208     /* Disconnected, ignore. */
2209     return OPERATOR_CANCELLED;
2210   }
2211 
2212   ebone_isect_child[0] = ebone_src;
2213   ebone_isect_child[1] = ebone_dst;
2214 
2215   /* ensure 'ebone_src' is the parent of 'ebone_dst', or set 'ebone_isect_parent' */
2216   if (ED_armature_ebone_is_child_recursive(ebone_src, ebone_dst)) {
2217     /* pass */
2218   }
2219   else if (ED_armature_ebone_is_child_recursive(ebone_dst, ebone_src)) {
2220     SWAP(EditBone *, ebone_src, ebone_dst);
2221   }
2222   else if ((ebone_isect_parent = ED_armature_ebone_find_shared_parent(ebone_isect_child, 2))) {
2223     /* pass */
2224   }
2225   else {
2226     /* disconnected bones */
2227     return OPERATOR_CANCELLED;
2228   }
2229 
2230   if (ebone_isect_parent) {
2231     if (armature_shortest_path_select(arm, ebone_isect_parent, ebone_src, false, true) &&
2232         armature_shortest_path_select(arm, ebone_isect_parent, ebone_dst, false, true)) {
2233       armature_shortest_path_select(arm, ebone_isect_parent, ebone_src, false, false);
2234       armature_shortest_path_select(arm, ebone_isect_parent, ebone_dst, false, false);
2235       changed = true;
2236     }
2237     else {
2238       /* unselectable */
2239       changed = false;
2240     }
2241   }
2242   else {
2243     if (armature_shortest_path_select(arm, ebone_src, ebone_dst, true, true)) {
2244       armature_shortest_path_select(arm, ebone_src, ebone_dst, true, false);
2245       changed = true;
2246     }
2247     else {
2248       /* unselectable */
2249       changed = false;
2250     }
2251   }
2252 
2253   if (changed) {
2254     arm->act_edbone = ebone_dst;
2255     ED_outliner_select_sync_from_edit_bone_tag(C);
2256     ED_armature_edit_sync_selection(arm->edbo);
2257     WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
2258     DEG_id_tag_update(&obedit->id, ID_RECALC_COPY_ON_WRITE);
2259 
2260     return OPERATOR_FINISHED;
2261   }
2262 
2263   BKE_report(op->reports, RPT_WARNING, "Unselectable bone in chain");
2264   return OPERATOR_CANCELLED;
2265 }
2266 
ARMATURE_OT_shortest_path_pick(wmOperatorType * ot)2267 void ARMATURE_OT_shortest_path_pick(wmOperatorType *ot)
2268 {
2269   /* identifiers */
2270   ot->name = "Pick Shortest Path";
2271   ot->idname = "ARMATURE_OT_shortest_path_pick";
2272   ot->description = "Select shortest path between two bones";
2273 
2274   /* api callbacks */
2275   ot->invoke = armature_shortest_path_pick_invoke;
2276   ot->poll = ED_operator_editarmature;
2277 
2278   /* flags */
2279   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2280 }
2281 
2282 /** \} */
2283