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