Blender  V2.93
view3d_select.c
Go to the documentation of this file.
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) 2008 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include <float.h>
25 #include <math.h>
26 #include <stdio.h>
27 #include <string.h>
28 
29 #include "DNA_action_types.h"
30 #include "DNA_armature_types.h"
31 #include "DNA_curve_types.h"
32 #include "DNA_gpencil_types.h"
33 #include "DNA_mesh_types.h"
34 #include "DNA_meshdata_types.h"
35 #include "DNA_meta_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_scene_types.h"
38 #include "DNA_tracking_types.h"
39 
40 #include "MEM_guardedalloc.h"
41 
42 #include "BLI_array.h"
43 #include "BLI_bitmap.h"
44 #include "BLI_lasso_2d.h"
45 #include "BLI_linklist.h"
46 #include "BLI_listbase.h"
47 #include "BLI_math.h"
48 #include "BLI_rect.h"
49 #include "BLI_string.h"
50 #include "BLI_utildefines.h"
51 
52 #ifdef __BIG_ENDIAN__
53 # include "BLI_endian_switch.h"
54 #endif
55 
56 /* vertex box select */
57 #include "BKE_global.h"
58 #include "BKE_main.h"
59 #include "IMB_imbuf.h"
60 #include "IMB_imbuf_types.h"
61 
62 #include "BKE_armature.h"
63 #include "BKE_context.h"
64 #include "BKE_curve.h"
65 #include "BKE_editmesh.h"
66 #include "BKE_layer.h"
67 #include "BKE_mball.h"
68 #include "BKE_mesh.h"
69 #include "BKE_object.h"
70 #include "BKE_paint.h"
71 #include "BKE_scene.h"
72 #include "BKE_tracking.h"
73 #include "BKE_workspace.h"
74 
75 #include "DEG_depsgraph.h"
76 
77 #include "WM_api.h"
78 #include "WM_toolsystem.h"
79 #include "WM_types.h"
80 
81 #include "RNA_access.h"
82 #include "RNA_define.h"
83 #include "RNA_enum_types.h"
84 
85 #include "ED_armature.h"
86 #include "ED_curve.h"
87 #include "ED_gpencil.h"
88 #include "ED_lattice.h"
89 #include "ED_mball.h"
90 #include "ED_mesh.h"
91 #include "ED_object.h"
92 #include "ED_outliner.h"
93 #include "ED_particle.h"
94 #include "ED_screen.h"
95 #include "ED_sculpt.h"
96 #include "ED_select_utils.h"
97 
98 #include "UI_interface.h"
99 #include "UI_resources.h"
100 
101 #include "GPU_matrix.h"
102 
103 #include "DEG_depsgraph.h"
104 #include "DEG_depsgraph_query.h"
105 
106 #include "DRW_engine.h"
107 #include "DRW_select_buffer.h"
108 
109 #include "view3d_intern.h" /* own include */
110 
111 // #include "PIL_time_utildefines.h"
112 
113 /* -------------------------------------------------------------------- */
118 {
119  return 75.0f * U.pixelsize;
120 }
121 
122 /* TODO: should return whether there is valid context to continue */
124 {
125  memset(vc, 0, sizeof(ViewContext));
126  vc->C = C;
127  vc->region = CTX_wm_region(C);
128  vc->bmain = CTX_data_main(C);
129  vc->depsgraph = depsgraph;
130  vc->scene = CTX_data_scene(C);
132  vc->v3d = CTX_wm_view3d(C);
133  vc->win = CTX_wm_window(C);
134  vc->rv3d = CTX_wm_region_view3d(C);
137 }
138 
140 {
141  vc->obact = obact;
142  if (vc->obedit) {
144  vc->obedit = obact;
145  if (vc->em) {
147  }
148  }
149 }
150 
153 /* -------------------------------------------------------------------- */
157 static bool object_deselect_all_visible(ViewLayer *view_layer, View3D *v3d)
158 {
159  bool changed = false;
160  LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
161  if (base->flag & BASE_SELECTED) {
162  if (BASE_SELECTABLE(v3d, base)) {
164  changed = true;
165  }
166  }
167  }
168  return changed;
169 }
170 
171 /* deselect all except b */
172 static bool object_deselect_all_except(ViewLayer *view_layer, Base *b)
173 {
174  bool changed = false;
175  LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
176  if (base->flag & BASE_SELECTED) {
177  if (b != base) {
179  changed = true;
180  }
181  }
182  }
183  return changed;
184 }
185 
188 /* -------------------------------------------------------------------- */
201 };
202 
203 static void editselect_buf_cache_init(ViewContext *vc, short select_mode)
204 {
205  if (vc->obedit) {
206  uint bases_len = 0;
208  vc->view_layer, vc->v3d, &bases_len);
209 
210  DRW_select_buffer_context_create(bases, bases_len, select_mode);
211  MEM_freeN(bases);
212  }
213  else {
214  /* Use for paint modes, currently only a single object at a time. */
215  if (vc->obact) {
216  Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact);
217  DRW_select_buffer_context_create(&base, 1, select_mode);
218  }
219  }
220 }
221 
223 {
225 }
226 
227 static void editselect_buf_cache_free_voidp(void *esel_voidp)
228 {
229  editselect_buf_cache_free(esel_voidp);
230  MEM_freeN(esel_voidp);
231 }
232 
234  ViewContext *vc,
235  short select_mode)
236 {
237  struct EditSelectBuf_Cache *esel = MEM_callocN(sizeof(*esel), __func__);
238  wm_userdata->data = esel;
240  wm_userdata->use_free = true;
241  editselect_buf_cache_init(vc, select_mode);
242 }
243 
246 /* -------------------------------------------------------------------- */
252  Object *ob,
253  BMEditMesh *em,
254  const eSelectOp sel_op)
255 {
256  BMVert *eve;
257  BMIter iter;
258  bool changed = false;
259 
260  const BLI_bitmap *select_bitmap = esel->select_bitmap;
262  if (index == 0) {
263  return false;
264  }
265 
266  index -= 1;
267  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
268  if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
269  const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
270  const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
271  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
272  if (sel_op_result != -1) {
273  BM_vert_select_set(em->bm, eve, sel_op_result);
274  changed = true;
275  }
276  }
277  index++;
278  }
279  return changed;
280 }
281 
284  Object *ob,
285  BMEditMesh *em,
286  const eSelectOp sel_op)
287 {
288  BMEdge *eed;
289  BMIter iter;
290  bool changed = false;
291 
292  const BLI_bitmap *select_bitmap = esel->select_bitmap;
294  if (index == 0) {
295  return false;
296  }
297 
298  index -= 1;
299  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
300  if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
301  const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
302  const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
303  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
304  if (sel_op_result != -1) {
305  BM_edge_select_set(em->bm, eed, sel_op_result);
306  changed = true;
307  }
308  }
309  index++;
310  }
311  return changed;
312 }
313 
316  Object *ob,
317  BMEditMesh *em,
318  const eSelectOp sel_op)
319 {
320  BMFace *efa;
321  BMIter iter;
322  bool changed = false;
323 
324  const BLI_bitmap *select_bitmap = esel->select_bitmap;
326  if (index == 0) {
327  return false;
328  }
329 
330  index -= 1;
331  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
332  if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
333  const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
334  const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
335  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
336  if (sel_op_result != -1) {
337  BM_face_select_set(em->bm, efa, sel_op_result);
338  changed = true;
339  }
340  }
341  index++;
342  }
343  return changed;
344 }
345 
346 /* object mode, edbm_ prefix is confusing here, rename? */
348  struct EditSelectBuf_Cache *esel,
349  const eSelectOp sel_op)
350 {
351  MVert *mv = me->mvert;
352  uint index;
353  bool changed = false;
354 
355  const BLI_bitmap *select_bitmap = esel->select_bitmap;
356 
357  if (mv) {
358  for (index = 0; index < me->totvert; index++, mv++) {
359  if (!(mv->flag & ME_HIDE)) {
360  const bool is_select = mv->flag & SELECT;
361  const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
362  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
363  if (sel_op_result != -1) {
364  SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT);
365  changed = true;
366  }
367  }
368  }
369  }
370  return changed;
371 }
372 
373 /* object mode, edbm_ prefix is confusing here, rename? */
375  struct EditSelectBuf_Cache *esel,
376  const eSelectOp sel_op)
377 {
378  MPoly *mpoly = me->mpoly;
379  uint index;
380  bool changed = false;
381 
382  const BLI_bitmap *select_bitmap = esel->select_bitmap;
383 
384  if (mpoly) {
385  for (index = 0; index < me->totpoly; index++, mpoly++) {
386  if (!(mpoly->flag & ME_HIDE)) {
387  const bool is_select = mpoly->flag & ME_FACE_SEL;
388  const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
389  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
390  if (sel_op_result != -1) {
391  SET_FLAG_FROM_TEST(mpoly->flag, sel_op_result, ME_FACE_SEL);
392  changed = true;
393  }
394  }
395  }
396  }
397  return changed;
398 }
399 
402 /* -------------------------------------------------------------------- */
406 typedef struct LassoSelectUserData {
408  const rcti *rect;
409  const rctf *rect_fl;
411  const int (*mcoords)[2];
415 
416  /* runtime */
417  int pass;
418  bool is_done;
421 
423  ViewContext *vc,
424  const rcti *rect,
425  const int (*mcoords)[2],
426  const int mcoords_len,
427  const eSelectOp sel_op)
428 {
429  r_data->vc = vc;
430 
431  r_data->rect = rect;
432  r_data->rect_fl = &r_data->_rect_fl;
433  BLI_rctf_rcti_copy(&r_data->_rect_fl, rect);
434 
435  r_data->mcoords = mcoords;
436  r_data->mcoords_len = mcoords_len;
437  r_data->sel_op = sel_op;
438  /* SELECT by default, but can be changed if needed (only few cases use and respect this). */
439  r_data->select_flag = SELECT;
440 
441  /* runtime */
442  r_data->pass = 0;
443  r_data->is_done = false;
444  r_data->is_changed = false;
445 }
446 
448 {
450 
452  return 0;
453  }
454 
455  if (ob) {
456  if (ob->mode & OB_MODE_EDIT) {
457  if (ob->type == OB_FONT) {
458  return 0;
459  }
460  }
461  else {
464  return 0;
465  }
466  }
467  }
468 
469  return 1;
470 }
471 
472 /* helper also for box_select */
473 static bool edge_fully_inside_rect(const rctf *rect, const float v1[2], const float v2[2])
474 {
475  return BLI_rctf_isect_pt_v(rect, v1) && BLI_rctf_isect_pt_v(rect, v2);
476 }
477 
478 static bool edge_inside_rect(const rctf *rect, const float v1[2], const float v2[2])
479 {
480  int d1, d2, d3, d4;
481 
482  /* check points in rect */
483  if (edge_fully_inside_rect(rect, v1, v2)) {
484  return 1;
485  }
486 
487  /* check points completely out rect */
488  if (v1[0] < rect->xmin && v2[0] < rect->xmin) {
489  return 0;
490  }
491  if (v1[0] > rect->xmax && v2[0] > rect->xmax) {
492  return 0;
493  }
494  if (v1[1] < rect->ymin && v2[1] < rect->ymin) {
495  return 0;
496  }
497  if (v1[1] > rect->ymax && v2[1] > rect->ymax) {
498  return 0;
499  }
500 
501  /* simple check lines intersecting. */
502  d1 = (v1[1] - v2[1]) * (v1[0] - rect->xmin) + (v2[0] - v1[0]) * (v1[1] - rect->ymin);
503  d2 = (v1[1] - v2[1]) * (v1[0] - rect->xmin) + (v2[0] - v1[0]) * (v1[1] - rect->ymax);
504  d3 = (v1[1] - v2[1]) * (v1[0] - rect->xmax) + (v2[0] - v1[0]) * (v1[1] - rect->ymax);
505  d4 = (v1[1] - v2[1]) * (v1[0] - rect->xmax) + (v2[0] - v1[0]) * (v1[1] - rect->ymin);
506 
507  if (d1 < 0 && d2 < 0 && d3 < 0 && d4 < 0) {
508  return 0;
509  }
510  if (d1 > 0 && d2 > 0 && d3 > 0 && d4 > 0) {
511  return 0;
512  }
513 
514  return 1;
515 }
516 
517 static void do_lasso_select_pose__do_tag(void *userData,
518  struct bPoseChannel *pchan,
519  const float screen_co_a[2],
520  const float screen_co_b[2])
521 {
522  LassoSelectUserData *data = userData;
523  bArmature *arm = data->vc->obact->data;
524 
525  if (PBONE_SELECTABLE(arm, pchan->bone)) {
526  bool is_point_done = false;
527  int points_proj_tot = 0;
528 
529  /* project head location to screenspace */
530  if (screen_co_a[0] != IS_CLIPPED) {
531  points_proj_tot++;
532  if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) &&
534  data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) {
535  is_point_done = true;
536  }
537  }
538 
539  /* project tail location to screenspace */
540  if (screen_co_b[0] != IS_CLIPPED) {
541  points_proj_tot++;
542  if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) &&
544  data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) {
545  is_point_done = true;
546  }
547  }
548 
549  /* if one of points selected, we skip the bone itself */
550  if ((is_point_done == true) || ((is_point_done == false) && (points_proj_tot == 2) &&
552  data->mcoords_len,
553  UNPACK2(screen_co_a),
554  UNPACK2(screen_co_b),
555  INT_MAX))) {
556  pchan->bone->flag |= BONE_DONE;
557  }
558  data->is_changed |= is_point_done;
559  }
560 }
562  Object *ob,
563  const int mcoords[][2],
564  const int mcoords_len)
565 {
566  ViewContext vc_tmp;
568  rcti rect;
569 
570  if ((ob->type != OB_ARMATURE) || (ob->pose == NULL)) {
571  return;
572  }
573 
574  vc_tmp = *vc;
575  vc_tmp.obact = ob;
576 
577  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
578 
579  view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, 0);
580 
581  ED_view3d_init_mats_rv3d(vc_tmp.obact, vc->rv3d);
582 
584 }
585 
587  const int mcoords[][2],
588  const int mcoords_len,
589  const eSelectOp sel_op)
590 {
591  View3D *v3d = vc->v3d;
592  Base *base;
593 
594  bool changed = false;
595  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
596  changed |= object_deselect_all_visible(vc->view_layer, vc->v3d);
597  }
598 
599  for (base = vc->view_layer->object_bases.first; base; base = base->next) {
600  if (BASE_SELECTABLE(v3d, base)) { /* Use this to avoid unnecessary lasso look-ups. */
601  const bool is_select = base->flag & BASE_SELECTED;
602  const bool is_inside = ((ED_view3d_project_base(vc->region, base) == V3D_PROJ_RET_OK) &&
604  mcoords, mcoords_len, base->sx, base->sy, IS_CLIPPED));
605  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
606  if (sel_op_result != -1) {
607  ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT);
608  changed = true;
609  }
610  }
611  }
612 
613  if (changed) {
616  }
617  return changed;
618 }
619 
624 {
625  Base **bases = NULL;
626  BLI_array_declare(bases);
628  Object *ob_iter = base_iter->object;
629  bArmature *arm = ob_iter->data;
630  LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_iter->pose->chanbase) {
631  Bone *bone = pchan->bone;
632  bone->flag &= ~BONE_DONE;
633  }
634  arm->id.tag |= LIB_TAG_DOIT;
635  ob_iter->id.tag &= ~LIB_TAG_DOIT;
636  BLI_array_append(bases, base_iter);
637  }
639  *r_bases_len = BLI_array_len(bases);
640  return bases;
641 }
642 
643 static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const eSelectOp sel_op)
644 {
645  bool changed_multi = false;
646 
647  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
648  for (int i = 0; i < bases_len; i++) {
649  Base *base_iter = bases[i];
650  Object *ob_iter = base_iter->object;
651  if (ED_pose_deselect_all(ob_iter, SEL_DESELECT, false)) {
653  changed_multi = true;
654  }
655  }
656  }
657 
658  for (int i = 0; i < bases_len; i++) {
659  Base *base_iter = bases[i];
660  Object *ob_iter = base_iter->object;
661  bArmature *arm = ob_iter->data;
662 
663  /* Don't handle twice. */
664  if (arm->id.tag & LIB_TAG_DOIT) {
665  arm->id.tag &= ~LIB_TAG_DOIT;
666  }
667  else {
668  continue;
669  }
670 
671  bool changed = true;
672  LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_iter->pose->chanbase) {
673  Bone *bone = pchan->bone;
674  if ((bone->flag & BONE_UNSELECTABLE) == 0) {
675  const bool is_select = bone->flag & BONE_SELECTED;
676  const bool is_inside = bone->flag & BONE_DONE;
677  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
678  if (sel_op_result != -1) {
679  SET_FLAG_FROM_TEST(bone->flag, sel_op_result, BONE_SELECTED);
680  if (sel_op_result == 0) {
681  if (arm->act_bone == bone) {
682  arm->act_bone = NULL;
683  }
684  }
685  changed = true;
686  }
687  }
688  }
689  if (changed) {
691  changed_multi = true;
692  }
693  }
694  return changed_multi;
695 }
696 
698  const int mcoords[][2],
699  const int mcoords_len,
700  const eSelectOp sel_op)
701 {
702  uint bases_len;
703  Base **bases = do_pose_tag_select_op_prepare(vc, &bases_len);
704 
705  for (int i = 0; i < bases_len; i++) {
706  Base *base_iter = bases[i];
707  Object *ob_iter = base_iter->object;
708  do_lasso_tag_pose(vc, ob_iter, mcoords, mcoords_len);
709  }
710 
711  const bool changed_multi = do_pose_tag_select_op_exec(bases, bases_len, sel_op);
712  if (changed_multi) {
715  }
716 
717  MEM_freeN(bases);
718  return changed_multi;
719 }
720 
721 static void do_lasso_select_mesh__doSelectVert(void *userData,
722  BMVert *eve,
723  const float screen_co[2],
724  int UNUSED(index))
725 {
726  LassoSelectUserData *data = userData;
727  const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
728  const bool is_inside =
729  (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
731  data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
732  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
733  if (sel_op_result != -1) {
734  BM_vert_select_set(data->vc->em->bm, eve, sel_op_result);
735  data->is_changed = true;
736  }
737 }
742 };
744  BMEdge *eed,
745  const float screen_co_a[2],
746  const float screen_co_b[2],
747  int index)
748 {
749  struct LassoSelectUserData_ForMeshEdge *data_for_edge = user_data;
750  LassoSelectUserData *data = data_for_edge->data;
751  bool is_visible = true;
752  if (data_for_edge->backbuf_offset) {
753  uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1;
754  is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx);
755  }
756 
757  const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
758  const bool is_inside =
759  (is_visible && edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) &&
761  data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), IS_CLIPPED) &&
763  data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), IS_CLIPPED));
764  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
765  if (sel_op_result != -1) {
766  BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
767  data->is_done = true;
768  data->is_changed = true;
769  }
770 }
772  BMEdge *eed,
773  const float screen_co_a[2],
774  const float screen_co_b[2],
775  int index)
776 {
777  struct LassoSelectUserData_ForMeshEdge *data_for_edge = user_data;
778  LassoSelectUserData *data = data_for_edge->data;
779  bool is_visible = true;
780  if (data_for_edge->backbuf_offset) {
781  uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1;
782  is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx);
783  }
784 
785  const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
786  const bool is_inside = (is_visible && BLI_lasso_is_edge_inside(data->mcoords,
787  data->mcoords_len,
788  UNPACK2(screen_co_a),
789  UNPACK2(screen_co_b),
790  IS_CLIPPED));
791  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
792  if (sel_op_result != -1) {
793  BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
794  data->is_changed = true;
795  }
796 }
797 
798 static void do_lasso_select_mesh__doSelectFace(void *userData,
799  BMFace *efa,
800  const float screen_co[2],
801  int UNUSED(index))
802 {
803  LassoSelectUserData *data = userData;
804  const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
805  const bool is_inside =
806  (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
808  data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
809  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
810  if (sel_op_result != -1) {
811  BM_face_select_set(data->vc->em->bm, efa, sel_op_result);
812  data->is_changed = true;
813  }
814 }
815 
817  wmGenericUserData *wm_userdata,
818  const int mcoords[][2],
819  const int mcoords_len,
820  const eSelectOp sel_op)
821 {
823  ToolSettings *ts = vc->scene->toolsettings;
824  rcti rect;
825 
826  /* set editmesh */
828 
829  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
830 
831  view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
832 
833  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
834  if (vc->em->bm->totvertsel) {
836  data.is_changed = true;
837  }
838  }
839 
840  /* for non zbuf projections, don't change the GL state */
842 
844 
845  const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d);
846 
847  struct EditSelectBuf_Cache *esel = wm_userdata->data;
848  if (use_zbuf) {
849  if (wm_userdata->data == NULL) {
851  esel = wm_userdata->data;
853  vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL);
854  }
855  }
856 
857  if (ts->selectmode & SCE_SELECT_VERTEX) {
858  if (use_zbuf) {
860  esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
861  }
862  else {
865  }
866  }
867  if (ts->selectmode & SCE_SELECT_EDGE) {
868  /* Does both use_zbuf and non-use_zbuf versions (need screen cos for both) */
869  struct LassoSelectUserData_ForMeshEdge data_for_edge = {
870  .data = &data,
871  .esel = use_zbuf ? esel : NULL,
872  .backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem(
873  vc->depsgraph, vc->obedit, SCE_SELECT_EDGE) :
874  0,
875  };
876 
877  const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR |
878  (use_zbuf ? 0 : V3D_PROJ_TEST_CLIP_BB);
880  vc, do_lasso_select_mesh__doSelectEdge_pass0, &data_for_edge, clip_flag);
881  if (data.is_done == false) {
883  vc, do_lasso_select_mesh__doSelectEdge_pass1, &data_for_edge, clip_flag);
884  }
885  }
886 
887  if (ts->selectmode & SCE_SELECT_FACE) {
888  if (use_zbuf) {
890  esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
891  }
892  else {
895  }
896  }
897 
898  if (data.is_changed) {
900  }
901  return data.is_changed;
902 }
903 
904 static void do_lasso_select_curve__doSelect(void *userData,
905  Nurb *UNUSED(nu),
906  BPoint *bp,
907  BezTriple *bezt,
908  int beztindex,
909  bool handles_visible,
910  const float screen_co[2])
911 {
912  LassoSelectUserData *data = userData;
913 
915  data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED);
916  if (bp) {
917  const bool is_select = bp->f1 & SELECT;
918  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
919  if (sel_op_result != -1) {
920  SET_FLAG_FROM_TEST(bp->f1, sel_op_result, data->select_flag);
921  data->is_changed = true;
922  }
923  }
924  else {
925  if (!handles_visible) {
926  /* can only be (beztindex == 1) here since handles are hidden */
927  const bool is_select = bezt->f2 & SELECT;
928  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
929  if (sel_op_result != -1) {
930  SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, data->select_flag);
931  }
932  bezt->f1 = bezt->f3 = bezt->f2;
933  data->is_changed = true;
934  }
935  else {
936  uint8_t *flag_p = (&bezt->f1) + beztindex;
937  const bool is_select = *flag_p & SELECT;
938  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
939  if (sel_op_result != -1) {
940  SET_FLAG_FROM_TEST(*flag_p, sel_op_result, data->select_flag);
941  data->is_changed = true;
942  }
943  }
944  }
945 }
946 
948  const int mcoords[][2],
949  const int mcoords_len,
950  const eSelectOp sel_op)
951 {
952  const bool deselect_all = (sel_op == SEL_OP_SET);
954  rcti rect;
955 
956  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
957 
958  view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
959 
960  Curve *curve = (Curve *)vc->obedit->data;
962 
963  /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */
964  if (deselect_all) {
966  data.select_flag = BEZT_FLAG_TEMP_TAG;
967  }
968 
969  ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
971 
972  /* Deselect items that were not added to selection (indicated by temp flag). */
973  if (deselect_all) {
975  }
976 
977  if (data.is_changed) {
979  }
980  return data.is_changed;
981 }
982 
983 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const float screen_co[2])
984 {
985  LassoSelectUserData *data = userData;
986  const bool is_select = bp->f1 & SELECT;
987  const bool is_inside =
988  (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
990  data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
991  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
992  if (sel_op_result != -1) {
993  SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT);
994  data->is_changed = true;
995  }
996 }
998  const int mcoords[][2],
999  const int mcoords_len,
1000  const eSelectOp sel_op)
1001 {
1003  rcti rect;
1004 
1005  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
1006 
1007  view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
1008 
1009  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
1010  data.is_changed |= ED_lattice_flags_set(vc->obedit, 0);
1011  }
1012 
1013  ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1016  return data.is_changed;
1017 }
1018 
1019 static void do_lasso_select_armature__doSelectBone(void *userData,
1020  EditBone *ebone,
1021  const float screen_co_a[2],
1022  const float screen_co_b[2])
1023 {
1024  LassoSelectUserData *data = userData;
1025  bArmature *arm = data->vc->obedit->data;
1026  if (EBONE_VISIBLE(arm, ebone)) {
1027  int is_ignore_flag = 0;
1028  int is_inside_flag = 0;
1029 
1030  if (screen_co_a[0] != IS_CLIPPED) {
1031  if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) &&
1033  data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) {
1034  is_inside_flag |= BONESEL_ROOT;
1035  }
1036  }
1037  else {
1038  is_ignore_flag |= BONESEL_ROOT;
1039  }
1040 
1041  if (screen_co_b[0] != IS_CLIPPED) {
1042  if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) &&
1044  data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) {
1045  is_inside_flag |= BONESEL_TIP;
1046  }
1047  }
1048  else {
1049  is_ignore_flag |= BONESEL_TIP;
1050  }
1051 
1052  if (is_ignore_flag == 0) {
1053  if (is_inside_flag == (BONE_ROOTSEL | BONE_TIPSEL) ||
1054  BLI_lasso_is_edge_inside(data->mcoords,
1055  data->mcoords_len,
1056  UNPACK2(screen_co_a),
1057  UNPACK2(screen_co_b),
1058  INT_MAX)) {
1059  is_inside_flag |= BONESEL_BONE;
1060  }
1061  }
1062 
1063  ebone->temp.i = is_inside_flag | (is_ignore_flag >> 16);
1064  }
1065 }
1066 
1068  const int mcoords[][2],
1069  const int mcoords_len,
1070  const eSelectOp sel_op)
1071 {
1073  rcti rect;
1074 
1075  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
1076 
1077  view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
1078 
1079  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
1081  }
1082 
1083  bArmature *arm = vc->obedit->data;
1084 
1086 
1088 
1091 
1092  data.is_changed |= ED_armature_edit_select_op_from_tagged(vc->obedit->data, sel_op);
1093 
1094  if (data.is_changed) {
1096  }
1097  return data.is_changed;
1098 }
1099 
1100 static void do_lasso_select_mball__doSelectElem(void *userData,
1101  struct MetaElem *ml,
1102  const float screen_co[2])
1103 {
1104  LassoSelectUserData *data = userData;
1105  const bool is_select = ml->flag & SELECT;
1106  const bool is_inside =
1107  (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
1109  data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], INT_MAX));
1110  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
1111  if (sel_op_result != -1) {
1112  SET_FLAG_FROM_TEST(ml->flag, sel_op_result, SELECT);
1113  data->is_changed = true;
1114  }
1115 }
1117  const int mcoords[][2],
1118  const int mcoords_len,
1119  const eSelectOp sel_op)
1120 {
1122  rcti rect;
1123 
1124  MetaBall *mb = (MetaBall *)vc->obedit->data;
1125 
1126  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
1127 
1128  view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
1129 
1130  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
1131  data.is_changed |= BKE_mball_deselect_all(mb);
1132  }
1133 
1135 
1138 
1139  return data.is_changed;
1140 }
1141 
1142 static void do_lasso_select_meshobject__doSelectVert(void *userData,
1143  MVert *mv,
1144  const float screen_co[2],
1145  int UNUSED(index))
1146 {
1147  LassoSelectUserData *data = userData;
1148  const bool is_select = mv->flag & SELECT;
1149  const bool is_inside =
1150  (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
1152  data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
1153  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
1154  if (sel_op_result != -1) {
1155  SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT);
1156  data->is_changed = true;
1157  }
1158 }
1160  wmGenericUserData *wm_userdata,
1161  const int mcoords[][2],
1162  const int mcoords_len,
1163  const eSelectOp sel_op)
1164 {
1165  const bool use_zbuf = !XRAY_ENABLED(vc->v3d);
1166  Object *ob = vc->obact;
1167  Mesh *me = ob->data;
1168  rcti rect;
1169 
1170  if (me == NULL || me->totvert == 0) {
1171  return false;
1172  }
1173 
1174  bool changed = false;
1175  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
1176  /* flush selection at the end */
1177  changed |= paintvert_deselect_all_visible(ob, SEL_DESELECT, false);
1178  }
1179 
1180  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
1181 
1182  struct EditSelectBuf_Cache *esel = wm_userdata->data;
1183  if (use_zbuf) {
1184  if (wm_userdata->data == NULL) {
1186  esel = wm_userdata->data;
1188  vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL);
1189  }
1190  }
1191 
1192  if (use_zbuf) {
1193  if (esel->select_bitmap != NULL) {
1194  changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op);
1195  }
1196  }
1197  else {
1199 
1200  view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
1201 
1203 
1206 
1207  changed |= data.is_changed;
1208  }
1209 
1210  if (changed) {
1211  if (SEL_OP_CAN_DESELECT(sel_op)) {
1213  }
1215  paintvert_tag_select_update(vc->C, ob);
1216  }
1217 
1218  return changed;
1219 }
1221  wmGenericUserData *wm_userdata,
1222  const int mcoords[][2],
1223  const int mcoords_len,
1224  const eSelectOp sel_op)
1225 {
1226  Object *ob = vc->obact;
1227  Mesh *me = ob->data;
1228  rcti rect;
1229 
1230  if (me == NULL || me->totpoly == 0) {
1231  return false;
1232  }
1233 
1234  bool changed = false;
1235  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
1236  /* flush selection at the end */
1237  changed |= paintface_deselect_all_visible(vc->C, ob, SEL_DESELECT, false);
1238  }
1239 
1240  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
1241 
1242  struct EditSelectBuf_Cache *esel = wm_userdata->data;
1243  if (esel == NULL) {
1245  esel = wm_userdata->data;
1247  vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL);
1248  }
1249 
1250  if (esel->select_bitmap) {
1251  changed |= edbm_backbuf_check_and_select_faces_obmode(me, esel, sel_op);
1252  }
1253 
1254  if (changed) {
1255  paintface_flush_flags(vc->C, ob, SELECT);
1256  }
1257  return changed;
1258 }
1259 
1260 #if 0
1261 static void do_lasso_select_node(int mcoords[][2], const int mcoords_len, const eSelectOp sel_op)
1262 {
1263  SpaceNode *snode = area->spacedata.first;
1264 
1265  bNode *node;
1266  rcti rect;
1267  int node_cent[2];
1268  float node_centf[2];
1269  bool changed = false;
1270 
1271  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
1272 
1273  /* store selection in temp test flag */
1274  for (node = snode->edittree->nodes.first; node; node = node->next) {
1275  node_centf[0] = BLI_RCT_CENTER_X(&node->totr);
1276  node_centf[1] = BLI_RCT_CENTER_Y(&node->totr);
1277 
1278  ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
1279  const bool is_select = node->flag & SELECT;
1280  const bool is_inside = (BLI_rcti_isect_pt_v(&rect, node_cent) &&
1281  BLI_lasso_is_point_inside(mcoords, mcoords_len, node_cent[0], node_cent[1]));
1282  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
1283  if (sel_op_result != -1) {
1284  SET_FLAG_FROM_TEST(node->flag, sel_op_result, SELECT);
1285  changed = true;
1286  }
1287  }
1288  if (changed) {
1289  BIF_undo_push("Lasso select nodes");
1290  }
1291 }
1292 #endif
1293 
1295  ViewContext *vc,
1296  const int mcoords[][2],
1297  const int mcoords_len,
1298  const eSelectOp sel_op)
1299 {
1301  bool changed_multi = false;
1302 
1303  wmGenericUserData wm_userdata_buf = {0};
1304  wmGenericUserData *wm_userdata = &wm_userdata_buf;
1305 
1306  if (vc->obedit == NULL) { /* Object Mode */
1307  if (BKE_paint_select_face_test(ob)) {
1308  changed_multi |= do_lasso_select_paintface(vc, wm_userdata, mcoords, mcoords_len, sel_op);
1309  }
1310  else if (BKE_paint_select_vert_test(ob)) {
1311  changed_multi |= do_lasso_select_paintvert(vc, wm_userdata, mcoords, mcoords_len, sel_op);
1312  }
1313  else if (ob &&
1315  /* pass */
1316  }
1317  else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
1318  changed_multi |= PE_lasso_select(C, mcoords, mcoords_len, sel_op);
1319  }
1320  else if (ob && (ob->mode & OB_MODE_POSE)) {
1321  changed_multi |= do_lasso_select_pose(vc, mcoords, mcoords_len, sel_op);
1322  if (changed_multi) {
1324  }
1325  }
1326  else {
1327  changed_multi |= do_lasso_select_objects(vc, mcoords, mcoords_len, sel_op);
1328  if (changed_multi) {
1330  }
1331  }
1332  }
1333  else { /* Edit Mode */
1334  FOREACH_OBJECT_IN_MODE_BEGIN (vc->view_layer, vc->v3d, ob->type, ob->mode, ob_iter) {
1335  ED_view3d_viewcontext_init_object(vc, ob_iter);
1336  bool changed = false;
1337 
1338  switch (vc->obedit->type) {
1339  case OB_MESH:
1340  changed = do_lasso_select_mesh(vc, wm_userdata, mcoords, mcoords_len, sel_op);
1341  break;
1342  case OB_CURVE:
1343  case OB_SURF:
1344  changed = do_lasso_select_curve(vc, mcoords, mcoords_len, sel_op);
1345  break;
1346  case OB_LATTICE:
1347  changed = do_lasso_select_lattice(vc, mcoords, mcoords_len, sel_op);
1348  break;
1349  case OB_ARMATURE:
1350  changed = do_lasso_select_armature(vc, mcoords, mcoords_len, sel_op);
1351  if (changed) {
1353  }
1354  break;
1355  case OB_MBALL:
1356  changed = do_lasso_select_meta(vc, mcoords, mcoords_len, sel_op);
1357  break;
1358  default:
1359  BLI_assert(!"lasso select on incorrect object type");
1360  break;
1361  }
1362 
1363  if (changed) {
1366  changed_multi = true;
1367  }
1368  }
1370  }
1371 
1372  WM_generic_user_data_free(wm_userdata);
1373 
1374  return changed_multi;
1375 }
1376 
1377 /* lasso operator gives properties, but since old code works
1378  * with short array we convert */
1380 {
1381  ViewContext vc;
1382  int mcoords_len;
1383  const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
1384 
1385  if (mcoords) {
1389 
1390  /* setup view context for argument to callbacks */
1392 
1393  eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
1394  bool changed_multi = view3d_lasso_select(C, &vc, mcoords, mcoords_len, sel_op);
1395 
1396  MEM_freeN((void *)mcoords);
1397 
1398  if (changed_multi) {
1399  return OPERATOR_FINISHED;
1400  }
1401  return OPERATOR_CANCELLED;
1402  }
1403  return OPERATOR_PASS_THROUGH;
1404 }
1405 
1407 {
1408  ot->name = "Lasso Select";
1409  ot->description = "Select items using lasso selection";
1410  ot->idname = "VIEW3D_OT_select_lasso";
1411 
1417 
1418  /* flags */
1419  ot->flag = OPTYPE_UNDO;
1420 
1421  /* properties */
1424 }
1425 
1428 /* -------------------------------------------------------------------- */
1432 /* The max number of menu items in an object select menu */
1433 typedef struct SelMenuItemF {
1434  char idname[MAX_ID_NAME - 2];
1435  int icon;
1437  void *item_ptr;
1439 
1440 #define SEL_MENU_SIZE 22
1442 
1443 /* special (crappy) operator only for menu select */
1445  PointerRNA *UNUSED(ptr),
1446  PropertyRNA *UNUSED(prop),
1447  bool *r_free)
1448 {
1449  EnumPropertyItem *item = NULL, item_tmp = {0};
1450  int totitem = 0;
1451  int i = 0;
1452 
1453  /* Don't need context but avoid API doc-generation using this. */
1454  if (C == NULL || object_mouse_select_menu_data[i].idname[0] == '\0') {
1455  return DummyRNA_NULL_items;
1456  }
1457 
1458  for (; i < SEL_MENU_SIZE && object_mouse_select_menu_data[i].idname[0] != '\0'; i++) {
1460  item_tmp.identifier = object_mouse_select_menu_data[i].idname;
1461  item_tmp.value = i;
1462  item_tmp.icon = object_mouse_select_menu_data[i].icon;
1463  RNA_enum_item_add(&item, &totitem, &item_tmp);
1464  }
1465 
1466  RNA_enum_item_end(&item, &totitem);
1467  *r_free = true;
1468 
1469  return item;
1470 }
1471 
1473 {
1474  const int name_index = RNA_enum_get(op->ptr, "name");
1475  const bool extend = RNA_boolean_get(op->ptr, "extend");
1476  const bool deselect = RNA_boolean_get(op->ptr, "deselect");
1477  const bool toggle = RNA_boolean_get(op->ptr, "toggle");
1478  bool changed = false;
1479  const char *name = object_mouse_select_menu_data[name_index].idname;
1480 
1481  View3D *v3d = CTX_wm_view3d(C);
1482  ViewLayer *view_layer = CTX_data_view_layer(C);
1483  const Base *oldbasact = BASACT(view_layer);
1484 
1485  Base *basact = NULL;
1486  CTX_DATA_BEGIN (C, Base *, base, selectable_bases) {
1487  /* This is a bit dodgy, there should only be ONE object with this name,
1488  * but library objects can mess this up. */
1489  if (STREQ(name, base->object->id.name + 2)) {
1490  basact = base;
1491  break;
1492  }
1493  }
1494  CTX_DATA_END;
1495 
1496  if (basact == NULL) {
1497  return OPERATOR_CANCELLED;
1498  }
1499  UNUSED_VARS_NDEBUG(v3d);
1500  BLI_assert(BASE_SELECTABLE(v3d, basact));
1501 
1502  if (extend) {
1504  changed = true;
1505  }
1506  else if (deselect) {
1508  changed = true;
1509  }
1510  else if (toggle) {
1511  if (basact->flag & BASE_SELECTED) {
1512  if (basact == oldbasact) {
1514  changed = true;
1515  }
1516  }
1517  else {
1519  changed = true;
1520  }
1521  }
1522  else {
1523  object_deselect_all_except(view_layer, basact);
1525  changed = true;
1526  }
1527 
1528  if ((oldbasact != basact)) {
1529  ED_object_base_activate(C, basact);
1530  }
1531 
1532  /* weak but ensures we activate menu again before using the enum */
1534 
1535  /* undo? */
1536  if (changed) {
1540 
1542 
1543  return OPERATOR_FINISHED;
1544  }
1545  return OPERATOR_CANCELLED;
1546 }
1547 
1549 {
1550  PropertyRNA *prop;
1551 
1552  /* identifiers */
1553  ot->name = "Select Menu";
1554  ot->description = "Menu object selection";
1555  ot->idname = "VIEW3D_OT_select_menu";
1556 
1557  /* api callbacks */
1560 
1561  /* flags */
1563 
1564  /* keyingset to use (dynamic enum) */
1565  prop = RNA_def_enum(ot->srna, "name", DummyRNA_NULL_items, 0, "Object Name", "");
1568  ot->prop = prop;
1569 
1570  RNA_def_boolean(ot->srna, "extend", 0, "Extend", "");
1571  RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
1572  RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
1573 }
1574 
1576  ViewContext *vc,
1577  const uint *buffer,
1578  int hits,
1579  const int mval[2],
1580  bool extend,
1581  bool deselect,
1582  bool toggle)
1583 {
1584  short baseCount = 0;
1585  bool ok;
1586  LinkNodePair linklist = {NULL, NULL};
1587 
1588  /* handle base->object->select_id */
1589  CTX_DATA_BEGIN (C, Base *, base, selectable_bases) {
1590  ok = false;
1591 
1592  /* two selection methods, the CTRL select uses max dist of 15 */
1593  if (buffer) {
1594  for (int a = 0; a < hits; a++) {
1595  /* index was converted */
1596  if (base->object->runtime.select_id == (buffer[(4 * a) + 3] & ~0xFFFF0000)) {
1597  ok = true;
1598  break;
1599  }
1600  }
1601  }
1602  else {
1603  const int dist = 15 * U.pixelsize;
1604  if (ED_view3d_project_base(vc->region, base) == V3D_PROJ_RET_OK) {
1605  const int delta_px[2] = {base->sx - mval[0], base->sy - mval[1]};
1606  if (len_manhattan_v2_int(delta_px) < dist) {
1607  ok = true;
1608  }
1609  }
1610  }
1611 
1612  if (ok) {
1613  baseCount++;
1614  BLI_linklist_append(&linklist, base);
1615 
1616  if (baseCount == SEL_MENU_SIZE) {
1617  break;
1618  }
1619  }
1620  }
1621  CTX_DATA_END;
1622 
1623  if (baseCount == 0) {
1624  return NULL;
1625  }
1626  if (baseCount == 1) {
1627  Base *base = (Base *)linklist.list->link;
1628  BLI_linklist_free(linklist.list, NULL);
1629  return base;
1630  }
1631 
1632  /* UI, full in static array values that we later use in an enum function */
1633  LinkNode *node;
1634  int i;
1635 
1637 
1638  for (node = linklist.list, i = 0; node; node = node->next, i++) {
1639  Base *base = node->link;
1640  Object *ob = base->object;
1641  const char *name = ob->id.name + 2;
1642 
1645  }
1646 
1647  wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_select_menu", false);
1648  PointerRNA ptr;
1649 
1651  RNA_boolean_set(&ptr, "extend", extend);
1652  RNA_boolean_set(&ptr, "deselect", deselect);
1653  RNA_boolean_set(&ptr, "toggle", toggle);
1656 
1657  BLI_linklist_free(linklist.list, NULL);
1658  return NULL;
1659 }
1660 
1662 {
1663  const int name_index = RNA_enum_get(op->ptr, "name");
1664  const bool extend = RNA_boolean_get(op->ptr, "extend");
1665  const bool deselect = RNA_boolean_get(op->ptr, "deselect");
1666  const bool toggle = RNA_boolean_get(op->ptr, "toggle");
1667 
1668  View3D *v3d = CTX_wm_view3d(C);
1669  ViewLayer *view_layer = CTX_data_view_layer(C);
1670  const Base *oldbasact = BASACT(view_layer);
1671 
1672  Base *basact = object_mouse_select_menu_data[name_index].base_ptr;
1673 
1674  if (basact == NULL) {
1675  return OPERATOR_CANCELLED;
1676  }
1677 
1678  BLI_assert(BASE_SELECTABLE(v3d, basact));
1679 
1680  if (basact->object->mode == OB_MODE_EDIT) {
1681  EditBone *ebone = (EditBone *)object_mouse_select_menu_data[name_index].item_ptr;
1682  ED_armature_edit_select_pick_bone(C, basact, ebone, BONE_SELECTED, extend, deselect, toggle);
1683  }
1684  else {
1685  bPoseChannel *pchan = (bPoseChannel *)object_mouse_select_menu_data[name_index].item_ptr;
1687  view_layer, v3d, basact->object, pchan->bone, extend, deselect, toggle);
1688  }
1689 
1690  /* Weak but ensures we activate the menu again before using the enum. */
1692 
1693  /* We make the armature selected:
1694  * Not-selected active object in posemode won't work well for tools. */
1696 
1699 
1700  /* In weight-paint, we use selected bone to select vertex-group,
1701  * so don't switch to new active object. */
1702  if (oldbasact && (oldbasact->object->mode & OB_MODE_ALL_WEIGHT_PAINT)) {
1703  /* Prevent activating.
1704  * Selection causes this to be considered the 'active' pose in weight-paint mode.
1705  * Eventually this limitation may be removed.
1706  * For now, de-select all other pose objects deforming this mesh. */
1707  ED_armature_pose_select_in_wpaint_mode(view_layer, basact);
1708 
1709  basact = NULL;
1710  }
1711 
1712  /* Undo? */
1717 
1719 
1720  return OPERATOR_FINISHED;
1721 }
1722 
1724 {
1725  PropertyRNA *prop;
1726 
1727  /* identifiers */
1728  ot->name = "Select Menu";
1729  ot->description = "Menu bone selection";
1730  ot->idname = "VIEW3D_OT_bone_select_menu";
1731 
1732  /* api callbacks */
1735 
1736  /* flags */
1738 
1739  /* keyingset to use (dynamic enum) */
1740  prop = RNA_def_enum(ot->srna, "name", DummyRNA_NULL_items, 0, "Bone Name", "");
1743  ot->prop = prop;
1744 
1745  RNA_def_boolean(ot->srna, "extend", 0, "Extend", "");
1746  RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
1747  RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
1748 }
1750  const uint *buffer,
1751  const int hits,
1752  const bool is_editmode,
1753  const bool extend,
1754  const bool deselect,
1755  const bool toggle)
1756 {
1757  BLI_assert(buffer);
1758 
1759  short baseCount = 0;
1760  LinkNodePair base_list = {NULL, NULL};
1761  LinkNodePair bone_list = {NULL, NULL};
1762  GSet *added_bones = BLI_gset_ptr_new("Bone mouse select menu");
1763 
1764  /* Select logic taken from ed_armature_pick_bone_from_selectbuffer_impl in armature_select.c */
1765  for (int a = 0; a < hits; a++) {
1766  void *bone_ptr = NULL;
1767  Base *bone_base = NULL;
1768  uint hitresult = buffer[3 + (a * 4)];
1769 
1770  if (!(hitresult & BONESEL_ANY)) {
1771  /* To avoid including objects in selection. */
1772  continue;
1773  }
1774 
1775  hitresult &= ~BONESEL_ANY;
1776  const uint hit_object = hitresult & 0xFFFF;
1777 
1778  /* Find the hit bone base (armature object). */
1779  CTX_DATA_BEGIN (C, Base *, base, selectable_bases) {
1780  if (base->object->runtime.select_id == hit_object) {
1781  bone_base = base;
1782  break;
1783  }
1784  }
1785  CTX_DATA_END;
1786 
1787  if (!bone_base) {
1788  continue;
1789  }
1790 
1791  /* Determine what the current bone is */
1792  if (is_editmode) {
1793  EditBone *ebone;
1794  const uint hit_bone = (hitresult & ~BONESEL_ANY) >> 16;
1795  bArmature *arm = bone_base->object->data;
1796  ebone = BLI_findlink(arm->edbo, hit_bone);
1797  if (ebone && !(ebone->flag & BONE_UNSELECTABLE)) {
1798  bone_ptr = ebone;
1799  }
1800  }
1801  else {
1802  bPoseChannel *pchan;
1803  const uint hit_bone = (hitresult & ~BONESEL_ANY) >> 16;
1804  pchan = BLI_findlink(&bone_base->object->pose->chanbase, hit_bone);
1805  if (pchan && !(pchan->bone->flag & BONE_UNSELECTABLE)) {
1806  bone_ptr = pchan;
1807  }
1808  }
1809 
1810  if (!bone_ptr) {
1811  continue;
1812  }
1813  /* We can hit a bone multiple times, so make sure we are not adding an already included bone
1814  * to the list.*/
1815  const bool is_duplicate_bone = BLI_gset_haskey(added_bones, bone_ptr);
1816 
1817  if (!is_duplicate_bone) {
1818  baseCount++;
1819  BLI_linklist_append(&base_list, bone_base);
1820  BLI_linklist_append(&bone_list, bone_ptr);
1821  BLI_gset_insert(added_bones, bone_ptr);
1822 
1823  if (baseCount == SEL_MENU_SIZE) {
1824  break;
1825  }
1826  }
1827  }
1828 
1829  BLI_gset_free(added_bones, NULL);
1830 
1831  if (baseCount == 0) {
1832  return false;
1833  }
1834  if (baseCount == 1) {
1835  BLI_linklist_free(base_list.list, NULL);
1836  BLI_linklist_free(bone_list.list, NULL);
1837  return false;
1838  }
1839 
1840  /* UI, full in static array values that we later use in an enum function */
1841  LinkNode *bone_node, *base_node;
1842  int i;
1843 
1845 
1846  for (base_node = base_list.list, bone_node = bone_list.list, i = 0; bone_node;
1847  base_node = base_node->next, bone_node = bone_node->next, i++) {
1848  char *name;
1849 
1851 
1852  if (is_editmode) {
1853  EditBone *ebone = bone_node->link;
1855  name = ebone->name;
1856  }
1857  else {
1858  bPoseChannel *pchan = bone_node->link;
1860  name = pchan->name;
1861  }
1862 
1864  object_mouse_select_menu_data[i].icon = ICON_BONE_DATA;
1865  }
1866 
1867  wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_bone_select_menu", false);
1868  PointerRNA ptr;
1869 
1871  RNA_boolean_set(&ptr, "extend", extend);
1872  RNA_boolean_set(&ptr, "deselect", deselect);
1873  RNA_boolean_set(&ptr, "toggle", toggle);
1876 
1877  BLI_linklist_free(base_list.list, NULL);
1878  BLI_linklist_free(bone_list.list, NULL);
1879  return true;
1880 }
1881 
1882 static bool selectbuffer_has_bones(const uint *buffer, const uint hits)
1883 {
1884  for (uint i = 0; i < hits; i++) {
1885  if (buffer[(4 * i) + 3] & 0xFFFF0000) {
1886  return true;
1887  }
1888  }
1889  return false;
1890 }
1891 
1892 /* utility function for mixed_bones_object_selectbuffer */
1893 static int selectbuffer_ret_hits_15(uint *UNUSED(buffer), const int hits15)
1894 {
1895  return hits15;
1896 }
1897 
1898 static int selectbuffer_ret_hits_9(uint *buffer, const int hits15, const int hits9)
1899 {
1900  const int ofs = 4 * hits15;
1901  memcpy(buffer, buffer + ofs, 4 * hits9 * sizeof(uint));
1902  return hits9;
1903 }
1904 
1906  const int hits15,
1907  const int hits9,
1908  const int hits5)
1909 {
1910  const int ofs = 4 * hits15 + 4 * hits9;
1911  memcpy(buffer, buffer + ofs, 4 * hits5 * sizeof(uint));
1912  return hits5;
1913 }
1914 
1924  uint *buffer,
1925  const int mval[2],
1926  eV3DSelectObjectFilter select_filter,
1927  bool do_nearest,
1928  bool do_nearest_xray_if_supported)
1929 {
1930  rcti rect;
1931  int hits15, hits9 = 0, hits5 = 0;
1932  bool has_bones15 = false, has_bones9 = false, has_bones5 = false;
1933 
1934  int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
1935  int hits = 0;
1936 
1937  if (do_nearest_xray_if_supported) {
1938  if ((U.gpu_flag & USER_GPU_FLAG_NO_DEPT_PICK) == 0) {
1939  select_mode = VIEW3D_SELECT_PICK_ALL;
1940  }
1941  }
1942 
1943  /* we _must_ end cache before return, use 'goto finally' */
1945 
1946  BLI_rcti_init_pt_radius(&rect, mval, 14);
1947  hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter);
1948  if (hits15 == 1) {
1949  hits = selectbuffer_ret_hits_15(buffer, hits15);
1950  goto finally;
1951  }
1952  else if (hits15 > 0) {
1953  int ofs;
1954  has_bones15 = selectbuffer_has_bones(buffer, hits15);
1955 
1956  ofs = 4 * hits15;
1957  BLI_rcti_init_pt_radius(&rect, mval, 9);
1958  hits9 = view3d_opengl_select(
1959  vc, buffer + ofs, MAXPICKBUF - ofs, &rect, select_mode, select_filter);
1960  if (hits9 == 1) {
1961  hits = selectbuffer_ret_hits_9(buffer, hits15, hits9);
1962  goto finally;
1963  }
1964  else if (hits9 > 0) {
1965  has_bones9 = selectbuffer_has_bones(buffer + ofs, hits9);
1966 
1967  ofs += 4 * hits9;
1968  BLI_rcti_init_pt_radius(&rect, mval, 5);
1969  hits5 = view3d_opengl_select(
1970  vc, buffer + ofs, MAXPICKBUF - ofs, &rect, select_mode, select_filter);
1971  if (hits5 == 1) {
1972  hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
1973  goto finally;
1974  }
1975  else if (hits5 > 0) {
1976  has_bones5 = selectbuffer_has_bones(buffer + ofs, hits5);
1977  }
1978  }
1979 
1980  if (has_bones5) {
1981  hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
1982  goto finally;
1983  }
1984  else if (has_bones9) {
1985  hits = selectbuffer_ret_hits_9(buffer, hits15, hits9);
1986  goto finally;
1987  }
1988  else if (has_bones15) {
1989  hits = selectbuffer_ret_hits_15(buffer, hits15);
1990  goto finally;
1991  }
1992 
1993  if (hits5 > 0) {
1994  hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
1995  goto finally;
1996  }
1997  else if (hits9 > 0) {
1998  hits = selectbuffer_ret_hits_9(buffer, hits15, hits9);
1999  goto finally;
2000  }
2001  else {
2002  hits = selectbuffer_ret_hits_15(buffer, hits15);
2003  goto finally;
2004  }
2005  }
2006 
2007 finally:
2009  return hits;
2010 }
2011 
2013  uint *buffer,
2014  const int mval[2],
2015  eV3DSelectObjectFilter select_filter,
2016  bool use_cycle,
2017  bool enumerate,
2018  bool *r_do_nearest)
2019 {
2020  static int last_mval[2] = {-100, -100};
2021  bool do_nearest = false;
2022  View3D *v3d = vc->v3d;
2023 
2024  /* define if we use solid nearest select or not */
2025  if (use_cycle) {
2026  if (!XRAY_ACTIVE(v3d)) {
2027  do_nearest = true;
2028  if (len_manhattan_v2v2_int(mval, last_mval) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) {
2029  do_nearest = false;
2030  }
2031  }
2032  copy_v2_v2_int(last_mval, mval);
2033  }
2034  else {
2035  if (!XRAY_ACTIVE(v3d)) {
2036  do_nearest = true;
2037  }
2038  }
2039 
2040  if (r_do_nearest) {
2041  *r_do_nearest = do_nearest;
2042  }
2043 
2044  do_nearest = do_nearest && !enumerate;
2045 
2046  int hits = mixed_bones_object_selectbuffer(vc, buffer, mval, select_filter, do_nearest, true);
2047 
2048  return hits;
2049 }
2050 
2059  const uint *buffer,
2060  int hits,
2061  Base *startbase,
2062  bool has_bones,
2063  bool do_nearest)
2064 {
2065  ViewLayer *view_layer = vc->view_layer;
2066  View3D *v3d = vc->v3d;
2067  Base *base, *basact = NULL;
2068  int a;
2069 
2070  if (do_nearest) {
2071  uint min = 0xFFFFFFFF;
2072  int selcol = 0, notcol = 0;
2073 
2074  if (has_bones) {
2075  /* we skip non-bone hits */
2076  for (a = 0; a < hits; a++) {
2077  if (min > buffer[4 * a + 1] && (buffer[4 * a + 3] & 0xFFFF0000)) {
2078  min = buffer[4 * a + 1];
2079  selcol = buffer[4 * a + 3] & 0xFFFF;
2080  }
2081  }
2082  }
2083  else {
2084  /* only exclude active object when it is selected... */
2085  if (BASACT(view_layer) && (BASACT(view_layer)->flag & BASE_SELECTED) && hits > 1) {
2086  notcol = BASACT(view_layer)->object->runtime.select_id;
2087  }
2088 
2089  for (a = 0; a < hits; a++) {
2090  if (min > buffer[4 * a + 1] && notcol != (buffer[4 * a + 3] & 0xFFFF)) {
2091  min = buffer[4 * a + 1];
2092  selcol = buffer[4 * a + 3] & 0xFFFF;
2093  }
2094  }
2095  }
2096 
2097  base = FIRSTBASE(view_layer);
2098  while (base) {
2099  if (has_bones ? BASE_VISIBLE(v3d, base) : BASE_SELECTABLE(v3d, base)) {
2100  if (base->object->runtime.select_id == selcol) {
2101  break;
2102  }
2103  }
2104  base = base->next;
2105  }
2106  if (base) {
2107  basact = base;
2108  }
2109  }
2110  else {
2111 
2112  base = startbase;
2113  while (base) {
2114  /* skip objects with select restriction, to prevent prematurely ending this loop
2115  * with an un-selectable choice */
2116  if (has_bones ? (base->flag & BASE_VISIBLE_VIEWLAYER) == 0 :
2117  (base->flag & BASE_SELECTABLE) == 0) {
2118  base = base->next;
2119  if (base == NULL) {
2120  base = FIRSTBASE(view_layer);
2121  }
2122  if (base == startbase) {
2123  break;
2124  }
2125  }
2126 
2127  if (has_bones ? BASE_VISIBLE(v3d, base) : BASE_SELECTABLE(v3d, base)) {
2128  for (a = 0; a < hits; a++) {
2129  if (has_bones) {
2130  /* skip non-bone objects */
2131  if ((buffer[4 * a + 3] & 0xFFFF0000)) {
2132  if (base->object->runtime.select_id == (buffer[(4 * a) + 3] & 0xFFFF)) {
2133  basact = base;
2134  }
2135  }
2136  }
2137  else {
2138  if (base->object->runtime.select_id == (buffer[(4 * a) + 3] & 0xFFFF)) {
2139  basact = base;
2140  }
2141  }
2142  }
2143  }
2144 
2145  if (basact) {
2146  break;
2147  }
2148 
2149  base = base->next;
2150  if (base == NULL) {
2151  base = FIRSTBASE(view_layer);
2152  }
2153  if (base == startbase) {
2154  break;
2155  }
2156  }
2157  }
2158 
2159  return basact;
2160 }
2161 
2162 /* mval comes from event->mval, only use within region handlers */
2164 {
2166  ViewContext vc;
2167  Base *basact = NULL;
2169 
2170  /* setup view context for argument to callbacks */
2173 
2175 
2176  const bool do_nearest = !XRAY_ACTIVE(vc.v3d);
2177  const int hits = mixed_bones_object_selectbuffer(
2178  &vc, buffer, mval, VIEW3D_SELECT_FILTER_NOP, do_nearest, false);
2179 
2180  if (hits > 0) {
2181  const bool has_bones = selectbuffer_has_bones(buffer, hits);
2182  basact = mouse_select_eval_buffer(
2183  &vc, buffer, hits, vc.view_layer->object_bases.first, has_bones, do_nearest);
2184  }
2185 
2186  return basact;
2187 }
2188 
2190 {
2191  Base *base = ED_view3d_give_base_under_cursor(C, mval);
2192  if (base) {
2193  return base->object;
2194  }
2195  return NULL;
2196 }
2197 
2199 {
2200  return ED_view3d_give_object_under_cursor(C, mval) != NULL;
2201 }
2202 
2203 static void deselect_all_tracks(MovieTracking *tracking)
2204 {
2205  MovieTrackingObject *object;
2206 
2207  object = tracking->objects.first;
2208  while (object) {
2209  ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
2210  MovieTrackingTrack *track = tracksbase->first;
2211 
2212  while (track) {
2214 
2215  track = track->next;
2216  }
2217 
2218  object = object->next;
2219  }
2220 }
2221 
2222 /* mval is region coords */
2224  const int mval[2],
2225  bool extend,
2226  bool deselect,
2227  bool toggle,
2228  bool obcenter,
2229  bool enumerate,
2230  bool object)
2231 {
2233  ViewContext vc;
2234  /* setup view context for argument to callbacks */
2236 
2237  const ARegion *region = CTX_wm_region(C);
2239  ViewLayer *view_layer = CTX_data_view_layer(C);
2240  View3D *v3d = CTX_wm_view3d(C);
2241  /* Don't set when the context has no active object (hidden), see: T60807. */
2242  const Base *oldbasact = vc.obact ? BASACT(view_layer) : NULL;
2243  Base *base, *startbase = NULL, *basact = NULL;
2244  const eObjectMode object_mode = oldbasact ? oldbasact->object->mode : OB_MODE_OBJECT;
2245  bool is_obedit;
2246  float dist = ED_view3d_select_dist_px() * 1.3333f;
2247  bool retval = false;
2248  int hits;
2249  const float mval_fl[2] = {(float)mval[0], (float)mval[1]};
2250 
2251  is_obedit = (vc.obedit != NULL);
2252  if (object) {
2253  /* Signal for #view3d_opengl_select to skip edit-mode objects. */
2254  vc.obedit = NULL;
2255  }
2256 
2257  /* In pose mode we don't want to mess with object selection. */
2258  const bool is_pose_mode = (vc.obact && vc.obact->mode & OB_MODE_POSE);
2259 
2260  /* always start list from basact in wire mode */
2261  startbase = FIRSTBASE(view_layer);
2262  if (oldbasact && oldbasact->next) {
2263  startbase = oldbasact->next;
2264  }
2265 
2266  /* This block uses the control key to make the object selected
2267  * by its center point rather than its contents */
2268 
2269  /* In edit-mode do not activate. */
2270  if (obcenter) {
2271 
2272  /* note; shift+alt goes to group-flush-selecting */
2273  if (enumerate) {
2274  basact = object_mouse_select_menu(C, &vc, NULL, 0, mval, extend, deselect, toggle);
2275  }
2276  else {
2277  base = startbase;
2278  while (base) {
2279  if (BASE_SELECTABLE(v3d, base)) {
2280  float screen_co[2];
2282  region, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_DEFAULT) ==
2283  V3D_PROJ_RET_OK) {
2284  float dist_temp = len_manhattan_v2v2(mval_fl, screen_co);
2285  if (base == oldbasact) {
2286  dist_temp += 10.0f;
2287  }
2288  if (dist_temp < dist) {
2289  dist = dist_temp;
2290  basact = base;
2291  }
2292  }
2293  }
2294  base = base->next;
2295 
2296  if (base == NULL) {
2297  base = FIRSTBASE(view_layer);
2298  }
2299  if (base == startbase) {
2300  break;
2301  }
2302  }
2303  }
2305  if (is_obedit == false) {
2306  if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) {
2307  if (object_mode == OB_MODE_OBJECT) {
2308  struct Main *bmain = CTX_data_main(C);
2309  ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object);
2310  }
2311  if (!BKE_object_is_mode_compat(basact->object, object_mode)) {
2312  basact = NULL;
2313  }
2314  }
2315  }
2316  }
2317  }
2318  else {
2320  bool do_nearest;
2321 
2322  // TIMEIT_START(select_time);
2323 
2324  /* if objects have posemode set, the bones are in the same selection buffer */
2325  const eV3DSelectObjectFilter select_filter = ((object == false) ?
2327  vc.obact) :
2330  &vc, buffer, mval, select_filter, true, enumerate, &do_nearest);
2331 
2332  // TIMEIT_END(select_time);
2333 
2334  if (hits > 0) {
2335  /* note: bundles are handling in the same way as bones */
2336  const bool has_bones = object ? false : selectbuffer_has_bones(buffer, hits);
2337 
2338  /* note; shift+alt goes to group-flush-selecting */
2339  if (enumerate) {
2340  if (has_bones &&
2341  bone_mouse_select_menu(C, buffer, hits, false, extend, deselect, toggle)) {
2342  basact = NULL;
2343  }
2344  else {
2345  basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, extend, deselect, toggle);
2346  }
2347  }
2348  else {
2349  basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, has_bones, do_nearest);
2350  }
2351 
2352  if (has_bones && basact) {
2353  if (basact->object->type == OB_CAMERA) {
2354  MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, false);
2355  if (clip != NULL && oldbasact == basact) {
2356  bool changed = false;
2357 
2358  for (int i = 0; i < hits; i++) {
2359  int hitresult = buffer[3 + (i * 4)];
2360 
2361  /* if there's bundles in buffer select bundles first,
2362  * so non-camera elements should be ignored in buffer */
2363  if (basact->object->runtime.select_id != (hitresult & 0xFFFF)) {
2364  continue;
2365  }
2366 
2367  /* index of bundle is 1<<16-based. if there's no "bone" index
2368  * in height word, this buffer value belongs to camera. not to bundle
2369  */
2370  if (buffer[4 * i + 3] & 0xFFFF0000) {
2371  MovieTracking *tracking = &clip->tracking;
2372  ListBase *tracksbase;
2373  MovieTrackingTrack *track;
2374 
2376  &clip->tracking, hitresult >> 16, &tracksbase);
2377 
2378  if (TRACK_SELECTED(track) && extend) {
2379  changed = false;
2381  }
2382  else {
2383  int oldsel = TRACK_SELECTED(track) ? 1 : 0;
2384  if (!extend) {
2385  deselect_all_tracks(tracking);
2386  }
2387 
2388  BKE_tracking_track_select(tracksbase, track, TRACK_AREA_ALL, extend);
2389 
2390  if (oldsel != (TRACK_SELECTED(track) ? 1 : 0)) {
2391  changed = true;
2392  }
2393  }
2394 
2396 
2397  retval = true;
2398 
2403 
2404  break;
2405  }
2406  }
2407 
2408  if (!changed) {
2409  /* fallback to regular object selection if no new bundles were selected,
2410  * allows to select object parented to reconstruction object */
2411  basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, 0, do_nearest);
2412  }
2413  }
2414  }
2415  else if (ED_armature_pose_select_pick_with_buffer(view_layer,
2416  v3d,
2417  basact,
2418  buffer,
2419  hits,
2420  extend,
2421  deselect,
2422  toggle,
2423  do_nearest)) {
2424  /* then bone is found */
2425 
2426  /* we make the armature selected:
2427  * not-selected active object in posemode won't work well for tools */
2429 
2430  retval = true;
2431  WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
2432  WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, basact->object);
2434 
2435  /* In weight-paint, we use selected bone to select vertex-group,
2436  * so don't switch to new active object. */
2437  if (oldbasact && (oldbasact->object->mode & OB_MODE_ALL_WEIGHT_PAINT)) {
2438  /* Prevent activating.
2439  * Selection causes this to be considered the 'active' pose in weight-paint mode.
2440  * Eventually this limitation may be removed.
2441  * For now, de-select all other pose objects deforming this mesh. */
2442  ED_armature_pose_select_in_wpaint_mode(view_layer, basact);
2443 
2444  basact = NULL;
2445  }
2446  }
2447  /* prevent bone selecting to pass on to object selecting */
2448  if (basact == oldbasact) {
2449  basact = NULL;
2450  }
2451  }
2452 
2454  if (is_obedit == false) {
2455  if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) {
2456  if (object_mode == OB_MODE_OBJECT) {
2457  struct Main *bmain = CTX_data_main(C);
2458  ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object);
2459  }
2460  if (!BKE_object_is_mode_compat(basact->object, object_mode)) {
2461  basact = NULL;
2462  }
2463  }
2464  }
2465  }
2466  }
2467  }
2468 
2470  /* Disallow switching modes,
2471  * special exception for edit-mode - vertex-parent operator. */
2472  if (is_obedit == false) {
2473  if (oldbasact && basact) {
2474  if ((oldbasact->object->mode != basact->object->mode) &&
2475  (oldbasact->object->mode & basact->object->mode) == 0) {
2476  basact = NULL;
2477  }
2478  }
2479  }
2480  }
2481 
2482  /* Ensure code above doesn't change the active base. */
2483  BLI_assert(oldbasact == (vc.obact ? BASACT(view_layer) : NULL));
2484 
2485  /* so, do we have something selected? */
2486  if (basact) {
2487  retval = true;
2488 
2489  if (vc.obedit) {
2490  /* only do select */
2491  object_deselect_all_except(view_layer, basact);
2493  }
2494  /* also prevent making it active on mouse selection */
2495  else if (BASE_SELECTABLE(v3d, basact)) {
2496  if (extend) {
2498  }
2499  else if (deselect) {
2501  }
2502  else if (toggle) {
2503  if (basact->flag & BASE_SELECTED) {
2504  if (basact == oldbasact) {
2506  }
2507  }
2508  else {
2510  }
2511  }
2512  else {
2513  /* When enabled, this puts other objects out of multi pose-mode. */
2514  if (is_pose_mode == false || (basact->object->mode & OB_MODE_POSE) == 0) {
2515  object_deselect_all_except(view_layer, basact);
2517  }
2518  }
2519 
2520  if ((oldbasact != basact) && (is_obedit == false)) {
2521  ED_object_base_activate(C, basact); /* adds notifier */
2524  }
2525  }
2526 
2527  /* Set special modes for grease pencil
2528  * The grease pencil modes are not real modes, but a hack to make the interface
2529  * consistent, so need some tricks to keep UI synchronized */
2530  /* XXX: This stuff needs reviewing (Aligorith) */
2531  if (false && (((oldbasact) && oldbasact->object->type == OB_GPENCIL) ||
2532  (basact->object->type == OB_GPENCIL))) {
2533  /* set cursor */
2534  if (ELEM(basact->object->mode,
2540  }
2541  else {
2542  /* TODO: maybe is better use restore */
2544  }
2545  }
2546  }
2547 
2550  }
2551 
2552  return retval;
2553 }
2554 
2555 /* mouse selection in weight paint */
2556 /* gets called via generic mouse select operator */
2558  bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, Object *obact)
2559 {
2560  View3D *v3d = CTX_wm_view3d(C);
2561  const bool use_zbuf = !XRAY_ENABLED(v3d);
2562 
2563  Mesh *me = obact->data; /* already checked for NULL */
2564  uint index = 0;
2565  MVert *mv;
2566 
2567  if (ED_mesh_pick_vert(C, obact, mval, ED_MESH_PICK_DEFAULT_VERT_DIST, use_zbuf, &index)) {
2568  mv = &me->mvert[index];
2569  if (extend) {
2570  mv->flag |= SELECT;
2571  }
2572  else if (deselect) {
2573  mv->flag &= ~SELECT;
2574  }
2575  else if (toggle) {
2576  mv->flag ^= SELECT;
2577  }
2578  else {
2580  mv->flag |= SELECT;
2581  }
2582 
2583  /* update mselect */
2584  if (mv->flag & SELECT) {
2586  }
2587  else {
2589  }
2590 
2591  paintvert_flush_flags(obact);
2593  return true;
2594  }
2595  return false;
2596 }
2597 
2599 {
2601  Object *obedit = CTX_data_edit_object(C);
2602  Object *obact = CTX_data_active_object(C);
2603  bool extend = RNA_boolean_get(op->ptr, "extend");
2604  bool deselect = RNA_boolean_get(op->ptr, "deselect");
2605  bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
2606  bool toggle = RNA_boolean_get(op->ptr, "toggle");
2607  bool center = RNA_boolean_get(op->ptr, "center");
2608  bool enumerate = RNA_boolean_get(op->ptr, "enumerate");
2609  /* Only force object select for edit-mode to support vertex parenting,
2610  * or paint-select to allow pose bone select with vert/face select. */
2611  bool object = (RNA_boolean_get(op->ptr, "object") &&
2612  (obedit || BKE_paint_select_elem_test(obact) ||
2613  /* so its possible to select bones in weight-paint mode (LMB select) */
2614  (obact && (obact->mode & OB_MODE_ALL_WEIGHT_PAINT) &&
2615  BKE_object_pose_armature_get(obact))));
2616 
2617  bool retval = false;
2618  int location[2];
2619 
2620  RNA_int_get_array(op->ptr, "location", location);
2621 
2624 
2625  if (object) {
2626  obedit = NULL;
2627  obact = NULL;
2628 
2629  /* ack, this is incorrect but to do this correctly we would need an
2630  * alternative edit-mode/object-mode keymap, this copies the functionality
2631  * from 2.4x where Ctrl+Select in edit-mode does object select only. */
2632  center = false;
2633  }
2634 
2635  if (obedit && object == false) {
2636  if (obedit->type == OB_MESH) {
2637  retval = EDBM_select_pick(C, location, extend, deselect, toggle);
2638  if (!retval && deselect_all) {
2639  retval = EDBM_mesh_deselect_all_multi(C);
2640  }
2641  }
2642  else if (obedit->type == OB_ARMATURE) {
2643  if (enumerate) {
2645  ViewContext vc;
2647 
2649  const int hits = mixed_bones_object_selectbuffer(
2650  &vc, buffer, location, VIEW3D_SELECT_FILTER_NOP, false, true);
2651  retval = bone_mouse_select_menu(C, buffer, hits, true, extend, deselect, toggle);
2652  }
2653  if (!retval) {
2654  retval = ED_armature_edit_select_pick(C, location, extend, deselect, toggle);
2655  }
2656 
2657  if (!retval && deselect_all) {
2659  }
2660  if (retval) {
2662  }
2663  }
2664  else if (obedit->type == OB_LATTICE) {
2665  retval = ED_lattice_select_pick(C, location, extend, deselect, toggle);
2666  if (!retval && deselect_all) {
2667  retval = ED_lattice_deselect_all_multi(C);
2668  }
2669  }
2670  else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
2671  retval = ED_curve_editnurb_select_pick(C, location, extend, deselect, toggle);
2672  if (!retval && deselect_all) {
2673  retval = ED_curve_deselect_all_multi(C);
2674  }
2675  }
2676  else if (obedit->type == OB_MBALL) {
2677  retval = ED_mball_select_pick(C, location, extend, deselect, toggle);
2678  if (!retval && deselect_all) {
2679  retval = ED_mball_deselect_all_multi(C);
2680  }
2681  }
2682  else if (obedit->type == OB_FONT) {
2683  retval = ED_curve_editfont_select_pick(C, location, extend, deselect, toggle);
2684  if (!retval && deselect_all) {
2685  /* pass */
2686  }
2687  }
2688  if (retval) {
2690  }
2691  }
2692  else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
2693  retval = PE_mouse_particles(C, location, extend, deselect, toggle);
2694  if (!retval && deselect_all) {
2695  retval = PE_deselect_all_visible(C);
2696  }
2697  }
2698  else if (obact && BKE_paint_select_face_test(obact)) {
2699  retval = paintface_mouse_select(C, obact, location, extend, deselect, toggle);
2700  if (!retval && deselect_all) {
2702  }
2703  }
2704  else if (BKE_paint_select_vert_test(obact)) {
2705  retval = ed_wpaint_vertex_select_pick(C, location, extend, deselect, toggle, obact);
2706  if (!retval && deselect_all) {
2707  retval = paintvert_deselect_all_visible(obact, SEL_DESELECT, false);
2708  if (retval) {
2710  }
2711  }
2712  }
2713  else {
2714  retval = ed_object_select_pick(
2715  C, location, extend, deselect, toggle, center, enumerate, object);
2716  if (!retval && deselect_all) {
2718  retval = ED_pose_deselect_all_multi(C, SEL_DESELECT, false);
2719  }
2720  else {
2721  retval = ED_object_base_deselect_all(
2724  }
2725  }
2726 
2727  if (retval) {
2728  if (obact && obact->mode & OB_MODE_POSE) {
2730  }
2731  else {
2733  }
2734  }
2735  }
2736 
2737  /* Pass-through allows tweaks
2738  * FINISHED to signal one operator worked */
2739  if (retval) {
2742  }
2743  return OPERATOR_PASS_THROUGH; /* nothing selected, just passthrough */
2744 }
2745 
2746 static int view3d_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2747 {
2748  RNA_int_set_array(op->ptr, "location", event->mval);
2749 
2750  return view3d_select_exec(C, op);
2751 }
2752 
2754 {
2755  PropertyRNA *prop;
2756 
2757  /* identifiers */
2758  ot->name = "Select";
2759  ot->description = "Select and activate item(s)";
2760  ot->idname = "VIEW3D_OT_select";
2761 
2762  /* api callbacks */
2766 
2767  /* flags */
2768  ot->flag = OPTYPE_UNDO;
2769 
2770  /* properties */
2772 
2773  prop = RNA_def_boolean(
2774  ot->srna,
2775  "center",
2776  0,
2777  "Center",
2778  "Use the object center when selecting, in edit mode used to extend object selection");
2780  prop = RNA_def_boolean(
2781  ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only)");
2783  prop = RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (edit mode only)");
2785 
2786  prop = RNA_def_int_vector(ot->srna,
2787  "location",
2788  2,
2789  NULL,
2790  INT_MIN,
2791  INT_MAX,
2792  "Location",
2793  "Mouse location",
2794  INT_MIN,
2795  INT_MAX);
2797 }
2798 
2801 /* -------------------------------------------------------------------- */
2805 typedef struct BoxSelectUserData {
2807  const rcti *rect;
2808  const rctf *rect_fl;
2812 
2813  /* runtime */
2814  bool is_done;
2817 
2819  ViewContext *vc,
2820  const rcti *rect,
2821  const eSelectOp sel_op)
2822 {
2823  r_data->vc = vc;
2824 
2825  r_data->rect = rect;
2826  r_data->rect_fl = &r_data->_rect_fl;
2827  BLI_rctf_rcti_copy(&r_data->_rect_fl, rect);
2828 
2829  r_data->sel_op = sel_op;
2830  /* SELECT by default, but can be changed if needed (only few cases use and respect this). */
2831  r_data->select_flag = SELECT;
2832 
2833  /* runtime */
2834  r_data->is_done = false;
2835  r_data->is_changed = false;
2836 }
2837 
2838 bool edge_inside_circle(const float cent[2],
2839  float radius,
2840  const float screen_co_a[2],
2841  const float screen_co_b[2])
2842 {
2843  const float radius_squared = radius * radius;
2844  return (dist_squared_to_line_segment_v2(cent, screen_co_a, screen_co_b) < radius_squared);
2845 }
2846 
2847 static void do_paintvert_box_select__doSelectVert(void *userData,
2848  MVert *mv,
2849  const float screen_co[2],
2850  int UNUSED(index))
2851 {
2852  BoxSelectUserData *data = userData;
2853  const bool is_select = mv->flag & SELECT;
2854  const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
2855  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
2856  if (sel_op_result != -1) {
2857  SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT);
2858  data->is_changed = true;
2859  }
2860 }
2862  wmGenericUserData *wm_userdata,
2863  const rcti *rect,
2864  const eSelectOp sel_op)
2865 {
2866  const bool use_zbuf = !XRAY_ENABLED(vc->v3d);
2867 
2868  Mesh *me;
2869 
2870  me = vc->obact->data;
2871  if ((me == NULL) || (me->totvert == 0)) {
2872  return OPERATOR_CANCELLED;
2873  }
2874 
2875  bool changed = false;
2876  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
2877  changed |= paintvert_deselect_all_visible(vc->obact, SEL_DESELECT, false);
2878  }
2879 
2880  if (BLI_rcti_is_empty(rect)) {
2881  /* pass */
2882  }
2883  else if (use_zbuf) {
2884  struct EditSelectBuf_Cache *esel = wm_userdata->data;
2885  if (wm_userdata->data == NULL) {
2887  esel = wm_userdata->data;
2889  vc->depsgraph, vc->region, vc->v3d, rect, NULL);
2890  }
2891  if (esel->select_bitmap != NULL) {
2892  changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op);
2893  }
2894  }
2895  else {
2897 
2898  view3d_userdata_boxselect_init(&data, vc, rect, sel_op);
2899 
2901 
2904  changed |= data.is_changed;
2905  }
2906 
2907  if (changed) {
2908  if (SEL_OP_CAN_DESELECT(sel_op)) {
2910  }
2913  }
2914  return changed;
2915 }
2916 
2918  wmGenericUserData *wm_userdata,
2919  const rcti *rect,
2920  int sel_op)
2921 {
2922  Object *ob = vc->obact;
2923  Mesh *me;
2924 
2925  me = BKE_mesh_from_object(ob);
2926  if ((me == NULL) || (me->totpoly == 0)) {
2927  return false;
2928  }
2929 
2930  bool changed = false;
2931  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
2932  changed |= paintface_deselect_all_visible(vc->C, vc->obact, SEL_DESELECT, false);
2933  }
2934 
2935  if (BLI_rcti_is_empty(rect)) {
2936  /* pass */
2937  }
2938  else {
2939  struct EditSelectBuf_Cache *esel = wm_userdata->data;
2940  if (wm_userdata->data == NULL) {
2942  esel = wm_userdata->data;
2944  vc->depsgraph, vc->region, vc->v3d, rect, NULL);
2945  }
2946  if (esel->select_bitmap != NULL) {
2947  changed |= edbm_backbuf_check_and_select_faces_obmode(me, esel, sel_op);
2948  }
2949  }
2950 
2951  if (changed) {
2952  paintface_flush_flags(vc->C, vc->obact, SELECT);
2953  }
2954  return changed;
2955 }
2956 
2957 static void do_nurbs_box_select__doSelect(void *userData,
2958  Nurb *UNUSED(nu),
2959  BPoint *bp,
2960  BezTriple *bezt,
2961  int beztindex,
2962  bool handles_visible,
2963  const float screen_co[2])
2964 {
2965  BoxSelectUserData *data = userData;
2966 
2967  const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
2968  if (bp) {
2969  const bool is_select = bp->f1 & SELECT;
2970  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
2971  if (sel_op_result != -1) {
2972  SET_FLAG_FROM_TEST(bp->f1, sel_op_result, data->select_flag);
2973  data->is_changed = true;
2974  }
2975  }
2976  else {
2977  if (!handles_visible) {
2978  /* can only be (beztindex == 1) here since handles are hidden */
2979  const bool is_select = bezt->f2 & SELECT;
2980  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
2981  if (sel_op_result != -1) {
2982  SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, data->select_flag);
2983  data->is_changed = true;
2984  }
2985  bezt->f1 = bezt->f3 = bezt->f2;
2986  }
2987  else {
2988  uint8_t *flag_p = (&bezt->f1) + beztindex;
2989  const bool is_select = *flag_p & SELECT;
2990  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
2991  if (sel_op_result != -1) {
2992  SET_FLAG_FROM_TEST(*flag_p, sel_op_result, data->select_flag);
2993  data->is_changed = true;
2994  }
2995  }
2996  }
2997 }
2998 static bool do_nurbs_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op)
2999 {
3000  const bool deselect_all = (sel_op == SEL_OP_SET);
3002 
3003  view3d_userdata_boxselect_init(&data, vc, rect, sel_op);
3004 
3005  Curve *curve = (Curve *)vc->obedit->data;
3007 
3008  /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */
3009  if (deselect_all) {
3011  data.select_flag = BEZT_FLAG_TEMP_TAG;
3012  }
3013 
3014  ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
3016 
3017  /* Deselect items that were not added to selection (indicated by temp flag). */
3018  if (deselect_all) {
3020  }
3021 
3023 
3024  return data.is_changed;
3025 }
3026 
3027 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, const float screen_co[2])
3028 {
3029  BoxSelectUserData *data = userData;
3030  const bool is_select = bp->f1 & SELECT;
3031  const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
3032  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
3033  if (sel_op_result != -1) {
3034  SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT);
3035  data->is_changed = true;
3036  }
3037 }
3038 static bool do_lattice_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op)
3039 {
3041 
3042  view3d_userdata_boxselect_init(&data, vc, rect, sel_op);
3043 
3044  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3045  data.is_changed |= ED_lattice_flags_set(vc->obedit, 0);
3046  }
3047 
3048  ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
3051 
3052  return data.is_changed;
3053 }
3054 
3055 static void do_mesh_box_select__doSelectVert(void *userData,
3056  BMVert *eve,
3057  const float screen_co[2],
3058  int UNUSED(index))
3059 {
3060  BoxSelectUserData *data = userData;
3061  const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
3062  const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
3063  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
3064  if (sel_op_result != -1) {
3065  BM_vert_select_set(data->vc->em->bm, eve, sel_op_result);
3066  data->is_changed = true;
3067  }
3068 }
3073 };
3075  void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
3076 {
3077  struct BoxSelectUserData_ForMeshEdge *data_for_edge = userData;
3078  BoxSelectUserData *data = data_for_edge->data;
3079  bool is_visible = true;
3080  if (data_for_edge->backbuf_offset) {
3081  uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1;
3082  is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx);
3083  }
3084 
3085  const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
3086  const bool is_inside = (is_visible &&
3087  edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b));
3088  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
3089  if (sel_op_result != -1) {
3090  BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
3091  data->is_done = true;
3092  data->is_changed = true;
3093  }
3094 }
3096  void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
3097 {
3098  struct BoxSelectUserData_ForMeshEdge *data_for_edge = userData;
3099  BoxSelectUserData *data = data_for_edge->data;
3100  bool is_visible = true;
3101  if (data_for_edge->backbuf_offset) {
3102  uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1;
3103  is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx);
3104  }
3105 
3106  const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
3107  const bool is_inside = (is_visible && edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b));
3108  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
3109  if (sel_op_result != -1) {
3110  BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
3111  data->is_changed = true;
3112  }
3113 }
3114 static void do_mesh_box_select__doSelectFace(void *userData,
3115  BMFace *efa,
3116  const float screen_co[2],
3117  int UNUSED(index))
3118 {
3119  BoxSelectUserData *data = userData;
3120  const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
3121  const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
3122  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
3123  if (sel_op_result != -1) {
3124  BM_face_select_set(data->vc->em->bm, efa, sel_op_result);
3125  data->is_changed = true;
3126  }
3127 }
3129  wmGenericUserData *wm_userdata,
3130  const rcti *rect,
3131  const eSelectOp sel_op)
3132 {
3134  ToolSettings *ts = vc->scene->toolsettings;
3135 
3136  view3d_userdata_boxselect_init(&data, vc, rect, sel_op);
3137 
3138  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3139  if (vc->em->bm->totvertsel) {
3141  data.is_changed = true;
3142  }
3143  }
3144 
3145  /* for non zbuf projections, don't change the GL state */
3147 
3148  GPU_matrix_set(vc->rv3d->viewmat);
3149 
3150  const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d);
3151 
3152  struct EditSelectBuf_Cache *esel = wm_userdata->data;
3153  if (use_zbuf) {
3154  if (wm_userdata->data == NULL) {
3156  esel = wm_userdata->data;
3158  vc->depsgraph, vc->region, vc->v3d, rect, NULL);
3159  }
3160  }
3161 
3162  if (ts->selectmode & SCE_SELECT_VERTEX) {
3163  if (use_zbuf) {
3165  esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
3166  }
3167  else {
3170  }
3171  }
3172  if (ts->selectmode & SCE_SELECT_EDGE) {
3173  /* Does both use_zbuf and non-use_zbuf versions (need screen cos for both) */
3174  struct BoxSelectUserData_ForMeshEdge cb_data = {
3175  .data = &data,
3176  .esel = use_zbuf ? esel : NULL,
3177  .backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem(
3178  vc->depsgraph, vc->obedit, SCE_SELECT_EDGE) :
3179  0,
3180  };
3181 
3182  const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR |
3183  (use_zbuf ? 0 : V3D_PROJ_TEST_CLIP_BB);
3185  vc, do_mesh_box_select__doSelectEdge_pass0, &cb_data, clip_flag);
3186  if (data.is_done == false) {
3188  vc, do_mesh_box_select__doSelectEdge_pass1, &cb_data, clip_flag);
3189  }
3190  }
3191 
3192  if (ts->selectmode & SCE_SELECT_FACE) {
3193  if (use_zbuf) {
3195  esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
3196  }
3197  else {
3200  }
3201  }
3202 
3203  if (data.is_changed) {
3205  }
3206  return data.is_changed;
3207 }
3208 
3209 static bool do_meta_box_select(ViewContext *vc, const rcti *rect, const eSelectOp sel_op)
3210 {
3211  Object *ob = vc->obedit;
3212  MetaBall *mb = (MetaBall *)ob->data;
3213  MetaElem *ml;
3214  int a;
3215  bool changed = false;
3216 
3218  int hits;
3219 
3220  hits = view3d_opengl_select(
3222 
3223  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3224  changed |= BKE_mball_deselect_all(mb);
3225  }
3226 
3227  int metaelem_id = 0;
3228  for (ml = mb->editelems->first; ml; ml = ml->next, metaelem_id += 0x10000) {
3229  bool is_inside_radius = false;
3230  bool is_inside_stiff = false;
3231 
3232  for (a = 0; a < hits; a++) {
3233  int hitresult = buffer[(4 * a) + 3];
3234 
3235  if (hitresult == -1) {
3236  continue;
3237  }
3238 
3239  const uint hit_object = hitresult & 0xFFFF;
3240  if (vc->obedit->runtime.select_id != hit_object) {
3241  continue;
3242  }
3243 
3244  if (metaelem_id != (hitresult & 0xFFFF0000 & ~MBALLSEL_ANY)) {
3245  continue;
3246  }
3247 
3248  if (hitresult & MBALLSEL_RADIUS) {
3249  is_inside_radius = true;
3250  break;
3251  }
3252 
3253  if (hitresult & MBALLSEL_STIFF) {
3254  is_inside_stiff = true;
3255  break;
3256  }
3257  }
3258  const int flag_prev = ml->flag;
3259  if (is_inside_radius) {
3260  ml->flag |= MB_SCALE_RAD;
3261  }
3262  if (is_inside_stiff) {
3263  ml->flag &= ~MB_SCALE_RAD;
3264  }
3265 
3266  const bool is_select = (ml->flag & SELECT);
3267  const bool is_inside = is_inside_radius || is_inside_stiff;
3268 
3269  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
3270  if (sel_op_result != -1) {
3271  SET_FLAG_FROM_TEST(ml->flag, sel_op_result, SELECT);
3272  }
3273  changed |= (flag_prev != ml->flag);
3274  }
3275 
3276  return changed;
3277 }
3278 
3279 static bool do_armature_box_select(ViewContext *vc, const rcti *rect, const eSelectOp sel_op)
3280 {
3281  bool changed = false;
3282  int a;
3283 
3285  int hits;
3286 
3287  hits = view3d_opengl_select(
3289 
3290  uint bases_len = 0;
3292  vc->view_layer, vc->v3d, &bases_len);
3293 
3294  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3295  changed |= ED_armature_edit_deselect_all_visible_multi_ex(bases, bases_len);
3296  }
3297 
3298  for (uint base_index = 0; base_index < bases_len; base_index++) {
3299  Object *obedit = bases[base_index]->object;
3300  obedit->id.tag &= ~LIB_TAG_DOIT;
3301 
3302  bArmature *arm = obedit->data;
3304  }
3305 
3306  /* first we only check points inside the border */
3307  for (a = 0; a < hits; a++) {
3308  int select_id = buffer[(4 * a) + 3];
3309  if (select_id != -1) {
3310  if ((select_id & 0xFFFF0000) == 0) {
3311  continue;
3312  }
3313 
3314  EditBone *ebone;
3316  bases, bases_len, select_id, &ebone);
3317  ebone->temp.i |= select_id & BONESEL_ANY;
3318  base_edit->object->id.tag |= LIB_TAG_DOIT;
3319  }
3320  }
3321 
3322  for (uint base_index = 0; base_index < bases_len; base_index++) {
3323  Object *obedit = bases[base_index]->object;
3324  if (obedit->id.tag & LIB_TAG_DOIT) {
3325  obedit->id.tag &= ~LIB_TAG_DOIT;
3326  changed |= ED_armature_edit_select_op_from_tagged(obedit->data, sel_op);
3327  }
3328  }
3329 
3330  MEM_freeN(bases);
3331 
3332  return changed;
3333 }
3334 
3339 static int opengl_bone_select_buffer_cmp(const void *sel_a_p, const void *sel_b_p)
3340 {
3341  /* 4th element is select id */
3342  uint sel_a = ((uint *)sel_a_p)[3];
3343  uint sel_b = ((uint *)sel_b_p)[3];
3344 
3345 #ifdef __BIG_ENDIAN__
3346  BLI_endian_switch_uint32(&sel_a);
3347  BLI_endian_switch_uint32(&sel_b);
3348 #endif
3349 
3350  if (sel_a < sel_b) {
3351  return -1;
3352  }
3353  if (sel_a > sel_b) {
3354  return 1;
3355  }
3356  return 0;
3357 }
3358 
3359 static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const eSelectOp sel_op)
3360 {
3361  View3D *v3d = vc->v3d;
3362  int totobj = MAXPICKBUF; /* XXX solve later */
3363 
3364  /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
3365  uint *vbuffer = MEM_mallocN(4 * (totobj + MAXPICKELEMS) * sizeof(uint[4]), "selection buffer");
3367  vc->obact);
3368  const int hits = view3d_opengl_select(
3369  vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter);
3370 
3371  LISTBASE_FOREACH (Base *, base, &vc->view_layer->object_bases) {
3372  base->object->id.tag &= ~LIB_TAG_DOIT;
3373  }
3374 
3375  Base **bases = NULL;
3376  BLI_array_declare(bases);
3377 
3378  bool changed = false;
3379  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3380  changed |= object_deselect_all_visible(vc->view_layer, vc->v3d);
3381  }
3382 
3383  if ((hits == -1) && !SEL_OP_USE_OUTSIDE(sel_op)) {
3384  goto finally;
3385  }
3386 
3387  LISTBASE_FOREACH (Base *, base, &vc->view_layer->object_bases) {
3388  if (BASE_SELECTABLE(v3d, base)) {
3389  if ((base->object->runtime.select_id & 0x0000FFFF) != 0) {
3390  BLI_array_append(bases, base);
3391  }
3392  }
3393  }
3394 
3395  /* The draw order doesn't always match the order we populate the engine, see: T51695. */
3396  qsort(vbuffer, hits, sizeof(uint[4]), opengl_bone_select_buffer_cmp);
3397 
3398  for (const uint *col = vbuffer + 3, *col_end = col + (hits * 4); col < col_end; col += 4) {
3399  bPoseChannel *pchan_dummy;
3401  bases, BLI_array_len(bases), *col, &pchan_dummy);
3402  if (base != NULL) {
3403  base->object->id.tag |= LIB_TAG_DOIT;
3404  }
3405  }
3406 
3407  for (Base *base = vc->view_layer->object_bases.first; base && hits; base = base->next) {
3408  if (BASE_SELECTABLE(v3d, base)) {
3409  const bool is_select = base->flag & BASE_SELECTED;
3410  const bool is_inside = base->object->id.tag & LIB_TAG_DOIT;
3411  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
3412  if (sel_op_result != -1) {
3413  ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT);
3414  changed = true;
3415  }
3416  }
3417  }
3418 
3419 finally:
3420  if (bases != NULL) {
3421  MEM_freeN(bases);
3422  }
3423 
3424  MEM_freeN(vbuffer);
3425 
3426  if (changed) {
3429  }
3430  return changed;
3431 }
3432 
3433 static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const eSelectOp sel_op)
3434 {
3435  uint bases_len;
3436  Base **bases = do_pose_tag_select_op_prepare(vc, &bases_len);
3437 
3438  int totobj = MAXPICKBUF; /* XXX solve later */
3439 
3440  /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
3441  uint *vbuffer = MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(uint[4]), "selection buffer");
3443  vc->obact);
3444  const int hits = view3d_opengl_select(
3445  vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter);
3446  /*
3447  * LOGIC NOTES (theeth):
3448  * The buffer and ListBase have the same relative order, which makes the selection
3449  * very simple. Loop through both data sets at the same time, if the color
3450  * is the same as the object, we have a hit and can move to the next color
3451  * and object pair, if not, just move to the next object,
3452  * keeping the same color until we have a hit.
3453  */
3454 
3455  if (hits > 0) {
3456  /* no need to loop if there's no hit */
3457 
3458  /* The draw order doesn't always match the order we populate the engine, see: T51695. */
3459  qsort(vbuffer, hits, sizeof(uint[4]), opengl_bone_select_buffer_cmp);
3460 
3461  for (const uint *col = vbuffer + 3, *col_end = col + (hits * 4); col < col_end; col += 4) {
3462  Bone *bone;
3463  Base *base = ED_armature_base_and_bone_from_select_buffer(bases, bases_len, *col, &bone);
3464 
3465  if (base == NULL) {
3466  continue;
3467  }
3468 
3469  /* Loop over contiguous bone hits for 'base'. */
3470  for (; col != col_end; col += 4) {
3471  /* should never fail */
3472  if (bone != NULL) {
3473  base->object->id.tag |= LIB_TAG_DOIT;
3474  bone->flag |= BONE_DONE;
3475  }
3476 
3477  /* Select the next bone if we're not switching bases. */
3478  if (col + 4 != col_end) {
3479  if ((base->object->runtime.select_id & 0x0000FFFF) != (col[4] & 0x0000FFFF)) {
3480  break;
3481  }
3482  if (base->object->pose != NULL) {
3483  const uint hit_bone = (col[4] & ~BONESEL_ANY) >> 16;
3484  bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone);
3485  bone = pchan ? pchan->bone : NULL;
3486  }
3487  else {
3488  bone = NULL;
3489  }
3490  }
3491  }
3492  }
3493  }
3494 
3495  const bool changed_multi = do_pose_tag_select_op_exec(bases, bases_len, sel_op);
3496  if (changed_multi) {
3499  }
3500 
3501  if (bases != NULL) {
3502  MEM_freeN(bases);
3503  }
3504  MEM_freeN(vbuffer);
3505 
3506  return changed_multi;
3507 }
3508 
3510 {
3512  ViewContext vc;
3513  rcti rect;
3514  bool changed_multi = false;
3515 
3516  wmGenericUserData wm_userdata_buf = {0};
3517  wmGenericUserData *wm_userdata = &wm_userdata_buf;
3518 
3521 
3522  /* setup view context for argument to callbacks */
3524 
3525  eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
3527 
3528  if (vc.obedit) {
3530  vc.view_layer, vc.v3d, vc.obedit->type, vc.obedit->mode, ob_iter) {
3531  ED_view3d_viewcontext_init_object(&vc, ob_iter);
3532  bool changed = false;
3533 
3534  switch (vc.obedit->type) {
3535  case OB_MESH:
3537  changed = do_mesh_box_select(&vc, wm_userdata, &rect, sel_op);
3538  if (changed) {
3541  }
3542  break;
3543  case OB_CURVE:
3544  case OB_SURF:
3545  changed = do_nurbs_box_select(&vc, &rect, sel_op);
3546  if (changed) {
3549  }
3550  break;
3551  case OB_MBALL:
3552  changed = do_meta_box_select(&vc, &rect, sel_op);
3553  if (changed) {
3556  }
3557  break;
3558  case OB_ARMATURE:
3559  changed = do_armature_box_select(&vc, &rect, sel_op);
3560  if (changed) {
3564  }
3565  break;
3566  case OB_LATTICE:
3567  changed = do_lattice_box_select(&vc, &rect, sel_op);
3568  if (changed) {
3571  }
3572  break;
3573  default:
3574  BLI_assert(!"box select on incorrect object type");
3575  break;
3576  }
3577  changed_multi |= changed;
3578  }
3580  }
3581  else { /* No edit-mode, unified for bones and objects. */
3582  if (vc.obact && BKE_paint_select_face_test(vc.obact)) {
3583  changed_multi = do_paintface_box_select(&vc, wm_userdata, &rect, sel_op);
3584  }
3585  else if (vc.obact && BKE_paint_select_vert_test(vc.obact)) {
3586  changed_multi = do_paintvert_box_select(&vc, wm_userdata, &rect, sel_op);
3587  }
3588  else if (vc.obact && vc.obact->mode & OB_MODE_PARTICLE_EDIT) {
3589  changed_multi = PE_box_select(C, &rect, sel_op);
3590  }
3591  else if (vc.obact && vc.obact->mode & OB_MODE_POSE) {
3592  changed_multi = do_pose_box_select(C, &vc, &rect, sel_op);
3593  if (changed_multi) {
3595  }
3596  }
3597  else { /* object mode with none active */
3598  changed_multi = do_object_box_select(C, &vc, &rect, sel_op);
3599  if (changed_multi) {
3601  }
3602  }
3603  }
3604 
3605  WM_generic_user_data_free(wm_userdata);
3606 
3607  if (changed_multi) {
3608  return OPERATOR_FINISHED;
3609  }
3610  return OPERATOR_CANCELLED;
3611 }
3612 
3614 {
3615  /* identifiers */
3616  ot->name = "Box Select";
3617  ot->description = "Select items using box selection";
3618  ot->idname = "VIEW3D_OT_select_box";
3619 
3620  /* api callbacks */
3626 
3627  /* flags */
3628  ot->flag = OPTYPE_UNDO;
3629 
3630  /* rna */
3633 }
3634 
3637 /* -------------------------------------------------------------------- */
3641 typedef struct CircleSelectUserData {
3643  bool select;
3644  int mval[2];
3645  float mval_fl[2];
3646  float radius;
3649 
3650  /* runtime */
3653 
3655  ViewContext *vc,
3656  const bool select,
3657  const int mval[2],
3658  const float rad)
3659 {
3660  r_data->vc = vc;
3661  r_data->select = select;
3662  copy_v2_v2_int(r_data->mval, mval);
3663  r_data->mval_fl[0] = mval[0];
3664  r_data->mval_fl[1] = mval[1];
3665 
3666  r_data->radius = rad;
3667  r_data->radius_squared = rad * rad;
3668 
3669  /* SELECT by default, but can be changed if needed (only few cases use and respect this). */
3670  r_data->select_flag = SELECT;
3671 
3672  /* runtime */
3673  r_data->is_changed = false;
3674 }
3675 
3676 static void mesh_circle_doSelectVert(void *userData,
3677  BMVert *eve,
3678  const float screen_co[2],
3679  int UNUSED(index))
3680 {
3681  CircleSelectUserData *data = userData;
3682 
3683  if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
3684  BM_vert_select_set(data->vc->em->bm, eve, data->select);
3685  data->is_changed = true;
3686  }
3687 }
3688 static void mesh_circle_doSelectEdge(void *userData,
3689  BMEdge *eed,
3690  const float screen_co_a[2],
3691  const float screen_co_b[2],
3692  int UNUSED(index))
3693 {
3694  CircleSelectUserData *data = userData;
3695 
3696  if (edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) {
3697  BM_edge_select_set(data->vc->em->bm, eed, data->select);
3698  data->is_changed = true;
3699  }
3700 }
3701 static void mesh_circle_doSelectFace(void *userData,
3702  BMFace *efa,
3703  const float screen_co[2],
3704  int UNUSED(index))
3705 {
3706  CircleSelectUserData *data = userData;
3707 
3708  if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
3709  BM_face_select_set(data->vc->em->bm, efa, data->select);
3710  data->is_changed = true;
3711  }
3712 }
3713 
3715  wmGenericUserData *wm_userdata,
3716  eSelectOp sel_op,
3717  const int mval[2],
3718  float rad)
3719 {
3720  ToolSettings *ts = vc->scene->toolsettings;
3722  vc->em = BKE_editmesh_from_object(vc->obedit);
3723 
3724  bool changed = false;
3725  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3726  if (vc->em->bm->totvertsel) {
3728  changed = true;
3729  }
3730  }
3731  const bool select = (sel_op != SEL_OP_SUB);
3732 
3733  ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
3734 
3735  view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
3736 
3737  const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d);
3738 
3739  if (use_zbuf) {
3740  if (wm_userdata->data == NULL) {
3742  }
3743  }
3744  struct EditSelectBuf_Cache *esel = wm_userdata->data;
3745 
3746  if (use_zbuf) {
3747  if (esel->select_bitmap == NULL) {
3749  vc->depsgraph, vc->region, vc->v3d, mval, (int)(rad + 1.0f), NULL);
3750  }
3751  }
3752 
3753  if (ts->selectmode & SCE_SELECT_VERTEX) {
3754  if (use_zbuf) {
3755  if (esel->select_bitmap != NULL) {
3757  esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
3758  }
3759  }
3760  else {
3762  }
3763  }
3764 
3765  if (ts->selectmode & SCE_SELECT_EDGE) {
3766  if (use_zbuf) {
3767  if (esel->select_bitmap != NULL) {
3769  esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
3770  }
3771  }
3772  else {
3775  }
3776  }
3777 
3778  if (ts->selectmode & SCE_SELECT_FACE) {
3779  if (use_zbuf) {
3780  if (esel->select_bitmap != NULL) {
3782  esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
3783  }
3784  }
3785  else {
3787  }
3788  }
3789 
3790  changed |= data.is_changed;
3791 
3792  if (changed) {
3794  }
3795  return changed;
3796 }
3797 
3799  wmGenericUserData *wm_userdata,
3800  const eSelectOp sel_op,
3801  const int mval[2],
3802  float rad)
3803 {
3805  Object *ob = vc->obact;
3806  Mesh *me = ob->data;
3807 
3808  bool changed = false;
3809  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3810  /* flush selection at the end */
3811  changed |= paintface_deselect_all_visible(vc->C, ob, SEL_DESELECT, false);
3812  }
3813 
3814  if (wm_userdata->data == NULL) {
3816  }
3817 
3818  {
3819  struct EditSelectBuf_Cache *esel = wm_userdata->data;
3821  vc->depsgraph, vc->region, vc->v3d, mval, (int)(rad + 1.0f), NULL);
3822  if (esel->select_bitmap != NULL) {
3823  changed |= edbm_backbuf_check_and_select_faces_obmode(me, esel, sel_op);
3824  MEM_freeN(esel->select_bitmap);
3825  esel->select_bitmap = NULL;
3826  }
3827  }
3828 
3829  if (changed) {
3830  paintface_flush_flags(vc->C, ob, SELECT);
3831  }
3832  return changed;
3833 }
3834 
3835 static void paint_vertsel_circle_select_doSelectVert(void *userData,
3836  MVert *mv,
3837  const float screen_co[2],
3838  int UNUSED(index))
3839 {
3840  CircleSelectUserData *data = userData;
3841 
3842  if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
3843  SET_FLAG_FROM_TEST(mv->flag, data->select, SELECT);
3844  data->is_changed = true;
3845  }
3846 }
3848  wmGenericUserData *wm_userdata,
3849  const eSelectOp sel_op,
3850  const int mval[2],
3851  float rad)
3852 {
3854  const bool use_zbuf = !XRAY_ENABLED(vc->v3d);
3855  Object *ob = vc->obact;
3856  Mesh *me = ob->data;
3857  /* CircleSelectUserData data = {NULL}; */ /* UNUSED */
3858 
3859  bool changed = false;
3860  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3861  /* Flush selection at the end. */
3862  changed |= paintvert_deselect_all_visible(ob, SEL_DESELECT, false);
3863  }
3864 
3865  const bool select = (sel_op != SEL_OP_SUB);
3866 
3867  if (use_zbuf) {
3868  if (wm_userdata->data == NULL) {
3870  }
3871  }
3872 
3873  if (use_zbuf) {
3874  struct EditSelectBuf_Cache *esel = wm_userdata->data;
3876  vc->depsgraph, vc->region, vc->v3d, mval, (int)(rad + 1.0f), NULL);
3877  if (esel->select_bitmap != NULL) {
3878  changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op);
3879  MEM_freeN(esel->select_bitmap);
3880  esel->select_bitmap = NULL;
3881  }
3882  }
3883  else {
3885 
3886  ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */
3887 
3888  view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
3891  changed |= data.is_changed;
3892  }
3893 
3894  if (changed) {
3895  if (sel_op == SEL_OP_SUB) {
3897  }
3899  paintvert_tag_select_update(vc->C, ob);
3900  }
3901  return changed;
3902 }
3903 
3904 static void nurbscurve_circle_doSelect(void *userData,
3905  Nurb *UNUSED(nu),
3906  BPoint *bp,
3907  BezTriple *bezt,
3908  int beztindex,
3909  bool UNUSED(handles_visible),
3910  const float screen_co[2])
3911 {
3912  CircleSelectUserData *data = userData;
3913 
3914  if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
3915  if (bp) {
3916  SET_FLAG_FROM_TEST(bp->f1, data->select, data->select_flag);
3917  }
3918  else {
3919  if (beztindex == 0) {
3920  SET_FLAG_FROM_TEST(bezt->f1, data->select, data->select_flag);
3921  }
3922  else if (beztindex == 1) {
3923  SET_FLAG_FROM_TEST(bezt->f2, data->select, data->select_flag);
3924  }
3925  else {
3926  SET_FLAG_FROM_TEST(bezt->f3, data->select, data->select_flag);
3927  }
3928  }
3929  data->is_changed = true;
3930  }
3931 }
3933  const eSelectOp sel_op,
3934  const int mval[2],
3935  float rad)
3936 {
3937  const bool select = (sel_op != SEL_OP_SUB);
3938  const bool deselect_all = (sel_op == SEL_OP_SET);
3940 
3941  view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
3942 
3943  Curve *curve = (Curve *)vc->obedit->data;
3945 
3946  /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */
3947  if (deselect_all) {
3949  data.select_flag = BEZT_FLAG_TEMP_TAG;
3950  }
3951 
3952  ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
3954 
3955  /* Deselect items that were not added to selection (indicated by temp flag). */
3956  if (deselect_all) {
3958  }
3959 
3961 
3962  return data.is_changed;
3963 }
3964 
3965 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, const float screen_co[2])
3966 {
3967  CircleSelectUserData *data = userData;
3968 
3969  if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
3970  bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
3971  data->is_changed = true;
3972  }
3973 }
3975  const eSelectOp sel_op,
3976  const int mval[2],
3977  float rad)
3978 {
3980  const bool select = (sel_op != SEL_OP_SUB);
3981 
3982  view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
3983 
3984  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3985  data.is_changed |= ED_lattice_flags_set(vc->obedit, 0);
3986  }
3987  ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
3988 
3990 
3991  return data.is_changed;
3992 }
3993 
3994 /* NOTE: pose-bone case is copied from editbone case... */
3995 static bool pchan_circle_doSelectJoint(void *userData,
3996  bPoseChannel *pchan,
3997  const float screen_co[2])
3998 {
3999  CircleSelectUserData *data = userData;
4000 
4001  if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
4002  if (data->select) {
4003  pchan->bone->flag |= BONE_SELECTED;
4004  }
4005  else {
4006  pchan->bone->flag &= ~BONE_SELECTED;
4007  }
4008  return 1;
4009  }
4010  return 0;
4011 }
4012 static void do_circle_select_pose__doSelectBone(void *userData,
4013  struct bPoseChannel *pchan,
4014  const float screen_co_a[2],
4015  const float screen_co_b[2])
4016 {
4017  CircleSelectUserData *data = userData;
4018  bArmature *arm = data->vc->obact->data;
4019 
4020  if (PBONE_SELECTABLE(arm, pchan->bone)) {
4021  bool is_point_done = false;
4022  int points_proj_tot = 0;
4023 
4024  /* project head location to screenspace */
4025  if (screen_co_a[0] != IS_CLIPPED) {
4026  points_proj_tot++;
4027  if (pchan_circle_doSelectJoint(data, pchan, screen_co_a)) {
4028  is_point_done = true;
4029  }
4030  }
4031 
4032  /* project tail location to screenspace */
4033  if (screen_co_b[0] != IS_CLIPPED) {
4034  points_proj_tot++;
4035  if (pchan_circle_doSelectJoint(data, pchan, screen_co_b)) {
4036  is_point_done = true;
4037  }
4038  }
4039 
4040  /* check if the head and/or tail is in the circle
4041  * - the call to check also does the selection already
4042  */
4043 
4044  /* only if the endpoints didn't get selected, deal with the middle of the bone too
4045  * It works nicer to only do this if the head or tail are not in the circle,
4046  * otherwise there is no way to circle select joints alone */
4047  if ((is_point_done == false) && (points_proj_tot == 2) &&
4048  edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) {
4049  if (data->select) {
4050  pchan->bone->flag |= BONE_SELECTED;
4051  }
4052  else {
4053  pchan->bone->flag &= ~BONE_SELECTED;
4054  }
4055  data->is_changed = true;
4056  }
4057 
4058  data->is_changed |= is_point_done;
4059  }
4060 }
4062  const eSelectOp sel_op,
4063  const int mval[2],
4064  float rad)
4065 {
4068  const bool select = (sel_op != SEL_OP_SUB);
4069 
4070  view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
4071 
4072  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
4073  data.is_changed |= ED_pose_deselect_all(vc->obact, SEL_DESELECT, false);
4074  }
4075 
4076  ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */
4077 
4080 
4081  if (data.is_changed) {
4083  }
4084  return data.is_changed;
4085 }
4086 
4087 static bool armature_circle_doSelectJoint(void *userData,
4088  EditBone *ebone,
4089  const float screen_co[2],
4090  bool head)
4091 {
4092  CircleSelectUserData *data = userData;
4093 
4094  if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
4095  if (head) {
4096  if (data->select) {
4097  ebone->flag |= BONE_ROOTSEL;
4098  }
4099  else {
4100  ebone->flag &= ~BONE_ROOTSEL;
4101  }
4102  }
4103  else {
4104  if (data->select) {
4105  ebone->flag |= BONE_TIPSEL;
4106  }
4107  else {
4108  ebone->flag &= ~BONE_TIPSEL;
4109  }
4110  }
4111  return 1;
4112  }
4113  return 0;
4114 }
4115 static void do_circle_select_armature__doSelectBone(void *userData,
4116  struct EditBone *ebone,
4117  const float screen_co_a[2],
4118  const float screen_co_b[2])
4119 {
4120  CircleSelectUserData *data = userData;
4121  bArmature *arm = data->vc->obedit->data;
4122 
4123  if (data->select ? EBONE_SELECTABLE(arm, ebone) : EBONE_VISIBLE(arm, ebone)) {
4124  bool is_point_done = false;
4125  int points_proj_tot = 0;
4126 
4127  /* project head location to screenspace */
4128  if (screen_co_a[0] != IS_CLIPPED) {
4129  points_proj_tot++;
4130  if (armature_circle_doSelectJoint(data, ebone, screen_co_a, true)) {
4131  is_point_done = true;
4132  }
4133  }
4134 
4135  /* project tail location to screenspace */
4136  if (screen_co_b[0] != IS_CLIPPED) {
4137  points_proj_tot++;
4138  if (armature_circle_doSelectJoint(data, ebone, screen_co_b, false)) {
4139  is_point_done = true;
4140  }
4141  }
4142 
4143  /* check if the head and/or tail is in the circle
4144  * - the call to check also does the selection already
4145  */
4146 
4147  /* only if the endpoints didn't get selected, deal with the middle of the bone too
4148  * It works nicer to only do this if the head or tail are not in the circle,
4149  * otherwise there is no way to circle select joints alone */
4150  if ((is_point_done == false) && (points_proj_tot == 2) &&
4151  edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) {
4152  if (data->select) {
4153  ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
4154  }
4155  else {
4156  ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
4157  }
4158  data->is_changed = true;
4159  }
4160 
4161  data->is_changed |= is_point_done;
4162  }
4163 }
4165  const eSelectOp sel_op,
4166  const int mval[2],
4167  float rad)
4168 {
4170  bArmature *arm = vc->obedit->data;
4171 
4172  const bool select = (sel_op != SEL_OP_SUB);
4173 
4174  view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
4175 
4176  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
4178  }
4179 
4181 
4184 
4185  if (data.is_changed) {
4189  }
4190  return data.is_changed;
4191 }
4192 
4193 static void do_circle_select_mball__doSelectElem(void *userData,
4194  struct MetaElem *ml,
4195  const float screen_co[2])
4196 {
4197  CircleSelectUserData *data = userData;
4198 
4199  if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
4200  if (data->select) {
4201  ml->flag |= SELECT;
4202  }
4203  else {
4204  ml->flag &= ~SELECT;
4205  }
4206  data->is_changed = true;
4207  }
4208 }
4210  const eSelectOp sel_op,
4211  const int mval[2],
4212  float rad)
4213 {
4215 
4216  const bool select = (sel_op != SEL_OP_SUB);
4217 
4218  view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
4219 
4220  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
4221  data.is_changed |= BKE_mball_deselect_all(vc->obedit->data);
4222  }
4223 
4225 
4228  return data.is_changed;
4229 }
4230 
4235  ViewContext *vc,
4236  wmGenericUserData *wm_userdata,
4237  const eSelectOp sel_op,
4238  const int mval[2],
4239  float rad)
4240 {
4241  bool changed = false;
4243  switch (vc->obedit->type) {
4244  case OB_MESH:
4245  changed = mesh_circle_select(vc, wm_userdata, sel_op, mval, rad);
4246  break;
4247  case OB_CURVE:
4248  case OB_SURF:
4249  changed = nurbscurve_circle_select(vc, sel_op, mval, rad);
4250  break;
4251  case OB_LATTICE:
4252  changed = lattice_circle_select(vc, sel_op, mval, rad);
4253  break;
4254  case OB_ARMATURE:
4255  changed = armature_circle_select(vc, sel_op, mval, rad);
4256  if (changed) {
4258  }
4259  break;
4260  case OB_MBALL:
4261  changed = mball_circle_select(vc, sel_op, mval, rad);
4262  break;
4263  default:
4264  BLI_assert(0);
4265  break;
4266  }
4267 
4268  if (changed) {
4271  }
4272  return changed;
4273 }
4274 
4276  const eSelectOp sel_op,
4277  const int mval[2],
4278  float rad)
4279 {
4281  ViewLayer *view_layer = vc->view_layer;
4282  View3D *v3d = vc->v3d;
4283 
4284  const float radius_squared = rad * rad;
4285  const float mval_fl[2] = {mval[0], mval[1]};
4286 
4287  bool changed = false;
4288  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
4289  changed |= object_deselect_all_visible(vc->view_layer, vc->v3d);
4290  }
4291  const bool select = (sel_op != SEL_OP_SUB);
4292  const int select_flag = select ? BASE_SELECTED : 0;
4293 
4294  Base *base;
4295  for (base = FIRSTBASE(view_layer); base; base = base->next) {
4296  if (BASE_SELECTABLE(v3d, base) && ((base->flag & BASE_SELECTED) != select_flag)) {
4297  float screen_co[2];
4299  vc->region, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_DEFAULT) ==
4300  V3D_PROJ_RET_OK) {
4301  if (len_squared_v2v2(mval_fl, screen_co) <= radius_squared) {
4303  changed = true;
4304  }
4305  }
4306  }
4307  }
4308 
4309  return changed;
4310 }
4311 
4312 /* not a real operator, only for circle test */
4314 {
4316  ViewContext vc;
4317  const int radius = RNA_int_get(op->ptr, "radius");
4318  const int mval[2] = {RNA_int_get(op->ptr, "x"), RNA_int_get(op->ptr, "y")};
4319 
4320  /* Allow each selection type to allocate their own data that's used between executions. */
4321  wmGesture *gesture = op->customdata; /* NULL when non-modal. */
4322  wmGenericUserData wm_userdata_buf = {0};
4323  wmGenericUserData *wm_userdata = gesture ? &gesture->user_data : &wm_userdata_buf;
4324 
4325  const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
4326  WM_gesture_is_modal_first(gesture));
4327 
4329 
4330  Object *obact = vc.obact;
4331  Object *obedit = vc.obedit;
4332 
4333  if (obedit || BKE_paint_select_elem_test(obact) || (obact && (obact->mode & OB_MODE_POSE))) {
4335  if (obedit == NULL) {
4337  }
4338 
4339  FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, vc.v3d, obact->type, obact->mode, ob_iter) {
4340  ED_view3d_viewcontext_init_object(&vc, ob_iter);
4341 
4342  obact = vc.obact;
4343  obedit = vc.obedit;
4344 
4345  if (obedit) {
4346  obedit_circle_select(C, &vc, wm_userdata, sel_op, mval, (float)radius);
4347  }
4348  else if (BKE_paint_select_face_test(obact)) {
4349  paint_facesel_circle_select(&vc, wm_userdata, sel_op, mval, (float)radius);
4350  }
4351  else if (BKE_paint_select_vert_test(obact)) {
4352  paint_vertsel_circle_select(&vc, wm_userdata, sel_op, mval, (float)radius);
4353  }
4354  else if (obact->mode & OB_MODE_POSE) {
4355  pose_circle_select(&vc, sel_op, mval, (float)radius);
4357  }
4358  else {
4359  BLI_assert(0);
4360  }
4361  }
4363  }
4364  else if (obact && (obact->mode & OB_MODE_PARTICLE_EDIT)) {
4365  if (PE_circle_select(C, sel_op, mval, (float)radius)) {
4366  return OPERATOR_FINISHED;
4367  }
4368  return OPERATOR_CANCELLED;
4369  }
4370  else if (obact && obact->mode & OB_MODE_SCULPT) {
4371  return OPERATOR_CANCELLED;
4372  }
4373  else {
4374  if (object_circle_select(&vc, sel_op, mval, (float)radius)) {
4377 
4379  }
4380  }
4381 
4382  /* Otherwise this is freed by the gesture. */
4383  if (wm_userdata == &wm_userdata_buf) {
4384  WM_generic_user_data_free(wm_userdata);
4385  }
4386  else {
4387  struct EditSelectBuf_Cache *esel = wm_userdata->data;
4388  if (esel && esel->select_bitmap) {
4389  MEM_freeN(esel->select_bitmap);
4390  esel->select_bitmap = NULL;
4391  }
4392  }
4393 
4394  return OPERATOR_FINISHED;
4395 }
4396 
4398 {
4399  ot->name = "Circle Select";
4400  ot->description = "Select items using circle selection";
4401  ot->idname = "VIEW3D_OT_select_circle";
4402 
4408 
4409  /* flags */
4410  ot->flag = OPTYPE_UNDO;
4411 
4412  /* properties */
4415 }
4416 
typedef float(TangentPoint)[2]
#define PBONE_SELECTABLE(arm, bone)
Definition: BKE_armature.h:343
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1296
#define CTX_DATA_BEGIN(C, Type, instance, member)
Definition: BKE_context.h:252
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1424
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1279
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:760
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
struct RegionView3D * CTX_wm_region_view3d(const bContext *C)
Definition: context.c:769
#define CTX_DATA_END
Definition: BKE_context.h:260
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
bool BKE_nurbList_flag_set_from_flag(ListBase *editnurb, uint8_t from_flag, uint8_t flag)
Definition: curve.c:4513
struct ListBase * BKE_curve_editNurbs_get(struct Curve *cu)
Definition: curve.c:437
void BKE_curve_nurb_vert_active_validate(struct Curve *cu)
Definition: curve.c:5173
void BKE_nurbList_flag_set(ListBase *editnurb, uint8_t flag, bool set)
Definition: curve.c:4475
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:85
#define FOREACH_BASE_IN_MODE_END
Definition: BKE_layer.h:270
#define BKE_view_layer_array_from_bases_in_edit_mode(view_layer, v3d, r_len)
Definition: BKE_layer.h:423
#define FOREACH_OBJECT_IN_MODE_END
Definition: BKE_layer.h:284
struct Base * BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob)
Definition: layer.c:394
#define BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:430
#define FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _v3d, _object_type, _object_mode, _instance)
Definition: BKE_layer.h:254
#define FOREACH_OBJECT_IN_MODE_BEGIN(_view_layer, _v3d, _object_type, _object_mode, _instance)
Definition: BKE_layer.h:280
bool BKE_mball_deselect_all(struct MetaBall *mb)
Definition: mball.c:696
struct Mesh * BKE_mesh_from_object(struct Object *ob)
Definition: mesh.c:1271
void BKE_mesh_mselect_active_set(struct Mesh *me, int index, int type)
Definition: mesh.c:1705
void BKE_mesh_mselect_validate(struct Mesh *me)
Definition: mesh.c:1617
General operations, lookup, etc. for blender objects.
struct MovieClip * BKE_object_movieclip_get(struct Scene *scene, struct Object *ob, bool use_default)
Definition: object.c:5079
void BKE_object_update_select_id(struct Main *bmain)
Definition: object.c:5654
struct Object * BKE_object_pose_armature_get(struct Object *ob)
Definition: object.c:2487
bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode)
Definition: object.c:1982
bool BKE_object_is_in_editmode(const struct Object *ob)
bool BKE_paint_select_elem_test(struct Object *ob)
Definition: paint.c:987
bool BKE_paint_select_vert_test(struct Object *ob)
Definition: paint.c:976
bool BKE_paint_select_face_test(struct Object *ob)
Definition: paint.c:968
void BKE_tracking_track_deselect(struct MovieTrackingTrack *track, int area)
Definition: tracking.c:1367
#define TRACK_AREA_ALL
Definition: BKE_tracking.h:524
#define TRACK_SELECTED(track)
Definition: BKE_tracking.h:489
void BKE_tracking_track_select(struct ListBase *tracksbase, struct MovieTrackingTrack *track, int area, bool extend)
Definition: tracking.c:1340
struct MovieTrackingTrack * BKE_tracking_track_get_indexed(struct MovieTracking *tracking, int tracknr, struct ListBase **r_tracksbase)
Definition: tracking.c:1137
struct ListBase * BKE_tracking_object_get_tracks(struct MovieTracking *tracking, struct MovieTrackingObject *object)
Definition: tracking.c:2218
A (mainly) macro array library.
#define BLI_array_append(arr, item)
Definition: BLI_array.h:104
#define BLI_array_declare(arr)
Definition: BLI_array.h:62
#define BLI_array_len(arr)
Definition: BLI_array.h:74
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_BITMAP_TEST_BOOL(_bitmap, _index)
Definition: BLI_bitmap.h:73
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:32
BLI_INLINE void BLI_endian_switch_uint32(unsigned int *val) ATTR_NONNULL(1)
struct GSet GSet
Definition: BLI_ghash.h:189
GSet * BLI_gset_ptr_new(const char *info)
void BLI_gset_insert(GSet *gs, void *key)
Definition: BLI_ghash.c:1147
bool BLI_gset_haskey(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1216
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1253
void BLI_lasso_boundbox(struct rcti *rect, const int mcoords[][2], const unsigned int mcoords_len)
Definition: lasso_2d.c:31
bool BLI_lasso_is_edge_inside(const int mcoords[][2], const unsigned int mcoords_len, int x0, int y0, int x1, int y1, const int error_value)
Definition: lasso_2d.c:69
bool BLI_lasso_is_point_inside(const int mcoords[][2], const unsigned int mcoords_len, const int sx, const int sy, const int error_value)
Definition: lasso_2d.c:54
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:338
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
MINLINE int len_manhattan_v2v2_int(const int a[2], const int b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_manhattan_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE int len_manhattan_v2_int(const int v[2]) ATTR_WARN_UNUSED_RESULT
bool BLI_rcti_isect_pt_v(const struct rcti *rect, const int xy[2])
bool BLI_rctf_isect_pt_v(const struct rctf *rect, const float xy[2])
void BLI_rcti_init_pt_radius(struct rcti *rect, const int xy[2], int size)
Definition: rct.c:508
bool BLI_rcti_isect_pt(const struct rcti *rect, const int x, const int y)
void BLI_rctf_rcti_copy(struct rctf *dst, const struct rcti *src)
bool BLI_rcti_is_empty(const struct rcti *rect)
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNPACK2(a)
#define UNUSED_VARS_NDEBUG(...)
#define UNUSED(x)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
#define STREQ(a, b)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_SELECT
Definition: DNA_ID.h:638
@ ID_RECALC_BASE_FLAGS
Definition: DNA_ID.h:641
@ LIB_TAG_DOIT
Definition: DNA_ID.h:554
#define MAX_ID_NAME
Definition: DNA_ID.h:269
@ BONE_ROOTSEL
@ BONE_SELECTED
@ BONE_UNSELECTABLE
@ BONE_DONE
@ BONE_TIPSEL
eBezTriple_Flag
@ BEZT_FLAG_TEMP_TAG
@ BASE_SELECTABLE
@ BASE_VISIBLE_VIEWLAYER
@ BASE_SELECTED
@ ME_VSEL
@ ME_HIDE
@ ME_FACE_SEL
#define MB_SCALE_RAD
#define OB_MODE_ALL_WEIGHT_PAINT
eObjectMode
@ OB_MODE_VERTEX_GPENCIL
@ OB_MODE_PARTICLE_EDIT
@ OB_MODE_EDIT
@ OB_MODE_WEIGHT_PAINT
@ OB_MODE_WEIGHT_GPENCIL
@ OB_MODE_SCULPT
@ OB_MODE_SCULPT_GPENCIL
@ OB_MODE_POSE
@ OB_MODE_TEXTURE_PAINT
@ OB_MODE_OBJECT
@ OB_MODE_VERTEX_PAINT
@ OB_MODE_PAINT_GPENCIL
Object is a sort of wrapper for general info.
@ OB_LATTICE
@ OB_MBALL
@ OB_SURF
@ OB_CAMERA
@ OB_FONT
@ OB_ARMATURE
@ OB_MESH
@ OB_CURVE
@ OB_GPENCIL
@ SCE_OBJECT_MODE_LOCK
#define FIRSTBASE(_view_layer)
#define SCE_SELECT_FACE
#define BASACT(_view_layer)
#define SCE_SELECT_VERTEX
#define SCE_SELECT_EDGE
#define BASE_VISIBLE(v3d, base)
@ USER_GPU_FLAG_NO_DEPT_PICK
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_PASS_THROUGH
uint DRW_select_buffer_context_offset_for_object_elem(struct Depsgraph *depsgraph, struct Object *object, char elem_type)
uint * DRW_select_buffer_bitmap_from_rect(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, const struct rcti *rect, uint *r_bitmap_len)
uint * DRW_select_buffer_bitmap_from_poly(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, const int poly[][2], const int poly_len, const struct rcti *rect, uint *r_bitmap_len)
uint * DRW_select_buffer_bitmap_from_circle(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, const int center[2], const int radius, uint *r_bitmap_len)
void DRW_select_buffer_context_create(struct Base **bases, const uint bases_len, short select_mode)
#define BONESEL_ANY
Definition: ED_armature.h:53
#define EBONE_VISIBLE(arm, ebone)
Definition: ED_armature.h:56
#define BONESEL_ROOT
Definition: ED_armature.h:50
#define BONESEL_TIP
Definition: ED_armature.h:51
#define BONESEL_BONE
Definition: ED_armature.h:52
#define EBONE_SELECTABLE(arm, ebone)
Definition: ED_armature.h:61
bool ED_lattice_deselect_all_multi(struct bContext *C)
bool ED_lattice_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
bool ED_lattice_flags_set(struct Object *obedit, int flag)
#define MBALLSEL_ANY
Definition: ED_mball.h:62
#define MBALLSEL_STIFF
Definition: ED_mball.h:60
bool ED_mball_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
Definition: mball_edit.c:764
#define MBALLSEL_RADIUS
Definition: ED_mball.h:61
bool ED_mball_deselect_all_multi(struct bContext *C)
Definition: mball_edit.c:106
bool paintvert_deselect_all_visible(struct Object *ob, int action, bool flush_flags)
Definition: editface.c:499
#define ED_MESH_PICK_DEFAULT_VERT_DIST
Definition: ED_mesh.h:514
bool paintface_deselect_all_visible(struct bContext *C, struct Object *ob, int action, bool flush_flags)
Definition: editface.c:287
bool paintface_mouse_select(struct bContext *C, struct Object *ob, const int mval[2], bool extend, bool deselect, bool toggle)
Definition: editface.c:385
void paintface_flush_flags(struct bContext *C, struct Object *ob, short flag)
Definition: editface.c:55
void paintvert_flush_flags(struct Object *ob)
Definition: editface.c:443
bool ED_mesh_pick_vert(struct bContext *C, struct Object *ob, const int mval[2], uint dist_px, bool use_zbuf, uint *r_index)
Definition: meshtools.c:1401
void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag)
bool EDBM_mesh_deselect_all_multi(struct bContext *C)
void paintvert_tag_select_update(struct bContext *C, struct Object *ob)
Definition: editface.c:489
bool EDBM_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
void EDBM_selectmode_flush(struct BMEditMesh *em)
void ED_object_mode_generic_exit(struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob)
Definition: object_modes.c:391
void ED_object_base_select(struct Base *base, eObjectSelect_Mode mode)
Definition: object_select.c:98
void ED_object_base_activate(struct bContext *C, struct Base *base)
@ BA_DESELECT
Definition: ED_object.h:146
@ BA_SELECT
Definition: ED_object.h:147
bool ED_object_base_deselect_all(struct ViewLayer *view_layer, struct View3D *v3d, int action)
void ED_outliner_select_sync_from_object_tag(struct bContext *C)
Definition: outliner_sync.c:56
void ED_outliner_select_sync_from_edit_bone_tag(struct bContext *C)
Definition: outliner_sync.c:62
void ED_outliner_select_sync_from_pose_bone_tag(struct bContext *C)
Definition: outliner_sync.c:68
bool PE_box_select(struct bContext *C, const struct rcti *rect, const int sel_op)
bool PE_mouse_particles(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
int PE_lasso_select(struct bContext *C, const int mcoords[][2], const int mcoords_len, const int sel_op)
bool PE_deselect_all_visible(struct bContext *C)
bool PE_circle_select(struct bContext *C, const int sel_op, const int mval[2], float rad)
bool ED_operator_view3d_active(struct bContext *C)
Definition: screen_ops.c:230
bool ED_operator_region_view3d_active(struct bContext *C)
Definition: screen_ops.c:235
#define SEL_OP_USE_PRE_DESELECT(sel_op)
#define SEL_OP_CAN_DESELECT(sel_op)
@ SEL_DESELECT
eSelectOp ED_select_op_modal(const eSelectOp sel_op, const bool is_first)
Definition: select_utils.c:77
int ED_select_op_action_deselected(const eSelectOp sel_op, const bool is_select, const bool is_inside)
Definition: select_utils.c:53
#define SEL_OP_USE_OUTSIDE(sel_op)
eSelectOp
@ SEL_OP_ADD
@ SEL_OP_SUB
@ SEL_OP_SET
void nurbs_foreachScreenVert(struct ViewContext *vc, void(*func)(void *userData, struct Nurb *nu, struct BPoint *bp, struct BezTriple *bezt, int beztindex, bool handle_visible, const float screen_co[2]), void *userData, const eV3DProjTest clip_flag)
void armature_foreachScreenBone(struct ViewContext *vc, void(*func)(void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2]), void *userData, const eV3DProjTest clip_flag)
#define XRAY_ENABLED(v3d)
Definition: ED_view3d.h:710
void view3d_opengl_select_cache_end(void)
Definition: view3d_view.c:897
eV3DProjStatus ED_view3d_project_base(const struct ARegion *region, struct Base *base)
void ED_view3d_init_mats_rv3d(struct Object *ob, struct RegionView3D *rv3d)
Definition: space_view3d.c:190
void mball_foreachScreenElem(struct ViewContext *vc, void(*func)(void *userData, struct MetaElem *ml, const float screen_co[2]), void *userData, const eV3DProjTest clip_flag)
eV3DProjTest
Definition: ED_view3d.h:192
@ V3D_PROJ_TEST_CLIP_NEAR
Definition: ED_view3d.h:196
@ V3D_PROJ_TEST_CLIP_BB
Definition: ED_view3d.h:194
@ V3D_PROJ_RET_OK
Definition: ED_view3d.h:176
#define MAXPICKBUF
Definition: ED_view3d.h:511
void meshobject_foreachScreenVert(struct ViewContext *vc, void(*func)(void *userData, struct MVert *eve, const float screen_co[2], int index), void *userData, const eV3DProjTest clip_flag)
#define XRAY_ACTIVE(v3d)
Definition: ED_view3d.h:711
void mesh_foreachScreenFace(struct ViewContext *vc, void(*func)(void *userData, struct BMFace *efa, const float screen_co[2], int index), void *userData, const eV3DProjTest clip_flag)
void mesh_foreachScreenVert(struct ViewContext *vc, void(*func)(void *userData, struct BMVert *eve, const float screen_co[2], int index), void *userData, const eV3DProjTest clip_flag)
#define IS_CLIPPED
Definition: ED_view3d.h:172
void view3d_opengl_select_cache_begin(void)
Definition: view3d_view.c:892
#define V3D_PROJ_TEST_CLIP_DEFAULT
Definition: ED_view3d.h:201
#define MAXPICKELEMS
Definition: ED_view3d.h:510
@ VIEW3D_SELECT_PICK_ALL
Definition: ED_view3d.h:517
@ VIEW3D_SELECT_PICK_NEAREST
Definition: ED_view3d.h:519
@ VIEW3D_SELECT_ALL
Definition: ED_view3d.h:515
int view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const struct rcti *input, eV3DSelectMode select_mode, eV3DSelectObjectFilter select_filter)
eV3DSelectObjectFilter ED_view3d_select_filter_from_mode(const struct Scene *scene, const struct Object *obact)
#define XRAY_FLAG_ENABLED(v3d)
Definition: ED_view3d.h:709
void lattice_foreachScreenVert(struct ViewContext *vc, void(*func)(void *userData, struct BPoint *bp, const float screen_co[2]), void *userData, const eV3DProjTest clip_flag)
void view3d_operator_needs_opengl(const struct bContext *C)
void pose_foreachScreenBone(struct ViewContext *vc, void(*func)(void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2]), void *userData, const eV3DProjTest clip_flag)
void mesh_foreachScreenEdge_clip_bb_segment(struct ViewContext *vc, void(*func)(void *userData, struct BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index), void *userData, const eV3DProjTest clip_flag)
eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *region, const float co[3], float r_co[2], const eV3DProjTest flag)
eV3DSelectObjectFilter
Definition: ED_view3d.h:522
@ VIEW3D_SELECT_FILTER_NOP
Definition: ED_view3d.h:524
NSNotificationCenter * center
_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
#define GPU_matrix_set(x)
Definition: GPU_matrix.h:224
Contains defines and structs used throughout the imbuf module.
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
@ PROP_ENUM_NO_TRANSLATE
Definition: RNA_types.h:279
@ PROP_SKIP_SAVE
Definition: RNA_types.h:204
@ PROP_HIDDEN
Definition: RNA_types.h:202
#define C
Definition: RandGen.cpp:39
int UI_icon_from_id(const struct ID *id)
#define NC_GEOM
Definition: WM_types.h:294
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
@ WM_OP_INVOKE_DEFAULT
Definition: WM_types.h:197
#define NC_MOVIECLIP
Definition: WM_types.h:298
#define ND_OB_SELECT
Definition: WM_types.h:342
#define NC_SCENE
Definition: WM_types.h:279
#define WM_EVENT_CURSOR_MOTION_THRESHOLD
Definition: WM_types.h:648
#define ND_SELECT
Definition: WM_types.h:407
#define ND_BONE_ACTIVE
Definition: WM_types.h:360
#define ND_BONE_SELECT
Definition: WM_types.h:361
#define NC_OBJECT
Definition: WM_types.h:280
bool ED_armature_edit_deselect_all_visible(Object *obedit)
Base * ED_armature_base_and_ebone_from_select_buffer(Base **bases, uint bases_len, int hit, EditBone **r_ebone)
Base * ED_armature_base_and_pchan_from_select_buffer(Base **bases, uint bases_len, int hit, bPoseChannel **r_pchan)
Base * ED_armature_base_and_bone_from_select_buffer(Base **bases, uint bases_len, int hit, Bone **r_bone)
bool ED_armature_edit_deselect_all_visible_multi(bContext *C)
bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
bool ED_armature_edit_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
bool ED_armature_edit_select_pick_bone(bContext *C, Base *basact, EditBone *ebone, const int selmask, const bool extend, const bool deselect, const bool toggle)
bool ED_armature_edit_deselect_all_visible_multi_ex(struct Base **bases, uint bases_len)
void ED_armature_ebone_listbase_temp_clear(ListBase *lb)
void ED_armature_edit_sync_selection(ListBase *edbo)
void ED_armature_edit_validate_active(struct bArmature *arm)
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
Select Face.
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
Select Vert.
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
Select Edge.
ATTR_WARN_UNUSED_RESULT const BMVert * v2
unsigned int U
Definition: btGjkEpa3.h:78
#define SELECT
OperationNode * node
Scene scene
Curve curve
const Depsgraph * depsgraph
void * user_data
bool ED_curve_editnurb_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
Definition: editcurve.c:4769
bool ED_curve_deselect_all_multi(struct bContext *C)
bool ED_curve_editfont_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
Definition: editfont.c:2214
static bool is_inside(int x, int y, int cols, int rows)
Definition: filesel.c:663
void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
uint col
__kernel void ccl_constant KernelData ccl_global void ccl_global char ccl_global int ccl_global char ccl_global unsigned int ccl_global float * buffer
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static unsigned a[3]
Definition: RandGen.cpp:92
static void area(int d1, int d2, int e1, int e2, float weights[2])
static bool do_lasso_select_node(bContext *C, const int mcoords[][2], const int mcoords_len, eSelectOp sel_op)
Definition: node_select.c:833
Object * ED_pose_object_from_context(bContext *C)
Definition: pose_edit.c:76
void ED_pose_bone_select_tag_update(Object *ob)
Definition: pose_select.c:96
bool ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibility)
Definition: pose_select.c:329
bool ED_pose_deselect_all_multi(bContext *C, int select_mode, const bool ignore_visibility)
Definition: pose_select.c:411
void ED_armature_pose_select_pick_bone(ViewLayer *view_layer, View3D *v3d, Object *ob, Bone *bone, const bool extend, const bool deselect, const bool toggle)
Definition: pose_select.c:141
bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer, View3D *v3d, Base *base, const uint *buffer, short hits, bool extend, bool deselect, bool toggle, bool do_nearest)
Definition: pose_select.c:245
void ED_armature_pose_select_in_wpaint_mode(ViewLayer *view_layer, Base *base_select)
Definition: pose_select.c:280
void RNA_int_set_array(PointerRNA *ptr, const char *name, const int *values)
Definition: rna_access.c:6343
void RNA_int_get_array(PointerRNA *ptr, const char *name, int *values)
Definition: rna_access.c:6331
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:6272
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
PropertyRNA * RNA_def_int_vector(StructOrFunctionRNA *cont_, const char *identifier, int len, const int *default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3611
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
Definition: rna_define.c:4470
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
Definition: rna_define.c:4416
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1512
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
Definition: rna_define.c:3819
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:3771
const EnumPropertyItem DummyRNA_NULL_items[]
Definition: rna_rna.c:40
#define min(a, b)
Definition: sort.c:51
unsigned char uint8_t
Definition: stdint.h:81
struct BMesh * bm
Definition: BKE_editmesh.h:52
int totvertsel
Definition: bmesh_class.h:298
uint8_t f1
struct Base * next
short flag
short sy
struct Object * object
short sx
struct EditSelectBuf_Cache * esel
const rctf * rect_fl
ViewContext * vc
const rcti * rect
eBezTriple_Flag select_flag
eBezTriple_Flag select_flag
char name[64]
Definition: BKE_armature.h:57
union EditBone::@2 temp
BLI_bitmap * select_bitmap
const char * name
Definition: RNA_types.h:450
int tag
Definition: DNA_ID.h:292
char name[66]
Definition: DNA_ID.h:283
struct EditSelectBuf_Cache * esel
LassoSelectUserData * data
const rctf * rect_fl
eBezTriple_Flag select_flag
const int(* mcoords)[2]
ViewContext * vc
LinkNode * list
Definition: BLI_linklist.h:50
void * link
Definition: BLI_linklist.h:40
struct LinkNode * next
Definition: BLI_linklist.h:39
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
struct MVert * mvert
int totvert
int totpoly
struct MPoly * mpoly
ListBase * editelems
short flag
struct MovieTracking tracking
struct MovieTrackingTrack * next
struct bPose * pose
Object_Runtime runtime
float obmat[4][4]
void * data
float viewmat[4][4]
struct ToolSettings * toolsettings
char idname[MAX_ID_NAME - 2]
struct bNodeTree * edittree
struct Depsgraph * depsgraph
Definition: ED_view3d.h:75
struct Scene * scene
Definition: ED_view3d.h:76
struct ARegion * region
Definition: ED_view3d.h:80
struct ViewLayer * view_layer
Definition: ED_view3d.h:77
struct BMEditMesh * em
Definition: ED_view3d.h:84
struct Main * bmain
Definition: ED_view3d.h:70
struct bContext * C
Definition: ED_view3d.h:69
struct Object * obact
Definition: ED_view3d.h:78
struct Object * obedit
Definition: ED_view3d.h:79
struct wmWindow * win
Definition: ED_view3d.h:82
struct View3D * v3d
Definition: ED_view3d.h:81
struct RegionView3D * rv3d
Definition: ED_view3d.h:83
ListBase object_bases
ListBase * edbo
ListBase nodes
struct Bone * bone
ListBase chanbase
float xmax
Definition: DNA_vec_types.h:85
float xmin
Definition: DNA_vec_types.h:85
float ymax
Definition: DNA_vec_types.h:86
float ymin
Definition: DNA_vec_types.h:86
int mval[2]
Definition: WM_types.h:583
void(* free_fn)(void *data)
Definition: WM_types.h:138
wmGenericUserData user_data
Definition: WM_types.h:532
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:768
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:760
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
PropertyRNA * prop
Definition: WM_types.h:814
struct PointerRNA * ptr
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: util_avxb.h:167
#define G(x, y, z)
static bool pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, const float screen_co[2])
static bool do_mesh_box_select(ViewContext *vc, wmGenericUserData *wm_userdata, const rcti *rect, const eSelectOp sel_op)
static bool edbm_backbuf_check_and_select_verts(struct EditSelectBuf_Cache *esel, Depsgraph *depsgraph, Object *ob, BMEditMesh *em, const eSelectOp sel_op)
void VIEW3D_OT_select(wmOperatorType *ot)
static void do_nurbs_box_select__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, bool handles_visible, const float screen_co[2])
static bool edbm_backbuf_check_and_select_verts_obmode(Mesh *me, struct EditSelectBuf_Cache *esel, const eSelectOp sel_op)
static bool armature_circle_select(ViewContext *vc, const eSelectOp sel_op, const int mval[2], float rad)
static bool paint_facesel_circle_select(ViewContext *vc, wmGenericUserData *wm_userdata, const eSelectOp sel_op, const int mval[2], float rad)
static Base ** do_pose_tag_select_op_prepare(ViewContext *vc, uint *r_bases_len)
static bool object_deselect_all_except(ViewLayer *view_layer, Base *b)
static bool object_deselect_all_visible(ViewLayer *view_layer, View3D *v3d)
static const EnumPropertyItem * object_select_menu_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
static bool armature_circle_doSelectJoint(void *userData, EditBone *ebone, const float screen_co[2], bool head)
static bool selectbuffer_has_bones(const uint *buffer, const uint hits)
static int view3d_box_select_exec(bContext *C, wmOperator *op)
static void mesh_circle_doSelectEdge(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int UNUSED(index))
static bool do_lattice_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op)
static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
static void do_lasso_select_armature__doSelectBone(void *userData, EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
static void do_circle_select_mball__doSelectElem(void *userData, struct MetaElem *ml, const float screen_co[2])
void VIEW3D_OT_bone_select_menu(wmOperatorType *ot)
static bool do_lasso_select_armature(ViewContext *vc, const int mcoords[][2], const int mcoords_len, const eSelectOp sel_op)
void VIEW3D_OT_select_box(wmOperatorType *ot)
static void editselect_buf_cache_init_with_generic_userdata(wmGenericUserData *wm_userdata, ViewContext *vc, short select_mode)
static void mesh_circle_doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index))
static bool do_lasso_select_objects(ViewContext *vc, const int mcoords[][2], const int mcoords_len, const eSelectOp sel_op)
static void latticecurve_circle_doSelect(void *userData, BPoint *bp, const float screen_co[2])
static void do_mesh_box_select__doSelectFace(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
Object * ED_view3d_give_object_under_cursor(bContext *C, const int mval[2])
static int mixed_bones_object_selectbuffer_extended(ViewContext *vc, uint *buffer, const int mval[2], eV3DSelectObjectFilter select_filter, bool use_cycle, bool enumerate, bool *r_do_nearest)
static void do_lasso_select_meshobject__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
static bool do_lasso_select_lattice(ViewContext *vc, const int mcoords[][2], const int mcoords_len, const eSelectOp sel_op)
static int view3d_circle_select_exec(bContext *C, wmOperator *op)
struct BoxSelectUserData BoxSelectUserData
static bool edge_fully_inside_rect(const rctf *rect, const float v1[2], const float v2[2])
static bool do_lasso_select_paintvert(ViewContext *vc, wmGenericUserData *wm_userdata, const int mcoords[][2], const int mcoords_len, const eSelectOp sel_op)
static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const float screen_co[2])
static bool do_lasso_select_curve(ViewContext *vc, const int mcoords[][2], const int mcoords_len, const eSelectOp sel_op)
static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data, ViewContext *vc, const rcti *rect, const int(*mcoords)[2], const int mcoords_len, const eSelectOp sel_op)
struct SelMenuItemF SelMenuItemF
static int selectbuffer_ret_hits_9(uint *buffer, const int hits15, const int hits9)
static bool edge_inside_rect(const rctf *rect, const float v1[2], const float v2[2])
static int mixed_bones_object_selectbuffer(ViewContext *vc, uint *buffer, const int mval[2], eV3DSelectObjectFilter select_filter, bool do_nearest, bool do_nearest_xray_if_supported)
static void do_circle_select_armature__doSelectBone(void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
static SelMenuItemF object_mouse_select_menu_data[SEL_MENU_SIZE]
static bool lattice_circle_select(ViewContext *vc, const eSelectOp sel_op, const int mval[2], float rad)
static bool object_circle_select(ViewContext *vc, const eSelectOp sel_op, const int mval[2], float rad)
static Base * object_mouse_select_menu(bContext *C, ViewContext *vc, const uint *buffer, int hits, const int mval[2], bool extend, bool deselect, bool toggle)
static bool paint_vertsel_circle_select(ViewContext *vc, wmGenericUserData *wm_userdata, const eSelectOp sel_op, const int mval[2], float rad)
static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
static Base * mouse_select_eval_buffer(ViewContext *vc, const uint *buffer, int hits, Base *startbase, bool has_bones, bool do_nearest)
static void do_mesh_box_select__doSelectEdge_pass1(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
static void do_lasso_select_curve__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, bool handles_visible, const float screen_co[2])
static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data, ViewContext *vc, const bool select, const int mval[2], const float rad)
static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const eSelectOp sel_op)
static void paint_vertsel_circle_select_doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
static bool bone_mouse_select_menu(bContext *C, const uint *buffer, const int hits, const bool is_editmode, const bool extend, const bool deselect, const bool toggle)
#define SEL_MENU_SIZE
static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcoords[][2], const int mcoords_len)
void VIEW3D_OT_select_menu(wmOperatorType *ot)
static void mesh_circle_doSelectFace(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc, Depsgraph *depsgraph)
static void do_paintvert_box_select__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
static void do_lasso_select_pose__do_tag(void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2])
static bool edbm_backbuf_check_and_select_faces(struct EditSelectBuf_Cache *esel, Depsgraph *depsgraph, Object *ob, BMEditMesh *em, const eSelectOp sel_op)
static bool ed_object_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, bool obcenter, bool enumerate, bool object)
struct CircleSelectUserData CircleSelectUserData
static bool pose_circle_select(ViewContext *vc, const eSelectOp sel_op, const int mval[2], float rad)
bool ED_view3d_is_object_under_cursor(bContext *C, const int mval[2])
static void do_lasso_select_mball__doSelectElem(void *userData, struct MetaElem *ml, const float screen_co[2])
static bool do_armature_box_select(ViewContext *vc, const rcti *rect, const eSelectOp sel_op)
static int object_select_menu_exec(bContext *C, wmOperator *op)
static bool obedit_circle_select(bContext *C, ViewContext *vc, wmGenericUserData *wm_userdata, const eSelectOp sel_op, const int mval[2], float rad)
static void editselect_buf_cache_init(ViewContext *vc, short select_mode)
static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data, ViewContext *vc, const rcti *rect, const eSelectOp sel_op)
static bool ed_wpaint_vertex_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, Object *obact)
static bool edbm_backbuf_check_and_select_edges(struct EditSelectBuf_Cache *esel, Depsgraph *depsgraph, Object *ob, BMEditMesh *em, const eSelectOp sel_op)
static bool view3d_lasso_select(bContext *C, ViewContext *vc, const int mcoords[][2], const int mcoords_len, const eSelectOp sel_op)
static void nurbscurve_circle_doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, bool UNUSED(handles_visible), const float screen_co[2])
static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index))
static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const eSelectOp sel_op)
static void do_mesh_box_select__doSelectEdge_pass0(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
static bool do_lasso_select_meta(ViewContext *vc, const int mcoords[][2], const int mcoords_len, const eSelectOp sel_op)
static void do_mesh_box_select__doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index))
static bool do_meta_box_select(ViewContext *vc, const rcti *rect, const eSelectOp sel_op)
static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
static bool do_lasso_select_pose(ViewContext *vc, const int mcoords[][2], const int mcoords_len, const eSelectOp sel_op)
static bool do_lasso_select_mesh(ViewContext *vc, wmGenericUserData *wm_userdata, const int mcoords[][2], const int mcoords_len, const eSelectOp sel_op)
static void deselect_all_tracks(MovieTracking *tracking)
static bool do_nurbs_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op)
static void editselect_buf_cache_free(struct EditSelectBuf_Cache *esel)
Base * ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
static bool do_paintvert_box_select(ViewContext *vc, wmGenericUserData *wm_userdata, const rcti *rect, const eSelectOp sel_op)
static void editselect_buf_cache_free_voidp(void *esel_voidp)
struct LassoSelectUserData LassoSelectUserData
static bool mesh_circle_select(ViewContext *vc, wmGenericUserData *wm_userdata, eSelectOp sel_op, const int mval[2], float rad)
static int selectbuffer_ret_hits_15(uint *UNUSED(buffer), const int hits15)
static int selectbuffer_ret_hits_5(uint *buffer, const int hits15, const int hits9, const int hits5)
bool edge_inside_circle(const float cent[2], float radius, const float screen_co_a[2], const float screen_co_b[2])
void VIEW3D_OT_select_circle(wmOperatorType *ot)
static void do_lasso_select_mesh__doSelectFace(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const eSelectOp sel_op)
void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact)
void VIEW3D_OT_select_lasso(wmOperatorType *ot)
static void do_circle_select_pose__doSelectBone(void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2])
static bool edbm_backbuf_check_and_select_faces_obmode(Mesh *me, struct EditSelectBuf_Cache *esel, const eSelectOp sel_op)
float ED_view3d_select_dist_px(void)
static int opengl_bone_select_buffer_cmp(const void *sel_a_p, const void *sel_b_p)
static bool mball_circle_select(ViewContext *vc, const eSelectOp sel_op, const int mval[2], float rad)
static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, const float screen_co[2])
static int view3d_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static bool do_paintface_box_select(ViewContext *vc, wmGenericUserData *wm_userdata, const rcti *rect, int sel_op)
static bool do_lasso_select_paintface(ViewContext *vc, wmGenericUserData *wm_userdata, const int mcoords[][2], const int mcoords_len, const eSelectOp sel_op)
static bool nurbscurve_circle_select(ViewContext *vc, const eSelectOp sel_op, const int mval[2], float rad)
static bool view3d_selectable_data(bContext *C)
static int bone_select_menu_exec(bContext *C, wmOperator *op)
static int view3d_select_exec(bContext *C, wmOperator *op)
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, short context, PointerRNA *properties)
PointerRNA * ptr
Definition: wm_files.c:3157
wmOperatorType * ot
Definition: wm_files.c:3156
bool WM_gesture_is_modal_first(const wmGesture *gesture)
Definition: wm_gesture.c:124
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_circle_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void WM_gesture_circle_cancel(bContext *C, wmOperator *op)
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
void WM_gesture_lasso_cancel(bContext *C, wmOperator *op)
int WM_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const int(* WM_gesture_lasso_path_to_array(bContext *UNUSED(C), wmOperator *op, int *r_mcoords_len))[2]
void WM_operator_properties_border_to_rcti(struct wmOperator *op, rcti *rect)
void WM_operator_properties_gesture_box(wmOperatorType *ot)
void WM_operator_properties_select_operation_simple(wmOperatorType *ot)
void WM_operator_properties_select_operation(wmOperatorType *ot)
void WM_operator_properties_gesture_lasso(wmOperatorType *ot)
void WM_operator_properties_gesture_circle(wmOperatorType *ot)
void WM_operator_properties_mouse_select(wmOperatorType *ot)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
Definition: wm_operators.c:584
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_operators.c:982
void WM_operator_properties_free(PointerRNA *ptr)
Definition: wm_operators.c:711
void WM_toolsystem_update_from_context_view3d(bContext *C)
void WM_generic_user_data_free(wmGenericUserData *wm_userdata)
Definition: wm_utils.c:59