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