Blender  V3.3
view3d_select.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2008 Blender Foundation. All rights reserved. */
3 
8 #include <float.h>
9 #include <math.h>
10 #include <stdio.h>
11 #include <string.h>
12 
13 #include "DNA_action_types.h"
14 #include "DNA_armature_types.h"
15 #include "DNA_curve_types.h"
16 #include "DNA_gpencil_types.h"
17 #include "DNA_mesh_types.h"
18 #include "DNA_meshdata_types.h"
19 #include "DNA_meta_types.h"
20 #include "DNA_object_types.h"
21 #include "DNA_scene_types.h"
22 #include "DNA_tracking_types.h"
23 
24 #include "MEM_guardedalloc.h"
25 
26 #include "BLI_array.h"
27 #include "BLI_bitmap.h"
28 #include "BLI_lasso_2d.h"
29 #include "BLI_linklist.h"
30 #include "BLI_listbase.h"
31 #include "BLI_math.h"
32 #include "BLI_rect.h"
33 #include "BLI_string.h"
34 #include "BLI_utildefines.h"
35 
36 #ifdef __BIG_ENDIAN__
37 # include "BLI_endian_switch.h"
38 #endif
39 
40 /* vertex box select */
41 #include "BKE_global.h"
42 #include "BKE_main.h"
43 #include "IMB_imbuf.h"
44 #include "IMB_imbuf_types.h"
45 
46 #include "BKE_action.h"
47 #include "BKE_armature.h"
48 #include "BKE_context.h"
49 #include "BKE_curve.h"
50 #include "BKE_editmesh.h"
51 #include "BKE_layer.h"
52 #include "BKE_mball.h"
53 #include "BKE_mesh.h"
54 #include "BKE_object.h"
55 #include "BKE_paint.h"
56 #include "BKE_scene.h"
57 #include "BKE_tracking.h"
58 #include "BKE_workspace.h"
59 
60 #include "WM_api.h"
61 #include "WM_toolsystem.h"
62 #include "WM_types.h"
63 
64 #include "RNA_access.h"
65 #include "RNA_define.h"
66 #include "RNA_enum_types.h"
67 
68 #include "ED_armature.h"
69 #include "ED_curve.h"
70 #include "ED_gpencil.h"
71 #include "ED_lattice.h"
72 #include "ED_mball.h"
73 #include "ED_mesh.h"
74 #include "ED_object.h"
75 #include "ED_outliner.h"
76 #include "ED_particle.h"
77 #include "ED_screen.h"
78 #include "ED_sculpt.h"
79 #include "ED_select_utils.h"
80 
81 #include "UI_interface.h"
82 #include "UI_resources.h"
83 
84 #include "GPU_matrix.h"
85 #include "GPU_select.h"
86 
87 #include "DEG_depsgraph.h"
88 #include "DEG_depsgraph_query.h"
89 
90 #include "DRW_engine.h"
91 #include "DRW_select_buffer.h"
92 
93 #include "view3d_intern.h" /* own include */
94 
95 // #include "PIL_time_utildefines.h"
96 
97 /* -------------------------------------------------------------------- */
102 {
103  return 75.0f * U.pixelsize;
104 }
105 
107 {
108  /* TODO: should return whether there is valid context to continue. */
109 
110  memset(vc, 0, sizeof(ViewContext));
111  vc->C = C;
112  vc->region = CTX_wm_region(C);
113  vc->bmain = CTX_data_main(C);
114  vc->depsgraph = depsgraph;
115  vc->scene = CTX_data_scene(C);
117  vc->v3d = CTX_wm_view3d(C);
118  vc->win = CTX_wm_window(C);
119  vc->rv3d = CTX_wm_region_view3d(C);
122 }
123 
125 {
126  vc->obact = obact;
127  /* See public doc-string for rationale on checking the existing values first. */
128  if (vc->obedit) {
130  vc->obedit = obact;
131  if (vc->em) {
133  }
134  }
135 }
136 
139 /* -------------------------------------------------------------------- */
143 static bool object_deselect_all_visible(ViewLayer *view_layer, View3D *v3d)
144 {
145  bool changed = false;
146  LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
147  if (base->flag & BASE_SELECTED) {
148  if (BASE_SELECTABLE(v3d, base)) {
150  changed = true;
151  }
152  }
153  }
154  return changed;
155 }
156 
157 /* deselect all except b */
158 static bool object_deselect_all_except(ViewLayer *view_layer, Base *b)
159 {
160  bool changed = false;
161  LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
162  if (base->flag & BASE_SELECTED) {
163  if (b != base) {
165  changed = true;
166  }
167  }
168  }
169  return changed;
170 }
171 
174 /* -------------------------------------------------------------------- */
187 };
188 
189 static void editselect_buf_cache_init(ViewContext *vc, short select_mode)
190 {
191  if (vc->obedit) {
192  uint bases_len = 0;
194  vc->view_layer, vc->v3d, &bases_len);
195 
196  DRW_select_buffer_context_create(bases, bases_len, select_mode);
197  MEM_freeN(bases);
198  }
199  else {
200  /* Use for paint modes, currently only a single object at a time. */
201  if (vc->obact) {
202  Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact);
203  DRW_select_buffer_context_create(&base, 1, select_mode);
204  }
205  }
206 }
207 
209 {
211 }
212 
213 static void editselect_buf_cache_free_voidp(void *esel_voidp)
214 {
215  editselect_buf_cache_free(esel_voidp);
216  MEM_freeN(esel_voidp);
217 }
218 
220  ViewContext *vc,
221  short select_mode)
222 {
223  struct EditSelectBuf_Cache *esel = MEM_callocN(sizeof(*esel), __func__);
224  wm_userdata->data = esel;
226  wm_userdata->use_free = true;
227  editselect_buf_cache_init(vc, select_mode);
228 }
229 
232 /* -------------------------------------------------------------------- */
238  Object *ob,
239  BMEditMesh *em,
240  const eSelectOp sel_op)
241 {
242  BMVert *eve;
243  BMIter iter;
244  bool changed = false;
245 
246  const BLI_bitmap *select_bitmap = esel->select_bitmap;
248  if (index == 0) {
249  return false;
250  }
251 
252  index -= 1;
253  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
254  if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
255  const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
256  const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
257  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
258  if (sel_op_result != -1) {
259  BM_vert_select_set(em->bm, eve, sel_op_result);
260  changed = true;
261  }
262  }
263  index++;
264  }
265  return changed;
266 }
267 
270  Object *ob,
271  BMEditMesh *em,
272  const eSelectOp sel_op)
273 {
274  BMEdge *eed;
275  BMIter iter;
276  bool changed = false;
277 
278  const BLI_bitmap *select_bitmap = esel->select_bitmap;
280  if (index == 0) {
281  return false;
282  }
283 
284  index -= 1;
285  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
286  if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
287  const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
288  const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
289  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
290  if (sel_op_result != -1) {
291  BM_edge_select_set(em->bm, eed, sel_op_result);
292  changed = true;
293  }
294  }
295  index++;
296  }
297  return changed;
298 }
299 
302  Object *ob,
303  BMEditMesh *em,
304  const eSelectOp sel_op)
305 {
306  BMFace *efa;
307  BMIter iter;
308  bool changed = false;
309 
310  const BLI_bitmap *select_bitmap = esel->select_bitmap;
312  if (index == 0) {
313  return false;
314  }
315 
316  index -= 1;
317  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
318  if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
319  const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
320  const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
321  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
322  if (sel_op_result != -1) {
323  BM_face_select_set(em->bm, efa, sel_op_result);
324  changed = true;
325  }
326  }
327  index++;
328  }
329  return changed;
330 }
331 
332 /* object mode, edbm_ prefix is confusing here, rename? */
334  struct EditSelectBuf_Cache *esel,
335  const eSelectOp sel_op)
336 {
337  MVert *mv = me->mvert;
338  uint index;
339  bool changed = false;
340 
341  const BLI_bitmap *select_bitmap = esel->select_bitmap;
342 
343  if (mv) {
344  for (index = 0; index < me->totvert; index++, mv++) {
345  if (!(mv->flag & ME_HIDE)) {
346  const bool is_select = mv->flag & SELECT;
347  const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
348  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
349  if (sel_op_result != -1) {
350  SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT);
351  changed = true;
352  }
353  }
354  }
355  }
356  return changed;
357 }
358 
359 /* object mode, edbm_ prefix is confusing here, rename? */
361  struct EditSelectBuf_Cache *esel,
362  const eSelectOp sel_op)
363 {
364  MPoly *mpoly = me->mpoly;
365  uint index;
366  bool changed = false;
367 
368  const BLI_bitmap *select_bitmap = esel->select_bitmap;
369 
370  if (mpoly) {
371  for (index = 0; index < me->totpoly; index++, mpoly++) {
372  if (!(mpoly->flag & ME_HIDE)) {
373  const bool is_select = mpoly->flag & ME_FACE_SEL;
374  const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
375  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
376  if (sel_op_result != -1) {
377  SET_FLAG_FROM_TEST(mpoly->flag, sel_op_result, ME_FACE_SEL);
378  changed = true;
379  }
380  }
381  }
382  }
383  return changed;
384 }
385 
388 /* -------------------------------------------------------------------- */
392 typedef struct LassoSelectUserData {
394  const rcti *rect;
395  const rctf *rect_fl;
397  const int (*mcoords)[2];
401 
402  /* runtime */
403  int pass;
404  bool is_done;
407 
409  ViewContext *vc,
410  const rcti *rect,
411  const int (*mcoords)[2],
412  const int mcoords_len,
413  const eSelectOp sel_op)
414 {
415  r_data->vc = vc;
416 
417  r_data->rect = rect;
418  r_data->rect_fl = &r_data->_rect_fl;
419  BLI_rctf_rcti_copy(&r_data->_rect_fl, rect);
420 
421  r_data->mcoords = mcoords;
422  r_data->mcoords_len = mcoords_len;
423  r_data->sel_op = sel_op;
424  /* SELECT by default, but can be changed if needed (only few cases use and respect this). */
425  r_data->select_flag = SELECT;
426 
427  /* runtime */
428  r_data->pass = 0;
429  r_data->is_done = false;
430  r_data->is_changed = false;
431 }
432 
434 {
436 
438  return 0;
439  }
440 
441  if (ob) {
442  if (ob->mode & OB_MODE_EDIT) {
443  if (ob->type == OB_FONT) {
444  return 0;
445  }
446  }
447  else {
450  return 0;
451  }
452  }
453  }
454 
455  return 1;
456 }
457 
458 /* helper also for box_select */
459 static bool edge_fully_inside_rect(const rctf *rect, const float v1[2], const float v2[2])
460 {
461  return BLI_rctf_isect_pt_v(rect, v1) && BLI_rctf_isect_pt_v(rect, v2);
462 }
463 
464 static bool edge_inside_rect(const rctf *rect, const float v1[2], const float v2[2])
465 {
466  int d1, d2, d3, d4;
467 
468  /* check points in rect */
469  if (edge_fully_inside_rect(rect, v1, v2)) {
470  return 1;
471  }
472 
473  /* check points completely out rect */
474  if (v1[0] < rect->xmin && v2[0] < rect->xmin) {
475  return 0;
476  }
477  if (v1[0] > rect->xmax && v2[0] > rect->xmax) {
478  return 0;
479  }
480  if (v1[1] < rect->ymin && v2[1] < rect->ymin) {
481  return 0;
482  }
483  if (v1[1] > rect->ymax && v2[1] > rect->ymax) {
484  return 0;
485  }
486 
487  /* simple check lines intersecting. */
488  d1 = (v1[1] - v2[1]) * (v1[0] - rect->xmin) + (v2[0] - v1[0]) * (v1[1] - rect->ymin);
489  d2 = (v1[1] - v2[1]) * (v1[0] - rect->xmin) + (v2[0] - v1[0]) * (v1[1] - rect->ymax);
490  d3 = (v1[1] - v2[1]) * (v1[0] - rect->xmax) + (v2[0] - v1[0]) * (v1[1] - rect->ymax);
491  d4 = (v1[1] - v2[1]) * (v1[0] - rect->xmax) + (v2[0] - v1[0]) * (v1[1] - rect->ymin);
492 
493  if (d1 < 0 && d2 < 0 && d3 < 0 && d4 < 0) {
494  return 0;
495  }
496  if (d1 > 0 && d2 > 0 && d3 > 0 && d4 > 0) {
497  return 0;
498  }
499 
500  return 1;
501 }
502 
503 static void do_lasso_select_pose__do_tag(void *userData,
504  struct bPoseChannel *pchan,
505  const float screen_co_a[2],
506  const float screen_co_b[2])
507 {
508  LassoSelectUserData *data = userData;
509  const bArmature *arm = data->vc->obact->data;
510  if (!PBONE_SELECTABLE(arm, pchan->bone)) {
511  return;
512  }
513 
514  if (BLI_rctf_isect_segment(data->rect_fl, screen_co_a, screen_co_b) &&
516  data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) {
517  pchan->bone->flag |= BONE_DONE;
518  data->is_changed = true;
519  }
520 }
522  Object *ob,
523  const int mcoords[][2],
524  const int mcoords_len)
525 {
526  ViewContext vc_tmp;
528  rcti rect;
529 
530  if ((ob->type != OB_ARMATURE) || (ob->pose == NULL)) {
531  return;
532  }
533 
534  vc_tmp = *vc;
535  vc_tmp.obact = ob;
536 
537  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
538 
539  view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, 0);
540 
541  ED_view3d_init_mats_rv3d(vc_tmp.obact, vc->rv3d);
542 
543  /* Treat bones as clipped segments (no joints). */
544  pose_foreachScreenBone(&vc_tmp,
546  &data,
548 }
549 
551  const int mcoords[][2],
552  const int mcoords_len,
553  const eSelectOp sel_op)
554 {
555  View3D *v3d = vc->v3d;
556  Base *base;
557 
558  bool changed = false;
559  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
560  changed |= object_deselect_all_visible(vc->view_layer, vc->v3d);
561  }
562 
563  for (base = vc->view_layer->object_bases.first; base; base = base->next) {
564  if (BASE_SELECTABLE(v3d, base)) { /* Use this to avoid unnecessary lasso look-ups. */
565  const bool is_select = base->flag & BASE_SELECTED;
566  const bool is_inside = ((ED_view3d_project_base(vc->region, base) == V3D_PROJ_RET_OK) &&
568  mcoords, mcoords_len, base->sx, base->sy, IS_CLIPPED));
569  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
570  if (sel_op_result != -1) {
571  ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT);
572  changed = true;
573  }
574  }
575  }
576 
577  if (changed) {
580  }
581  return changed;
582 }
583 
588 {
589  Base **bases = NULL;
590  BLI_array_declare(bases);
592  Object *ob_iter = base_iter->object;
593  bArmature *arm = ob_iter->data;
594  LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_iter->pose->chanbase) {
595  Bone *bone = pchan->bone;
596  bone->flag &= ~BONE_DONE;
597  }
598  arm->id.tag |= LIB_TAG_DOIT;
599  ob_iter->id.tag &= ~LIB_TAG_DOIT;
600  BLI_array_append(bases, base_iter);
601  }
603  *r_bases_len = BLI_array_len(bases);
604  return bases;
605 }
606 
607 static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const eSelectOp sel_op)
608 {
609  bool changed_multi = false;
610 
611  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
612  for (int i = 0; i < bases_len; i++) {
613  Base *base_iter = bases[i];
614  Object *ob_iter = base_iter->object;
615  if (ED_pose_deselect_all(ob_iter, SEL_DESELECT, false)) {
617  changed_multi = true;
618  }
619  }
620  }
621 
622  for (int i = 0; i < bases_len; i++) {
623  Base *base_iter = bases[i];
624  Object *ob_iter = base_iter->object;
625  bArmature *arm = ob_iter->data;
626 
627  /* Don't handle twice. */
628  if (arm->id.tag & LIB_TAG_DOIT) {
629  arm->id.tag &= ~LIB_TAG_DOIT;
630  }
631  else {
632  continue;
633  }
634 
635  bool changed = true;
636  LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_iter->pose->chanbase) {
637  Bone *bone = pchan->bone;
638  if ((bone->flag & BONE_UNSELECTABLE) == 0) {
639  const bool is_select = bone->flag & BONE_SELECTED;
640  const bool is_inside = bone->flag & BONE_DONE;
641  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
642  if (sel_op_result != -1) {
643  SET_FLAG_FROM_TEST(bone->flag, sel_op_result, BONE_SELECTED);
644  if (sel_op_result == 0) {
645  if (arm->act_bone == bone) {
646  arm->act_bone = NULL;
647  }
648  }
649  changed = true;
650  }
651  }
652  }
653  if (changed) {
655  changed_multi = true;
656  }
657  }
658  return changed_multi;
659 }
660 
662  const int mcoords[][2],
663  const int mcoords_len,
664  const eSelectOp sel_op)
665 {
666  uint bases_len;
667  Base **bases = do_pose_tag_select_op_prepare(vc, &bases_len);
668 
669  for (int i = 0; i < bases_len; i++) {
670  Base *base_iter = bases[i];
671  Object *ob_iter = base_iter->object;
672  do_lasso_tag_pose(vc, ob_iter, mcoords, mcoords_len);
673  }
674 
675  const bool changed_multi = do_pose_tag_select_op_exec(bases, bases_len, sel_op);
676  if (changed_multi) {
679  }
680 
681  MEM_freeN(bases);
682  return changed_multi;
683 }
684 
685 static void do_lasso_select_mesh__doSelectVert(void *userData,
686  BMVert *eve,
687  const float screen_co[2],
688  int UNUSED(index))
689 {
690  LassoSelectUserData *data = userData;
691  const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
692  const bool is_inside =
693  (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
695  data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
696  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
697  if (sel_op_result != -1) {
698  BM_vert_select_set(data->vc->em->bm, eve, sel_op_result);
699  data->is_changed = true;
700  }
701 }
706 };
708  BMEdge *eed,
709  const float screen_co_a[2],
710  const float screen_co_b[2],
711  int index)
712 {
713  struct LassoSelectUserData_ForMeshEdge *data_for_edge = user_data;
714  LassoSelectUserData *data = data_for_edge->data;
715  bool is_visible = true;
716  if (data_for_edge->backbuf_offset) {
717  uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1;
718  is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx);
719  }
720 
721  const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
722  const bool is_inside =
723  (is_visible && edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) &&
725  data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), IS_CLIPPED) &&
727  data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), IS_CLIPPED));
728  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
729  if (sel_op_result != -1) {
730  BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
731  data->is_done = true;
732  data->is_changed = true;
733  }
734 }
736  BMEdge *eed,
737  const float screen_co_a[2],
738  const float screen_co_b[2],
739  int index)
740 {
741  struct LassoSelectUserData_ForMeshEdge *data_for_edge = user_data;
742  LassoSelectUserData *data = data_for_edge->data;
743  bool is_visible = true;
744  if (data_for_edge->backbuf_offset) {
745  uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1;
746  is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx);
747  }
748 
749  const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
750  const bool is_inside = (is_visible && BLI_lasso_is_edge_inside(data->mcoords,
751  data->mcoords_len,
752  UNPACK2(screen_co_a),
753  UNPACK2(screen_co_b),
754  IS_CLIPPED));
755  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
756  if (sel_op_result != -1) {
757  BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
758  data->is_changed = true;
759  }
760 }
761 
762 static void do_lasso_select_mesh__doSelectFace(void *userData,
763  BMFace *efa,
764  const float screen_co[2],
765  int UNUSED(index))
766 {
767  LassoSelectUserData *data = userData;
768  const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
769  const bool is_inside =
770  (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
772  data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
773  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
774  if (sel_op_result != -1) {
775  BM_face_select_set(data->vc->em->bm, efa, sel_op_result);
776  data->is_changed = true;
777  }
778 }
779 
781  wmGenericUserData *wm_userdata,
782  const int mcoords[][2],
783  const int mcoords_len,
784  const eSelectOp sel_op)
785 {
787  ToolSettings *ts = vc->scene->toolsettings;
788  rcti rect;
789 
790  /* set editmesh */
792 
793  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
794 
795  view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
796 
797  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
798  if (vc->em->bm->totvertsel) {
800  data.is_changed = true;
801  }
802  }
803 
804  /* for non zbuf projections, don't change the GL state */
806 
808 
809  const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d);
810 
811  struct EditSelectBuf_Cache *esel = wm_userdata->data;
812  if (use_zbuf) {
813  if (wm_userdata->data == NULL) {
815  esel = wm_userdata->data;
817  vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL);
818  }
819  }
820 
821  if (ts->selectmode & SCE_SELECT_VERTEX) {
822  if (use_zbuf) {
824  esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
825  }
826  else {
829  }
830  }
831  if (ts->selectmode & SCE_SELECT_EDGE) {
832  /* Does both use_zbuf and non-use_zbuf versions (need screen cos for both) */
833  struct LassoSelectUserData_ForMeshEdge data_for_edge = {
834  .data = &data,
835  .esel = use_zbuf ? esel : NULL,
836  .backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem(
837  vc->depsgraph, vc->obedit, SCE_SELECT_EDGE) :
838  0,
839  };
840 
841  const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR |
842  (use_zbuf ? 0 : V3D_PROJ_TEST_CLIP_BB);
843  /* Fully inside. */
845  vc, do_lasso_select_mesh__doSelectEdge_pass0, &data_for_edge, clip_flag);
846  if (data.is_done == false) {
847  /* Fall back to partially inside.
848  * Clip content to account for edges partially behind the view. */
851  &data_for_edge,
853  }
854  }
855 
856  if (ts->selectmode & SCE_SELECT_FACE) {
857  if (use_zbuf) {
859  esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
860  }
861  else {
864  }
865  }
866 
867  if (data.is_changed) {
869  }
870  return data.is_changed;
871 }
872 
873 static void do_lasso_select_curve__doSelect(void *userData,
874  Nurb *UNUSED(nu),
875  BPoint *bp,
876  BezTriple *bezt,
877  int beztindex,
878  bool handles_visible,
879  const float screen_co[2])
880 {
881  LassoSelectUserData *data = userData;
882 
884  data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED);
885  if (bp) {
886  const bool is_select = bp->f1 & SELECT;
887  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
888  if (sel_op_result != -1) {
889  SET_FLAG_FROM_TEST(bp->f1, sel_op_result, data->select_flag);
890  data->is_changed = true;
891  }
892  }
893  else {
894  if (!handles_visible) {
895  /* can only be (beztindex == 1) here since handles are hidden */
896  const bool is_select = bezt->f2 & SELECT;
897  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
898  if (sel_op_result != -1) {
899  SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, data->select_flag);
900  }
901  bezt->f1 = bezt->f3 = bezt->f2;
902  data->is_changed = true;
903  }
904  else {
905  uint8_t *flag_p = (&bezt->f1) + beztindex;
906  const bool is_select = *flag_p & SELECT;
907  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
908  if (sel_op_result != -1) {
909  SET_FLAG_FROM_TEST(*flag_p, sel_op_result, data->select_flag);
910  data->is_changed = true;
911  }
912  }
913  }
914 }
915 
917  const int mcoords[][2],
918  const int mcoords_len,
919  const eSelectOp sel_op)
920 {
921  const bool deselect_all = (sel_op == SEL_OP_SET);
923  rcti rect;
924 
925  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
926 
927  view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
928 
929  Curve *curve = (Curve *)vc->obedit->data;
931 
932  /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */
933  if (deselect_all) {
935  data.select_flag = BEZT_FLAG_TEMP_TAG;
936  }
937 
938  ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
940 
941  /* Deselect items that were not added to selection (indicated by temp flag). */
942  if (deselect_all) {
944  }
945 
946  if (data.is_changed) {
948  }
949  return data.is_changed;
950 }
951 
952 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const float screen_co[2])
953 {
954  LassoSelectUserData *data = userData;
955  const bool is_select = bp->f1 & SELECT;
956  const bool is_inside =
957  (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
959  data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
960  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
961  if (sel_op_result != -1) {
962  SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT);
963  data->is_changed = true;
964  }
965 }
967  const int mcoords[][2],
968  const int mcoords_len,
969  const eSelectOp sel_op)
970 {
972  rcti rect;
973 
974  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
975 
976  view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
977 
978  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
979  data.is_changed |= ED_lattice_flags_set(vc->obedit, 0);
980  }
981 
982  ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
985  return data.is_changed;
986 }
987 
988 static void do_lasso_select_armature__doSelectBone(void *userData,
989  EditBone *ebone,
990  const float screen_co_a[2],
991  const float screen_co_b[2])
992 {
993  LassoSelectUserData *data = userData;
994  const bArmature *arm = data->vc->obedit->data;
995  if (!EBONE_VISIBLE(arm, ebone)) {
996  return;
997  }
998 
999  int is_ignore_flag = 0;
1000  int is_inside_flag = 0;
1001 
1002  if (screen_co_a[0] != IS_CLIPPED) {
1003  if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) &&
1005  data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) {
1006  is_inside_flag |= BONESEL_ROOT;
1007  }
1008  }
1009  else {
1010  is_ignore_flag |= BONESEL_ROOT;
1011  }
1012 
1013  if (screen_co_b[0] != IS_CLIPPED) {
1014  if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) &&
1016  data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) {
1017  is_inside_flag |= BONESEL_TIP;
1018  }
1019  }
1020  else {
1021  is_ignore_flag |= BONESEL_TIP;
1022  }
1023 
1024  if (is_ignore_flag == 0) {
1025  if (is_inside_flag == (BONE_ROOTSEL | BONE_TIPSEL) ||
1026  BLI_lasso_is_edge_inside(data->mcoords,
1027  data->mcoords_len,
1028  UNPACK2(screen_co_a),
1029  UNPACK2(screen_co_b),
1030  INT_MAX)) {
1031  is_inside_flag |= BONESEL_BONE;
1032  }
1033  }
1034 
1035  ebone->temp.i = is_inside_flag | (is_ignore_flag >> 16);
1036 }
1038  EditBone *ebone,
1039  const float screen_co_a[2],
1040  const float screen_co_b[2])
1041 {
1042  LassoSelectUserData *data = userData;
1043  bArmature *arm = data->vc->obedit->data;
1044  if (!EBONE_VISIBLE(arm, ebone)) {
1045  return;
1046  }
1047 
1048  const int is_ignore_flag = ebone->temp.i << 16;
1049  int is_inside_flag = ebone->temp.i & ~0xFFFF;
1050 
1051  /* - When #BONESEL_BONE is set, there is nothing to do.
1052  * - When #BONE_ROOTSEL or #BONE_TIPSEL have been set - they take priority over bone selection.
1053  */
1054  if (is_inside_flag & (BONESEL_BONE | BONE_ROOTSEL | BONE_TIPSEL)) {
1055  return;
1056  }
1057 
1059  data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) {
1060  is_inside_flag |= BONESEL_BONE;
1061  }
1062 
1063  ebone->temp.i = is_inside_flag | (is_ignore_flag >> 16);
1064 }
1065 
1067  const int mcoords[][2],
1068  const int mcoords_len,
1069  const eSelectOp sel_op)
1070 {
1072  rcti rect;
1073 
1074  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
1075 
1076  view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
1077 
1078  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
1080  }
1081 
1082  bArmature *arm = vc->obedit->data;
1083 
1085 
1087 
1088  /* Operate on fully visible (non-clipped) points. */
1091 
1092  /* Operate on bones as segments clipped to the viewport bounds
1093  * (needed to handle bones with both points outside the view).
1094  * A separate pass is needed since clipped coordinates can't be used for selecting joints. */
1097  &data,
1099 
1100  data.is_changed |= ED_armature_edit_select_op_from_tagged(vc->obedit->data, sel_op);
1101 
1102  if (data.is_changed) {
1104  }
1105  return data.is_changed;
1106 }
1107 
1108 static void do_lasso_select_mball__doSelectElem(void *userData,
1109  struct MetaElem *ml,
1110  const float screen_co[2])
1111 {
1112  LassoSelectUserData *data = userData;
1113  const bool is_select = ml->flag & SELECT;
1114  const bool is_inside =
1115  (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
1117  data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], INT_MAX));
1118  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
1119  if (sel_op_result != -1) {
1120  SET_FLAG_FROM_TEST(ml->flag, sel_op_result, SELECT);
1121  data->is_changed = true;
1122  }
1123 }
1125  const int mcoords[][2],
1126  const int mcoords_len,
1127  const eSelectOp sel_op)
1128 {
1130  rcti rect;
1131 
1132  MetaBall *mb = (MetaBall *)vc->obedit->data;
1133 
1134  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
1135 
1136  view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
1137 
1138  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
1139  data.is_changed |= BKE_mball_deselect_all(mb);
1140  }
1141 
1143 
1146 
1147  return data.is_changed;
1148 }
1149 
1150 static void do_lasso_select_meshobject__doSelectVert(void *userData,
1151  MVert *mv,
1152  const float screen_co[2],
1153  int UNUSED(index))
1154 {
1155  LassoSelectUserData *data = userData;
1156  const bool is_select = mv->flag & SELECT;
1157  const bool is_inside =
1158  (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
1160  data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
1161  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
1162  if (sel_op_result != -1) {
1163  SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT);
1164  data->is_changed = true;
1165  }
1166 }
1168  wmGenericUserData *wm_userdata,
1169  const int mcoords[][2],
1170  const int mcoords_len,
1171  const eSelectOp sel_op)
1172 {
1173  const bool use_zbuf = !XRAY_ENABLED(vc->v3d);
1174  Object *ob = vc->obact;
1175  Mesh *me = ob->data;
1176  rcti rect;
1177 
1178  if (me == NULL || me->totvert == 0) {
1179  return false;
1180  }
1181 
1182  bool changed = false;
1183  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
1184  /* flush selection at the end */
1185  changed |= paintvert_deselect_all_visible(ob, SEL_DESELECT, false);
1186  }
1187 
1188  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
1189 
1190  struct EditSelectBuf_Cache *esel = wm_userdata->data;
1191  if (use_zbuf) {
1192  if (wm_userdata->data == NULL) {
1194  esel = wm_userdata->data;
1196  vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL);
1197  }
1198  }
1199 
1200  if (use_zbuf) {
1201  if (esel->select_bitmap != NULL) {
1202  changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op);
1203  }
1204  }
1205  else {
1207 
1208  view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
1209 
1211 
1214 
1215  changed |= data.is_changed;
1216  }
1217 
1218  if (changed) {
1219  if (SEL_OP_CAN_DESELECT(sel_op)) {
1221  }
1223  paintvert_tag_select_update(vc->C, ob);
1224  }
1225 
1226  return changed;
1227 }
1229  wmGenericUserData *wm_userdata,
1230  const int mcoords[][2],
1231  const int mcoords_len,
1232  const eSelectOp sel_op)
1233 {
1234  Object *ob = vc->obact;
1235  Mesh *me = ob->data;
1236  rcti rect;
1237 
1238  if (me == NULL || me->totpoly == 0) {
1239  return false;
1240  }
1241 
1242  bool changed = false;
1243  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
1244  /* flush selection at the end */
1245  changed |= paintface_deselect_all_visible(vc->C, ob, SEL_DESELECT, false);
1246  }
1247 
1248  BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
1249 
1250  struct EditSelectBuf_Cache *esel = wm_userdata->data;
1251  if (esel == NULL) {
1253  esel = wm_userdata->data;
1255  vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL);
1256  }
1257 
1258  if (esel->select_bitmap) {
1259  changed |= edbm_backbuf_check_and_select_faces_obmode(me, esel, sel_op);
1260  }
1261 
1262  if (changed) {
1263  paintface_flush_flags(vc->C, ob, SELECT);
1264  }
1265  return changed;
1266 }
1267 
1269  ViewContext *vc,
1270  const int mcoords[][2],
1271  const int mcoords_len,
1272  const eSelectOp sel_op)
1273 {
1275  bool changed_multi = false;
1276 
1277  wmGenericUserData wm_userdata_buf = {0};
1278  wmGenericUserData *wm_userdata = &wm_userdata_buf;
1279 
1280  if (vc->obedit == NULL) { /* Object Mode */
1281  if (BKE_paint_select_face_test(ob)) {
1282  changed_multi |= do_lasso_select_paintface(vc, wm_userdata, mcoords, mcoords_len, sel_op);
1283  }
1284  else if (BKE_paint_select_vert_test(ob)) {
1285  changed_multi |= do_lasso_select_paintvert(vc, wm_userdata, mcoords, mcoords_len, sel_op);
1286  }
1287  else if (ob &&
1289  /* pass */
1290  }
1291  else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
1292  changed_multi |= PE_lasso_select(C, mcoords, mcoords_len, sel_op);
1293  }
1294  else if (ob && (ob->mode & OB_MODE_POSE)) {
1295  changed_multi |= do_lasso_select_pose(vc, mcoords, mcoords_len, sel_op);
1296  if (changed_multi) {
1298  }
1299  }
1300  else {
1301  changed_multi |= do_lasso_select_objects(vc, mcoords, mcoords_len, sel_op);
1302  if (changed_multi) {
1304  }
1305  }
1306  }
1307  else { /* Edit Mode */
1308  FOREACH_OBJECT_IN_MODE_BEGIN (vc->view_layer, vc->v3d, ob->type, ob->mode, ob_iter) {
1309  ED_view3d_viewcontext_init_object(vc, ob_iter);
1310  bool changed = false;
1311 
1312  switch (vc->obedit->type) {
1313  case OB_MESH:
1314  changed = do_lasso_select_mesh(vc, wm_userdata, mcoords, mcoords_len, sel_op);
1315  break;
1316  case OB_CURVES_LEGACY:
1317  case OB_SURF:
1318  changed = do_lasso_select_curve(vc, mcoords, mcoords_len, sel_op);
1319  break;
1320  case OB_LATTICE:
1321  changed = do_lasso_select_lattice(vc, mcoords, mcoords_len, sel_op);
1322  break;
1323  case OB_ARMATURE:
1324  changed = do_lasso_select_armature(vc, mcoords, mcoords_len, sel_op);
1325  if (changed) {
1327  }
1328  break;
1329  case OB_MBALL:
1330  changed = do_lasso_select_meta(vc, mcoords, mcoords_len, sel_op);
1331  break;
1332  default:
1333  BLI_assert_msg(0, "lasso select on incorrect object type");
1334  break;
1335  }
1336 
1337  if (changed) {
1340  changed_multi = true;
1341  }
1342  }
1344  }
1345 
1346  WM_generic_user_data_free(wm_userdata);
1347 
1348  return changed_multi;
1349 }
1350 
1351 /* lasso operator gives properties, but since old code works
1352  * with short array we convert */
1354 {
1355  ViewContext vc;
1356  int mcoords_len;
1357  const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
1358 
1359  if (mcoords) {
1363 
1364  /* setup view context for argument to callbacks */
1366 
1367  eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
1368  bool changed_multi = view3d_lasso_select(C, &vc, mcoords, mcoords_len, sel_op);
1369 
1370  MEM_freeN((void *)mcoords);
1371 
1372  if (changed_multi) {
1373  return OPERATOR_FINISHED;
1374  }
1375  return OPERATOR_CANCELLED;
1376  }
1377  return OPERATOR_PASS_THROUGH;
1378 }
1379 
1381 {
1382  ot->name = "Lasso Select";
1383  ot->description = "Select items using lasso selection";
1384  ot->idname = "VIEW3D_OT_select_lasso";
1385 
1391 
1392  /* flags */
1394 
1395  /* properties */
1398 }
1399 
1402 /* -------------------------------------------------------------------- */
1406 /* The max number of menu items in an object select menu */
1407 typedef struct SelMenuItemF {
1408  char idname[MAX_ID_NAME - 2];
1409  int icon;
1411  void *item_ptr;
1413 
1414 #define SEL_MENU_SIZE 22
1416 
1417 /* special (crappy) operator only for menu select */
1419  PointerRNA *UNUSED(ptr),
1420  PropertyRNA *UNUSED(prop),
1421  bool *r_free)
1422 {
1423  EnumPropertyItem *item = NULL, item_tmp = {0};
1424  int totitem = 0;
1425  int i = 0;
1426 
1427  /* Don't need context but avoid API doc-generation using this. */
1428  if (C == NULL || object_mouse_select_menu_data[i].idname[0] == '\0') {
1429  return DummyRNA_NULL_items;
1430  }
1431 
1432  for (; i < SEL_MENU_SIZE && object_mouse_select_menu_data[i].idname[0] != '\0'; i++) {
1434  item_tmp.identifier = object_mouse_select_menu_data[i].idname;
1435  item_tmp.value = i;
1436  item_tmp.icon = object_mouse_select_menu_data[i].icon;
1437  RNA_enum_item_add(&item, &totitem, &item_tmp);
1438  }
1439 
1440  RNA_enum_item_end(&item, &totitem);
1441  *r_free = true;
1442 
1443  return item;
1444 }
1445 
1447 {
1448  const int name_index = RNA_enum_get(op->ptr, "name");
1449  const bool extend = RNA_boolean_get(op->ptr, "extend");
1450  const bool deselect = RNA_boolean_get(op->ptr, "deselect");
1451  const bool toggle = RNA_boolean_get(op->ptr, "toggle");
1452  bool changed = false;
1453  const char *name = object_mouse_select_menu_data[name_index].idname;
1454 
1455  View3D *v3d = CTX_wm_view3d(C);
1456  ViewLayer *view_layer = CTX_data_view_layer(C);
1457  const Base *oldbasact = BASACT(view_layer);
1458 
1459  Base *basact = NULL;
1460  CTX_DATA_BEGIN (C, Base *, base, selectable_bases) {
1461  /* This is a bit dodgy, there should only be ONE object with this name,
1462  * but library objects can mess this up. */
1463  if (STREQ(name, base->object->id.name + 2)) {
1464  basact = base;
1465  break;
1466  }
1467  }
1468  CTX_DATA_END;
1469 
1470  if (basact == NULL) {
1471  return OPERATOR_CANCELLED;
1472  }
1473  UNUSED_VARS_NDEBUG(v3d);
1474  BLI_assert(BASE_SELECTABLE(v3d, basact));
1475 
1476  if (extend) {
1478  changed = true;
1479  }
1480  else if (deselect) {
1482  changed = true;
1483  }
1484  else if (toggle) {
1485  if (basact->flag & BASE_SELECTED) {
1486  if (basact == oldbasact) {
1488  changed = true;
1489  }
1490  }
1491  else {
1493  changed = true;
1494  }
1495  }
1496  else {
1497  object_deselect_all_except(view_layer, basact);
1499  changed = true;
1500  }
1501 
1502  if ((oldbasact != basact)) {
1503  ED_object_base_activate(C, basact);
1504  }
1505 
1506  /* weak but ensures we activate menu again before using the enum */
1508 
1509  /* undo? */
1510  if (changed) {
1514 
1516 
1517  return OPERATOR_FINISHED;
1518  }
1519  return OPERATOR_CANCELLED;
1520 }
1521 
1523 {
1524  PropertyRNA *prop;
1525 
1526  /* identifiers */
1527  ot->name = "Select Menu";
1528  ot->description = "Menu object selection";
1529  ot->idname = "VIEW3D_OT_select_menu";
1530 
1531  /* api callbacks */
1534 
1535  /* flags */
1537 
1538  /* #Object.id.name to select (dynamic enum). */
1539  prop = RNA_def_enum(ot->srna, "name", DummyRNA_NULL_items, 0, "Object Name", "");
1542  ot->prop = prop;
1543 
1544  prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend", "");
1546  prop = RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
1548  prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
1550 }
1551 
1556  ViewContext *vc,
1557  const GPUSelectResult *buffer,
1558  const int hits,
1559  const int mval[2],
1560  const struct SelectPick_Params *params,
1561  Base **r_basact)
1562 {
1563  int base_count = 0;
1564  bool ok;
1565  LinkNodePair linklist = {NULL, NULL};
1566 
1567  /* handle base->object->select_id */
1568  CTX_DATA_BEGIN (C, Base *, base, selectable_bases) {
1569  ok = false;
1570 
1571  /* two selection methods, the CTRL select uses max dist of 15 */
1572  if (buffer) {
1573  for (int a = 0; a < hits; a++) {
1574  /* index was converted */
1575  if (base->object->runtime.select_id == (buffer[a].id & ~0xFFFF0000)) {
1576  ok = true;
1577  break;
1578  }
1579  }
1580  }
1581  else {
1582  const int dist = 15 * U.pixelsize;
1583  if (ED_view3d_project_base(vc->region, base) == V3D_PROJ_RET_OK) {
1584  const int delta_px[2] = {base->sx - mval[0], base->sy - mval[1]};
1585  if (len_manhattan_v2_int(delta_px) < dist) {
1586  ok = true;
1587  }
1588  }
1589  }
1590 
1591  if (ok) {
1592  base_count++;
1593  BLI_linklist_append(&linklist, base);
1594 
1595  if (base_count == SEL_MENU_SIZE) {
1596  break;
1597  }
1598  }
1599  }
1600  CTX_DATA_END;
1601 
1602  *r_basact = NULL;
1603 
1604  if (base_count == 0) {
1605  return false;
1606  }
1607  if (base_count == 1) {
1608  Base *base = (Base *)linklist.list->link;
1609  BLI_linklist_free(linklist.list, NULL);
1610  *r_basact = base;
1611  return false;
1612  }
1613 
1614  /* UI, full in static array values that we later use in an enum function */
1615  LinkNode *node;
1616  int i;
1617 
1619 
1620  for (node = linklist.list, i = 0; node; node = node->next, i++) {
1621  Base *base = node->link;
1622  Object *ob = base->object;
1623  const char *name = ob->id.name + 2;
1624 
1627  }
1628 
1629  wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_select_menu", false);
1630  PointerRNA ptr;
1631 
1633  RNA_boolean_set(&ptr, "extend", params->sel_op == SEL_OP_ADD);
1634  RNA_boolean_set(&ptr, "deselect", params->sel_op == SEL_OP_SUB);
1635  RNA_boolean_set(&ptr, "toggle", params->sel_op == SEL_OP_XOR);
1638 
1639  BLI_linklist_free(linklist.list, NULL);
1640  return true;
1641 }
1642 
1644 {
1645  const int name_index = RNA_enum_get(op->ptr, "name");
1646 
1647  const struct SelectPick_Params params = {
1648  .sel_op = ED_select_op_from_operator(op->ptr),
1649  };
1650 
1651  View3D *v3d = CTX_wm_view3d(C);
1652  ViewLayer *view_layer = CTX_data_view_layer(C);
1653  const Base *oldbasact = BASACT(view_layer);
1654 
1655  Base *basact = object_mouse_select_menu_data[name_index].base_ptr;
1656 
1657  if (basact == NULL) {
1658  return OPERATOR_CANCELLED;
1659  }
1660 
1661  BLI_assert(BASE_SELECTABLE(v3d, basact));
1662 
1663  if (basact->object->mode & OB_MODE_EDIT) {
1664  EditBone *ebone = (EditBone *)object_mouse_select_menu_data[name_index].item_ptr;
1666  }
1667  else {
1668  bPoseChannel *pchan = (bPoseChannel *)object_mouse_select_menu_data[name_index].item_ptr;
1669  ED_armature_pose_select_pick_bone(view_layer, v3d, basact->object, pchan->bone, &params);
1670  }
1671 
1672  /* Weak but ensures we activate the menu again before using the enum. */
1674 
1675  /* We make the armature selected:
1676  * Not-selected active object in pose-mode won't work well for tools. */
1678 
1681 
1682  /* In weight-paint, we use selected bone to select vertex-group,
1683  * so don't switch to new active object. */
1684  if (oldbasact) {
1685  if (basact->object->mode & OB_MODE_EDIT) {
1686  /* Pass. */
1687  }
1688  else if (oldbasact->object->mode & OB_MODE_ALL_WEIGHT_PAINT) {
1689  /* Prevent activating.
1690  * Selection causes this to be considered the 'active' pose in weight-paint mode.
1691  * Eventually this limitation may be removed.
1692  * For now, de-select all other pose objects deforming this mesh. */
1693  ED_armature_pose_select_in_wpaint_mode(view_layer, basact);
1694  }
1695  else {
1696  if (oldbasact != basact) {
1697  ED_object_base_activate(C, basact);
1698  }
1699  }
1700  }
1701 
1702  /* Undo? */
1707 
1709 
1710  return OPERATOR_FINISHED;
1711 }
1712 
1714 {
1715  PropertyRNA *prop;
1716 
1717  /* identifiers */
1718  ot->name = "Select Menu";
1719  ot->description = "Menu bone selection";
1720  ot->idname = "VIEW3D_OT_bone_select_menu";
1721 
1722  /* api callbacks */
1725 
1726  /* flags */
1728 
1729  /* #Object.id.name to select (dynamic enum). */
1730  prop = RNA_def_enum(ot->srna, "name", DummyRNA_NULL_items, 0, "Bone Name", "");
1733  ot->prop = prop;
1734 
1735  prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend", "");
1737  prop = RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
1739  prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
1741 }
1742 
1747  const GPUSelectResult *buffer,
1748  const int hits,
1749  const bool is_editmode,
1750  const struct SelectPick_Params *params)
1751 {
1752  BLI_assert(buffer);
1753 
1754  int bone_count = 0;
1755  LinkNodePair base_list = {NULL, NULL};
1756  LinkNodePair bone_list = {NULL, NULL};
1757  GSet *added_bones = BLI_gset_ptr_new("Bone mouse select menu");
1758 
1759  /* Select logic taken from ed_armature_pick_bone_from_selectbuffer_impl in armature_select.c */
1760  for (int a = 0; a < hits; a++) {
1761  void *bone_ptr = NULL;
1762  Base *bone_base = NULL;
1763  uint hitresult = buffer[a].id;
1764 
1765  if (!(hitresult & BONESEL_ANY)) {
1766  /* To avoid including objects in selection. */
1767  continue;
1768  }
1769 
1770  hitresult &= ~BONESEL_ANY;
1771  const uint hit_object = hitresult & 0xFFFF;
1772 
1773  /* Find the hit bone base (armature object). */
1774  CTX_DATA_BEGIN (C, Base *, base, selectable_bases) {
1775  if (base->object->runtime.select_id == hit_object) {
1776  bone_base = base;
1777  break;
1778  }
1779  }
1780  CTX_DATA_END;
1781 
1782  if (!bone_base) {
1783  continue;
1784  }
1785 
1786  /* Determine what the current bone is */
1787  if (is_editmode) {
1788  EditBone *ebone;
1789  const uint hit_bone = (hitresult & ~BONESEL_ANY) >> 16;
1790  bArmature *arm = bone_base->object->data;
1791  ebone = BLI_findlink(arm->edbo, hit_bone);
1792  if (ebone && !(ebone->flag & BONE_UNSELECTABLE)) {
1793  bone_ptr = ebone;
1794  }
1795  }
1796  else {
1797  bPoseChannel *pchan;
1798  const uint hit_bone = (hitresult & ~BONESEL_ANY) >> 16;
1799  pchan = BLI_findlink(&bone_base->object->pose->chanbase, hit_bone);
1800  if (pchan && !(pchan->bone->flag & BONE_UNSELECTABLE)) {
1801  bone_ptr = pchan;
1802  }
1803  }
1804 
1805  if (!bone_ptr) {
1806  continue;
1807  }
1808  /* We can hit a bone multiple times, so make sure we are not adding an already included bone
1809  * to the list. */
1810  const bool is_duplicate_bone = BLI_gset_haskey(added_bones, bone_ptr);
1811 
1812  if (!is_duplicate_bone) {
1813  bone_count++;
1814  BLI_linklist_append(&base_list, bone_base);
1815  BLI_linklist_append(&bone_list, bone_ptr);
1816  BLI_gset_insert(added_bones, bone_ptr);
1817 
1818  if (bone_count == SEL_MENU_SIZE) {
1819  break;
1820  }
1821  }
1822  }
1823 
1824  BLI_gset_free(added_bones, NULL);
1825 
1826  if (bone_count == 0) {
1827  return false;
1828  }
1829  if (bone_count == 1) {
1830  BLI_linklist_free(base_list.list, NULL);
1831  BLI_linklist_free(bone_list.list, NULL);
1832  return false;
1833  }
1834 
1835  /* UI, full in static array values that we later use in an enum function */
1836  LinkNode *bone_node, *base_node;
1837  int i;
1838 
1840 
1841  for (base_node = base_list.list, bone_node = bone_list.list, i = 0; bone_node;
1842  base_node = base_node->next, bone_node = bone_node->next, i++) {
1843  char *name;
1844 
1846 
1847  if (is_editmode) {
1848  EditBone *ebone = bone_node->link;
1850  name = ebone->name;
1851  }
1852  else {
1853  bPoseChannel *pchan = bone_node->link;
1855  name = pchan->name;
1856  }
1857 
1859  object_mouse_select_menu_data[i].icon = ICON_BONE_DATA;
1860  }
1861 
1862  wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_bone_select_menu", false);
1863  PointerRNA ptr;
1864 
1866  RNA_boolean_set(&ptr, "extend", params->sel_op == SEL_OP_ADD);
1867  RNA_boolean_set(&ptr, "deselect", params->sel_op == SEL_OP_SUB);
1868  RNA_boolean_set(&ptr, "toggle", params->sel_op == SEL_OP_XOR);
1871 
1872  BLI_linklist_free(base_list.list, NULL);
1873  BLI_linklist_free(bone_list.list, NULL);
1874  return true;
1875 }
1876 
1877 static bool selectbuffer_has_bones(const GPUSelectResult *buffer, const uint hits)
1878 {
1879  for (uint i = 0; i < hits; i++) {
1880  if (buffer[i].id & 0xFFFF0000) {
1881  return true;
1882  }
1883  }
1884  return false;
1885 }
1886 
1887 /* utility function for mixed_bones_object_selectbuffer */
1889 {
1890  return hits15;
1891 }
1892 
1893 static int selectbuffer_ret_hits_9(GPUSelectResult *buffer, const int hits15, const int hits9)
1894 {
1895  const int ofs = hits15;
1896  memcpy(buffer, buffer + ofs, hits9 * sizeof(GPUSelectResult));
1897  return hits9;
1898 }
1899 
1901  const int hits15,
1902  const int hits9,
1903  const int hits5)
1904 {
1905  const int ofs = hits15 + hits9;
1906  memcpy(buffer, buffer + ofs, hits5 * sizeof(GPUSelectResult));
1907  return hits5;
1908 }
1909 
1920  const int buffer_len,
1921  const int mval[2],
1922  eV3DSelectObjectFilter select_filter,
1923  bool do_nearest,
1924  bool do_nearest_xray_if_supported,
1925  const bool do_material_slot_selection)
1926 {
1927  rcti rect;
1928  int hits15, hits9 = 0, hits5 = 0;
1929  bool has_bones15 = false, has_bones9 = false, has_bones5 = false;
1930 
1931  int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
1932  int hits = 0;
1933 
1934  if (do_nearest_xray_if_supported) {
1935  if ((U.gpu_flag & USER_GPU_FLAG_NO_DEPT_PICK) == 0) {
1936  select_mode = VIEW3D_SELECT_PICK_ALL;
1937  }
1938  }
1939 
1940  /* we _must_ end cache before return, use 'goto finally' */
1942 
1943  BLI_rcti_init_pt_radius(&rect, mval, 14);
1944  hits15 = view3d_opengl_select_ex(
1945  vc, buffer, buffer_len, &rect, select_mode, select_filter, do_material_slot_selection);
1946  if (hits15 == 1) {
1947  hits = selectbuffer_ret_hits_15(buffer, hits15);
1948  goto finally;
1949  }
1950  else if (hits15 > 0) {
1951  int ofs;
1952  has_bones15 = selectbuffer_has_bones(buffer, hits15);
1953 
1954  ofs = hits15;
1955  BLI_rcti_init_pt_radius(&rect, mval, 9);
1956  hits9 = view3d_opengl_select(
1957  vc, buffer + ofs, buffer_len - ofs, &rect, select_mode, select_filter);
1958  if (hits9 == 1) {
1959  hits = selectbuffer_ret_hits_9(buffer, hits15, hits9);
1960  goto finally;
1961  }
1962  else if (hits9 > 0) {
1963  has_bones9 = selectbuffer_has_bones(buffer + ofs, hits9);
1964 
1965  ofs += hits9;
1966  BLI_rcti_init_pt_radius(&rect, mval, 5);
1967  hits5 = view3d_opengl_select(
1968  vc, buffer + ofs, buffer_len - ofs, &rect, select_mode, select_filter);
1969  if (hits5 == 1) {
1970  hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
1971  goto finally;
1972  }
1973  else if (hits5 > 0) {
1974  has_bones5 = selectbuffer_has_bones(buffer + ofs, hits5);
1975  }
1976  }
1977 
1978  if (has_bones5) {
1979  hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
1980  goto finally;
1981  }
1982  else if (has_bones9) {
1983  hits = selectbuffer_ret_hits_9(buffer, hits15, hits9);
1984  goto finally;
1985  }
1986  else if (has_bones15) {
1987  hits = selectbuffer_ret_hits_15(buffer, hits15);
1988  goto finally;
1989  }
1990 
1991  if (hits5 > 0) {
1992  hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
1993  goto finally;
1994  }
1995  else if (hits9 > 0) {
1996  hits = selectbuffer_ret_hits_9(buffer, hits15, hits9);
1997  goto finally;
1998  }
1999  else {
2000  hits = selectbuffer_ret_hits_15(buffer, hits15);
2001  goto finally;
2002  }
2003  }
2004 
2005 finally:
2007  return hits;
2008 }
2009 
2012  const int buffer_len,
2013  const int mval[2],
2014  eV3DSelectObjectFilter select_filter,
2015  bool use_cycle,
2016  bool enumerate,
2017  bool *r_do_nearest)
2018 {
2019  bool do_nearest = false;
2020  View3D *v3d = vc->v3d;
2021 
2022  /* define if we use solid nearest select or not */
2023  if (use_cycle) {
2024  /* Update the coordinates (even if the return value isn't used). */
2025  const bool has_motion = WM_cursor_test_motion_and_update(mval);
2026  if (!XRAY_ACTIVE(v3d)) {
2027  do_nearest = has_motion;
2028  }
2029  }
2030  else {
2031  if (!XRAY_ACTIVE(v3d)) {
2032  do_nearest = true;
2033  }
2034  }
2035 
2036  if (r_do_nearest) {
2037  *r_do_nearest = do_nearest;
2038  }
2039 
2040  do_nearest = do_nearest && !enumerate;
2041 
2043  vc, buffer, buffer_len, mval, select_filter, do_nearest, true, false);
2044 
2045  return hits;
2046 }
2047 
2052 static int gpu_select_buffer_depth_id_cmp(const void *sel_a_p, const void *sel_b_p)
2053 {
2054  GPUSelectResult *a = (GPUSelectResult *)sel_a_p;
2055  GPUSelectResult *b = (GPUSelectResult *)sel_b_p;
2056 
2057  if (a->depth < b->depth) {
2058  return -1;
2059  }
2060  if (a->depth > b->depth) {
2061  return 1;
2062  }
2063 
2064  /* Depths match, sort by id. */
2065  uint sel_a = a->id;
2066  uint sel_b = b->id;
2067 
2068 #ifdef __BIG_ENDIAN__
2069  BLI_endian_switch_uint32(&sel_a);
2070  BLI_endian_switch_uint32(&sel_b);
2071 #endif
2072 
2073  if (sel_a < sel_b) {
2074  return -1;
2075  }
2076  if (sel_a > sel_b) {
2077  return 1;
2078  }
2079  return 0;
2080 }
2081 
2090  const GPUSelectResult *buffer,
2091  int hits,
2092  bool do_nearest,
2093  bool has_bones,
2094  bool do_bones_get_priotity,
2095  int *r_select_id_subelem)
2096 {
2097  ViewLayer *view_layer = vc->view_layer;
2098  View3D *v3d = vc->v3d;
2099  int a;
2100 
2101  bool found = false;
2102  int select_id = 0;
2103  int select_id_subelem = 0;
2104 
2105  if (do_nearest) {
2106  uint min = 0xFFFFFFFF;
2107  int hit_index = -1;
2108 
2109  if (has_bones && do_bones_get_priotity) {
2110  /* we skip non-bone hits */
2111  for (a = 0; a < hits; a++) {
2112  if (min > buffer[a].depth && (buffer[a].id & 0xFFFF0000)) {
2113  min = buffer[a].depth;
2114  hit_index = a;
2115  }
2116  }
2117  }
2118  else {
2119 
2120  for (a = 0; a < hits; a++) {
2121  /* Any object. */
2122  if (min > buffer[a].depth) {
2123  min = buffer[a].depth;
2124  hit_index = a;
2125  }
2126  }
2127  }
2128 
2129  if (hit_index != -1) {
2130  select_id = buffer[hit_index].id & 0xFFFF;
2131  select_id_subelem = (buffer[hit_index].id & 0xFFFF0000) >> 16;
2132  found = true;
2133  /* No need to set `min` to `buffer[hit_index].depth`, it's not used from now on. */
2134  }
2135  }
2136  else {
2137 
2138  {
2139  GPUSelectResult *buffer_sorted = MEM_mallocN(sizeof(*buffer_sorted) * hits, __func__);
2140  memcpy(buffer_sorted, buffer, sizeof(*buffer_sorted) * hits);
2141  /* Remove non-bone objects. */
2142  if (has_bones && do_bones_get_priotity) {
2143  /* Loop backwards to reduce re-ordering. */
2144  for (a = hits - 1; a >= 0; a--) {
2145  if ((buffer_sorted[a].id & 0xFFFF0000) == 0) {
2146  buffer_sorted[a] = buffer_sorted[--hits];
2147  }
2148  }
2149  }
2150  qsort(buffer_sorted, hits, sizeof(GPUSelectResult), gpu_select_buffer_depth_id_cmp);
2151  buffer = buffer_sorted;
2152  }
2153 
2154  int hit_index = -1;
2155 
2156  /* It's possible there are no hits (all objects contained bones). */
2157  if (hits > 0) {
2158  /* Only exclude active object when it is selected. */
2159  if (BASACT(view_layer) && (BASACT(view_layer)->flag & BASE_SELECTED)) {
2160  const int select_id_active = BASACT(view_layer)->object->runtime.select_id;
2161  for (int i_next = 0, i_prev = hits - 1; i_next < hits; i_prev = i_next++) {
2162  if ((select_id_active == (buffer[i_prev].id & 0xFFFF)) &&
2163  (select_id_active != (buffer[i_next].id & 0xFFFF))) {
2164  hit_index = i_next;
2165  break;
2166  }
2167  }
2168  }
2169 
2170  /* When the active object is unselected or not in `buffer`, use the nearest. */
2171  if (hit_index == -1) {
2172  /* Just pick the nearest. */
2173  hit_index = 0;
2174  }
2175  }
2176 
2177  if (hit_index != -1) {
2178  select_id = buffer[hit_index].id & 0xFFFF;
2179  select_id_subelem = (buffer[hit_index].id & 0xFFFF0000) >> 16;
2180  found = true;
2181  }
2182  MEM_freeN((void *)buffer);
2183  }
2184 
2185  Base *basact = NULL;
2186  if (found) {
2187  for (Base *base = FIRSTBASE(view_layer); base; base = base->next) {
2188  if (has_bones ? BASE_VISIBLE(v3d, base) : BASE_SELECTABLE(v3d, base)) {
2189  if (base->object->runtime.select_id == select_id) {
2190  basact = base;
2191  break;
2192  }
2193  }
2194  }
2195 
2196  if (basact && r_select_id_subelem) {
2197  *r_select_id_subelem = select_id_subelem;
2198  }
2199  }
2200 
2201  return basact;
2202 }
2203 
2204 static Base *mouse_select_object_center(ViewContext *vc, Base *startbase, const int mval[2])
2205 {
2206  ARegion *region = vc->region;
2207  ViewLayer *view_layer = vc->view_layer;
2208  View3D *v3d = vc->v3d;
2209 
2210  Base *oldbasact = BASACT(view_layer);
2211 
2212  const float mval_fl[2] = {(float)mval[0], (float)mval[1]};
2213  float dist = ED_view3d_select_dist_px() * 1.3333f;
2214  Base *basact = NULL;
2215 
2216  /* Put the active object at a disadvantage to cycle through other objects. */
2217  const float penalty_dist = 10.0f * UI_DPI_FAC;
2218  Base *base = startbase;
2219  while (base) {
2220  if (BASE_SELECTABLE(v3d, base)) {
2221  float screen_co[2];
2223  region, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_DEFAULT) ==
2224  V3D_PROJ_RET_OK) {
2225  float dist_test = len_manhattan_v2v2(mval_fl, screen_co);
2226  if (base == oldbasact) {
2227  dist_test += penalty_dist;
2228  }
2229  if (dist_test < dist) {
2230  dist = dist_test;
2231  basact = base;
2232  }
2233  }
2234  }
2235  base = base->next;
2236 
2237  if (base == NULL) {
2238  base = FIRSTBASE(view_layer);
2239  }
2240  if (base == startbase) {
2241  break;
2242  }
2243  }
2244  return basact;
2245 }
2246 
2248  const int mval[2],
2249  int *r_material_slot)
2250 {
2252  ViewContext vc;
2253  Base *basact = NULL;
2255 
2256  /* setup view context for argument to callbacks */
2259 
2261 
2262  const bool do_nearest = !XRAY_ACTIVE(vc.v3d);
2263  const bool do_material_slot_selection = r_material_slot != NULL;
2264  const int hits = mixed_bones_object_selectbuffer(&vc,
2265  buffer,
2266  ARRAY_SIZE(buffer),
2267  mval,
2269  do_nearest,
2270  false,
2271  do_material_slot_selection);
2272 
2273  if (hits > 0) {
2274  const bool has_bones = (r_material_slot == NULL) && selectbuffer_has_bones(buffer, hits);
2275  basact = mouse_select_eval_buffer(
2276  &vc, buffer, hits, do_nearest, has_bones, true, r_material_slot);
2277  }
2278 
2279  return basact;
2280 }
2281 
2283 {
2285 }
2286 
2288 {
2289  Base *base = ED_view3d_give_base_under_cursor(C, mval);
2290  if (base) {
2291  return base->object;
2292  }
2293  return NULL;
2294 }
2295 
2297  const int mval[2],
2298  int *r_material_slot)
2299 {
2300  Base *base = ed_view3d_give_base_under_cursor_ex(C, mval, r_material_slot);
2301  if (base) {
2302  return base->object;
2303  }
2304  return NULL;
2305 }
2306 
2308 {
2309  return ED_view3d_give_object_under_cursor(C, mval) != NULL;
2310 }
2311 
2312 static void deselect_all_tracks(MovieTracking *tracking)
2313 {
2314  MovieTrackingObject *object;
2315 
2316  object = tracking->objects.first;
2317  while (object) {
2318  ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
2319  MovieTrackingTrack *track = tracksbase->first;
2320 
2321  while (track) {
2323 
2324  track = track->next;
2325  }
2326 
2327  object = object->next;
2328  }
2329 }
2330 
2332  Scene *scene,
2333  Base *basact,
2334  MovieClip *clip,
2335  const struct GPUSelectResult *buffer,
2336  const short hits,
2337  const struct SelectPick_Params *params)
2338 {
2339  bool changed = false;
2340  bool found = false;
2341 
2342  MovieTracking *tracking = &clip->tracking;
2343  ListBase *tracksbase = NULL;
2345 
2346  for (int i = 0; i < hits; i++) {
2347  const int hitresult = buffer[i].id;
2348 
2349  /* If there's bundles in buffer select bundles first,
2350  * so non-camera elements should be ignored in buffer. */
2351  if (basact->object->runtime.select_id != (hitresult & 0xFFFF)) {
2352  continue;
2353  }
2354  /* Index of bundle is 1<<16-based. if there's no "bone" index
2355  * in height word, this buffer value belongs to camera. not to bundle. */
2356  if ((hitresult & 0xFFFF0000) == 0) {
2357  continue;
2358  }
2359 
2360  track = BKE_tracking_track_get_indexed(&clip->tracking, hitresult >> 16, &tracksbase);
2361  found = true;
2362  break;
2363  }
2364 
2365  /* Note `params->deselect_all` is ignored for tracks as in this case
2366  * all objects will be de-selected (not tracks). */
2367  if (params->sel_op == SEL_OP_SET) {
2368  if ((found && params->select_passthrough) && TRACK_SELECTED(track)) {
2369  found = false;
2370  }
2371  else if (found /* `|| params->deselect_all` */) {
2372  /* Deselect everything. */
2373  deselect_all_tracks(tracking);
2374  changed = true;
2375  }
2376  }
2377 
2378  if (found) {
2379  switch (params->sel_op) {
2380  case SEL_OP_ADD: {
2381  BKE_tracking_track_select(tracksbase, track, TRACK_AREA_ALL, true);
2382  break;
2383  }
2384  case SEL_OP_SUB: {
2386  break;
2387  }
2388  case SEL_OP_XOR: {
2389  if (TRACK_SELECTED(track)) {
2391  }
2392  else {
2393  BKE_tracking_track_select(tracksbase, track, TRACK_AREA_ALL, true);
2394  }
2395  break;
2396  }
2397  case SEL_OP_SET: {
2398  BKE_tracking_track_select(tracksbase, track, TRACK_AREA_ALL, false);
2399  break;
2400  }
2401  case SEL_OP_AND: {
2402  BLI_assert_unreachable(); /* Doesn't make sense for picking. */
2403  break;
2404  }
2405  }
2406 
2411 
2412  changed = true;
2413  }
2414 
2415  return changed || found;
2416 }
2417 
2431  const int mval[2],
2432  const struct SelectPick_Params *params,
2433  const bool center,
2434  const bool enumerate,
2435  const bool object_only)
2436 {
2438  ViewContext vc;
2439  /* Setup view context for argument to callbacks. */
2441 
2442  Scene *scene = vc.scene;
2443  View3D *v3d = vc.v3d;
2444 
2445  /* Menu activation may find a base to make active (if it only finds a single item to select). */
2446  Base *basact_override = NULL;
2447 
2448  const bool is_obedit = (vc.obedit != NULL);
2449  if (object_only) {
2450  /* Signal for #view3d_opengl_select to skip edit-mode objects. */
2451  vc.obedit = NULL;
2452  }
2453 
2454  /* Set for GPU depth buffer picking, leave NULL when selecting by center. */
2455  struct {
2457  int hits;
2458  bool do_nearest;
2459  bool has_bones;
2460  } *gpu = NULL;
2461 
2462  /* First handle menu selection, early exit if a menu opens
2463  * since this takes ownership of the selection action.
2464  *
2465  * Even when there is no menu `basact_override` may be set to avoid having to re-find
2466  * the item under the cursor. */
2467 
2468  if (center == false) {
2469  gpu = MEM_mallocN(sizeof(*gpu), __func__);
2470  gpu->do_nearest = false;
2471  gpu->has_bones = false;
2472 
2473  /* If objects have pose-mode set, the bones are in the same selection buffer. */
2474  const eV3DSelectObjectFilter select_filter = ((object_only == false) ?
2476  vc.obact) :
2479  gpu->buffer,
2480  ARRAY_SIZE(gpu->buffer),
2481  mval,
2482  select_filter,
2483  true,
2484  enumerate,
2485  &gpu->do_nearest);
2486  gpu->has_bones = (object_only && gpu->hits > 0) ?
2487  false :
2488  selectbuffer_has_bones(gpu->buffer, gpu->hits);
2489  }
2490 
2491  /* First handle menu selection, early exit when a menu was opened.
2492  * Otherwise fall through to regular selection. */
2493  if (enumerate) {
2494  bool has_menu = false;
2495  if (center) {
2496  if (object_mouse_select_menu(C, &vc, NULL, 0, mval, params, &basact_override)) {
2497  has_menu = true;
2498  }
2499  }
2500  else {
2501  if (gpu->hits != 0) {
2502  if (gpu->has_bones && bone_mouse_select_menu(C, gpu->buffer, gpu->hits, false, params)) {
2503  has_menu = true;
2504  }
2505  else if (object_mouse_select_menu(
2506  C, &vc, gpu->buffer, gpu->hits, mval, params, &basact_override)) {
2507  has_menu = true;
2508  }
2509  }
2510  }
2511 
2512  /* Let the menu handle any further actions. */
2513  if (has_menu) {
2514  if (gpu != NULL) {
2515  MEM_freeN(gpu);
2516  }
2517  return false;
2518  }
2519  }
2520 
2521  /* No menu, continue with selection. */
2522 
2523  ViewLayer *view_layer = vc.view_layer;
2524  /* Don't set when the context has no active object (hidden), see: T60807. */
2525  const Base *oldbasact = vc.obact ? BASACT(view_layer) : NULL;
2526  /* Always start list from `basact` when cycling the selection. */
2527  Base *startbase = (oldbasact && oldbasact->next) ? oldbasact->next : FIRSTBASE(view_layer);
2528 
2529  /* The next object's base to make active. */
2530  Base *basact = NULL;
2531  const eObjectMode object_mode = oldbasact ? oldbasact->object->mode : OB_MODE_OBJECT;
2532 
2533  /* When enabled, don't attempt any further selection. */
2534  bool handled = false;
2535 
2536  /* Split `changed` into data-types so their associated updates can be properly performed.
2537  * This is also needed as multiple changes may happen at once.
2538  * Selecting a pose-bone or track can also select the object for e.g. */
2539  bool changed_object = false;
2540  bool changed_pose = false;
2541  bool changed_track = false;
2542 
2543  /* Handle setting the new base active (even when `handled == true`). */
2544  bool use_activate_selected_base = false;
2545 
2546  if (center) {
2547  if (basact_override) {
2548  basact = basact_override;
2549  }
2550  else {
2551  basact = mouse_select_object_center(&vc, startbase, mval);
2552  }
2553  }
2554  else {
2555  if (basact_override) {
2556  basact = basact_override;
2557  }
2558  else {
2559  /* Regarding bone priority.
2560  *
2561  * - When in pose-bone, it's useful that any selection containing a bone
2562  * gets priority over other geometry (background scenery for example).
2563  *
2564  * - When in object-mode, don't prioritize bones as it would cause
2565  * pose-objects behind other objects to get priority
2566  * (mainly noticeable when #SCE_OBJECT_MODE_LOCK is disabled).
2567  *
2568  * This way prioritizing based on pose-mode has a bias to stay in pose-mode
2569  * without having to enforce this through locking the object mode. */
2570  bool do_bones_get_priotity = (object_mode & OB_MODE_POSE) != 0;
2571 
2572  basact = (gpu->hits > 0) ? mouse_select_eval_buffer(&vc,
2573  gpu->buffer,
2574  gpu->hits,
2575  gpu->do_nearest,
2576  gpu->has_bones,
2577  do_bones_get_priotity,
2578  NULL) :
2579  NULL;
2580  }
2581 
2582  /* Select pose-bones or camera-tracks. */
2583  if (((gpu->hits > 0) && gpu->has_bones) ||
2584  /* Special case, even when there are no hits, pose logic may de-select all bones. */
2585  ((gpu->hits == 0) && (object_mode & OB_MODE_POSE))) {
2586 
2587  if (basact && (gpu->has_bones && (basact->object->type == OB_CAMERA))) {
2588  MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, false);
2589  if (clip != NULL) {
2591  C, scene, basact, clip, gpu->buffer, gpu->hits, params)) {
2593  /* Don't set `handled` here as the object activation may be necessary. */
2594  changed_object = true;
2595 
2596  changed_track = true;
2597  }
2598  else {
2599  /* Fallback to regular object selection if no new bundles were selected,
2600  * allows to select object parented to reconstruction object. */
2601  basact = mouse_select_eval_buffer(
2602  &vc, gpu->buffer, gpu->hits, gpu->do_nearest, false, false, NULL);
2603  }
2604  }
2605  }
2606  else if (ED_armature_pose_select_pick_with_buffer(view_layer,
2607  v3d,
2608  basact ? basact : (Base *)oldbasact,
2609  gpu->buffer,
2610  gpu->hits,
2611  params,
2612  gpu->do_nearest)) {
2613 
2614  changed_pose = true;
2615 
2616  /* When there is no `baseact` this will have operated on `oldbasact`,
2617  * allowing #SelectPick_Params.deselect_all work in pose-mode.
2618  * In this case no object operations are needed. */
2619  if (basact == NULL) {
2620  handled = true;
2621  }
2622  else {
2623  /* By convention the armature-object is selected when in pose-mode.
2624  * While leaving it unselected will work, leaving pose-mode would leave the object
2625  * active + unselected which isn't ideal when performing other actions on the object. */
2627  changed_object = true;
2628 
2631 
2632  /* In weight-paint, we use selected bone to select vertex-group.
2633  * In this case the active object mustn't change as it would leave weight-paint mode. */
2634  if (oldbasact) {
2635  if (oldbasact->object->mode & OB_MODE_ALL_WEIGHT_PAINT) {
2636  /* Prevent activating.
2637  * Selection causes this to be considered the 'active' pose in weight-paint mode.
2638  * Eventually this limitation may be removed.
2639  * For now, de-select all other pose objects deforming this mesh. */
2640  ED_armature_pose_select_in_wpaint_mode(view_layer, basact);
2641 
2642  handled = true;
2643  }
2644  else if ((object_mode & OB_MODE_POSE) && (basact->object->mode & OB_MODE_POSE)) {
2645  /* Within pose-mode, keep the current selection when switching pose bones,
2646  * this is noticeable when in pose mode with multiple objects at once.
2647  * Where selecting the bone of a different object would de-select this one.
2648  * After that, exiting pose-mode would only have the active armature selected.
2649  * This matches multi-object edit-mode behavior. */
2650  handled = true;
2651 
2652  if (oldbasact != basact) {
2653  use_activate_selected_base = true;
2654  }
2655  }
2656  else {
2657  /* Don't set `handled` here as the object selection may be necessary
2658  * when starting out in object-mode and moving into pose-mode,
2659  * when moving from pose to object-mode using object selection also makes sense. */
2660  }
2661  }
2662  }
2663  }
2664  /* Prevent bone/track selecting to pass on to object selecting. */
2665  if (basact == oldbasact) {
2666  handled = true;
2667  }
2668  }
2669  }
2670 
2671  if (handled == false) {
2673  /* No special logic in edit-mode. */
2674  if (is_obedit == false) {
2675  if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) {
2676  if (object_mode == OB_MODE_OBJECT) {
2677  struct Main *bmain = vc.bmain;
2678  ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object);
2679  }
2680  if (!BKE_object_is_mode_compat(basact->object, object_mode)) {
2681  basact = NULL;
2682  }
2683  }
2684 
2685  /* Disallow switching modes,
2686  * special exception for edit-mode - vertex-parent operator. */
2687  if (basact && oldbasact) {
2688  if ((oldbasact->object->mode != basact->object->mode) &&
2689  (oldbasact->object->mode & basact->object->mode) == 0) {
2690  basact = NULL;
2691  }
2692  }
2693  }
2694  }
2695  }
2696 
2697  /* Ensure code above doesn't change the active base. This code is already fairly involved,
2698  * it's best if changing the active object is localized to a single place. */
2699  BLI_assert(oldbasact == (vc.obact ? BASACT(view_layer) : NULL));
2700 
2701  bool found = (basact != NULL);
2702  if ((handled == false) && (vc.obedit == NULL)) {
2703  /* Object-mode (pose mode will have been handled already). */
2704  if (params->sel_op == SEL_OP_SET) {
2705  if ((found && params->select_passthrough) && (basact->flag & BASE_SELECTED)) {
2706  found = false;
2707  }
2708  else if (found || params->deselect_all) {
2709  /* Deselect everything. */
2710  /* `basact` may be NULL. */
2711  if (object_deselect_all_except(view_layer, basact)) {
2712  changed_object = true;
2713  }
2714  }
2715  }
2716  }
2717 
2718  if ((handled == false) && found) {
2719 
2720  if (vc.obedit) {
2721  /* Only do the select (use for setting vertex parents & hooks).
2722  * In edit-mode do not activate. */
2723  object_deselect_all_except(view_layer, basact);
2725 
2726  changed_object = true;
2727  }
2728  /* Also prevent making it active on mouse selection. */
2729  else if (BASE_SELECTABLE(v3d, basact)) {
2730  use_activate_selected_base |= (oldbasact != basact) && (is_obedit == false);
2731 
2732  switch (params->sel_op) {
2733  case SEL_OP_ADD: {
2735  break;
2736  }
2737  case SEL_OP_SUB: {
2739  break;
2740  }
2741  case SEL_OP_XOR: {
2742  if (basact->flag & BASE_SELECTED) {
2743  /* Keep selected if the base is to be activated. */
2744  if (use_activate_selected_base == false) {
2746  }
2747  }
2748  else {
2750  }
2751  break;
2752  }
2753  case SEL_OP_SET: {
2754  object_deselect_all_except(view_layer, basact);
2756  break;
2757  }
2758  case SEL_OP_AND: {
2759  BLI_assert_unreachable(); /* Doesn't make sense for picking. */
2760  break;
2761  }
2762  }
2763 
2764  changed_object = true;
2765  }
2766  }
2767 
2768  /* Perform the activation even when 'handled', since this is used to ensure
2769  * the object from the pose-bone selected is also activated. */
2770  if (use_activate_selected_base && (basact != NULL)) {
2771  changed_object = true;
2772  ED_object_base_activate(C, basact); /* adds notifier */
2775  }
2776  }
2777 
2778  if (changed_object) {
2781 
2783  }
2784 
2785  if (changed_pose) {
2787  }
2788 
2789  if (gpu != NULL) {
2790  MEM_freeN(gpu);
2791  }
2792 
2793  return (changed_object || changed_pose || changed_track);
2794 }
2795 
2803  const int mval[2],
2804  const struct SelectPick_Params *params,
2805  Object *obact)
2806 {
2807  View3D *v3d = CTX_wm_view3d(C);
2808  const bool use_zbuf = !XRAY_ENABLED(v3d);
2809 
2810  Mesh *me = obact->data; /* already checked for NULL */
2811  uint index = 0;
2812  MVert *mv;
2813  bool changed = false;
2814 
2815  bool found = ED_mesh_pick_vert(C, obact, mval, ED_MESH_PICK_DEFAULT_VERT_DIST, use_zbuf, &index);
2816 
2817  if (params->sel_op == SEL_OP_SET) {
2818  if ((found && params->select_passthrough) && (me->mvert[index].flag & SELECT)) {
2819  found = false;
2820  }
2821  else if (found || params->deselect_all) {
2822  /* Deselect everything. */
2823  changed |= paintface_deselect_all_visible(C, obact, SEL_DESELECT, false);
2824  }
2825  }
2826 
2827  if (found) {
2828  mv = &me->mvert[index];
2829  switch (params->sel_op) {
2830  case SEL_OP_ADD: {
2831  mv->flag |= SELECT;
2832  break;
2833  }
2834  case SEL_OP_SUB: {
2835  mv->flag &= ~SELECT;
2836  break;
2837  }
2838  case SEL_OP_XOR: {
2839  mv->flag ^= SELECT;
2840  break;
2841  }
2842  case SEL_OP_SET: {
2844  mv->flag |= SELECT;
2845  break;
2846  }
2847  case SEL_OP_AND: {
2848  BLI_assert_unreachable(); /* Doesn't make sense for picking. */
2849  break;
2850  }
2851  }
2852 
2853  /* update mselect */
2854  if (mv->flag & SELECT) {
2856  }
2857  else {
2859  }
2860 
2861  paintvert_flush_flags(obact);
2862 
2863  changed = true;
2864  }
2865 
2866  if (changed) {
2868  }
2869 
2870  return changed || found;
2871 }
2872 
2874 {
2876  Object *obedit = CTX_data_edit_object(C);
2877  Object *obact = CTX_data_active_object(C);
2878 
2879  if (obact && obact->type == OB_GPENCIL && GPENCIL_ANY_MODE((bGPdata *)obact->data) &&
2881  /* Prevent acting on Grease Pencil (when not in object mode -- or not in weight-paint + pose
2882  * selection), it implements its own selection operator in other modes. We might still fall
2883  * trough to here (because that operator uses OPERATOR_PASS_THROUGH to make tweak work) but if
2884  * we don't stop here code below assumes we are in object mode it might falsely toggle object
2885  * selection. Alternatively, this could be put in the poll function instead. */
2887  }
2888 
2889  struct SelectPick_Params params = {0};
2891 
2892  const bool vert_without_handles = RNA_boolean_get(op->ptr, "vert_without_handles");
2893  bool center = RNA_boolean_get(op->ptr, "center");
2894  bool enumerate = RNA_boolean_get(op->ptr, "enumerate");
2895  /* Only force object select for edit-mode to support vertex parenting,
2896  * or paint-select to allow pose bone select with vert/face select. */
2897  bool object_only = (RNA_boolean_get(op->ptr, "object") &&
2898  (obedit || BKE_paint_select_elem_test(obact) ||
2899  /* so its possible to select bones in weight-paint mode (LMB select) */
2900  (obact && (obact->mode & OB_MODE_ALL_WEIGHT_PAINT) &&
2901  BKE_object_pose_armature_get(obact))));
2902 
2903  /* This could be called "changed_or_found" since this is true when there is an element
2904  * under the cursor to select, even if it happens that the selection & active state doesn't
2905  * actually change. This is important so undo pushes are predictable. */
2906  bool changed = false;
2907  int mval[2];
2908 
2909  if (object_only) {
2910  obedit = NULL;
2911  obact = NULL;
2912 
2913  /* ack, this is incorrect but to do this correctly we would need an
2914  * alternative edit-mode/object-mode keymap, this copies the functionality
2915  * from 2.4x where Ctrl+Select in edit-mode does object select only. */
2916  center = false;
2917  }
2918 
2919  if (obedit && enumerate) {
2920  /* Enumerate makes no sense in edit-mode unless also explicitly picking objects or bones.
2921  * Pass the event through so the event may be handled by loop-select for e.g. see: T100204. */
2922  if (obedit->type != OB_ARMATURE) {
2924  }
2925  }
2926 
2927  RNA_int_get_array(op->ptr, "location", mval);
2928 
2931 
2932  if (obedit && object_only == false) {
2933  if (obedit->type == OB_MESH) {
2934  changed = EDBM_select_pick(C, mval, &params);
2935  }
2936  else if (obedit->type == OB_ARMATURE) {
2937  if (enumerate) {
2939  ViewContext vc;
2941 
2943  const int hits = mixed_bones_object_selectbuffer(
2944  &vc, buffer, ARRAY_SIZE(buffer), mval, VIEW3D_SELECT_FILTER_NOP, false, true, false);
2945  changed = bone_mouse_select_menu(C, buffer, hits, true, &params);
2946  }
2947  if (!changed) {
2948  changed = ED_armature_edit_select_pick(C, mval, &params);
2949  }
2950  }
2951  else if (obedit->type == OB_LATTICE) {
2952  changed = ED_lattice_select_pick(C, mval, &params);
2953  }
2954  else if (ELEM(obedit->type, OB_CURVES_LEGACY, OB_SURF)) {
2956  C, mval, ED_view3d_select_dist_px(), vert_without_handles, &params);
2957  }
2958  else if (obedit->type == OB_MBALL) {
2959  changed = ED_mball_select_pick(C, mval, &params);
2960  }
2961  else if (obedit->type == OB_FONT) {
2962  changed = ED_curve_editfont_select_pick(C, mval, &params);
2963  }
2964  }
2965  else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
2966  changed = PE_mouse_particles(C, mval, &params);
2967  }
2968  else if (obact && BKE_paint_select_face_test(obact)) {
2969  changed = paintface_mouse_select(C, mval, &params, obact);
2970  }
2971  else if (BKE_paint_select_vert_test(obact)) {
2972  changed = ed_wpaint_vertex_select_pick(C, mval, &params, obact);
2973  }
2974  else {
2975  changed = ed_object_select_pick(C, mval, &params, center, enumerate, object_only);
2976  }
2977 
2978  /* Pass-through flag may be cleared, see #WM_operator_flag_only_pass_through_on_press. */
2979 
2980  /* Pass-through allows tweaks
2981  * FINISHED to signal one operator worked */
2982  if (changed) {
2985  }
2986  /* Nothing selected, just passthrough. */
2988 }
2989 
2990 static int view3d_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2991 {
2992  RNA_int_set_array(op->ptr, "location", event->mval);
2993 
2994  const int retval = view3d_select_exec(C, op);
2995 
2996  return WM_operator_flag_only_pass_through_on_press(retval, event);
2997 }
2998 
3000 {
3001  PropertyRNA *prop;
3002 
3003  /* identifiers */
3004  ot->name = "Select";
3005  ot->description = "Select and activate item(s)";
3006  ot->idname = "VIEW3D_OT_select";
3007 
3008  /* api callbacks */
3013 
3014  /* flags */
3015  ot->flag = OPTYPE_UNDO;
3016 
3017  /* properties */
3019 
3020  prop = RNA_def_boolean(
3021  ot->srna,
3022  "center",
3023  0,
3024  "Center",
3025  "Use the object center when selecting, in edit mode used to extend object selection");
3027  prop = RNA_def_boolean(
3028  ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only)");
3030  prop = RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (edit mode only)");
3032 
3033  /* Needed for select-through to usefully drag handles, see: T98254.
3034  * NOTE: this option may be removed and become default behavior, see design task: T98552. */
3035  prop = RNA_def_boolean(ot->srna,
3036  "vert_without_handles",
3037  0,
3038  "Control Point Without Handles",
3039  "Only select the curve control point, not it's handles");
3041 
3042  prop = RNA_def_int_vector(ot->srna,
3043  "location",
3044  2,
3045  NULL,
3046  INT_MIN,
3047  INT_MAX,
3048  "Location",
3049  "Mouse location",
3050  INT_MIN,
3051  INT_MAX);
3053 }
3054 
3057 /* -------------------------------------------------------------------- */
3061 typedef struct BoxSelectUserData {
3063  const rcti *rect;
3064  const rctf *rect_fl;
3068 
3069  /* runtime */
3070  bool is_done;
3073 
3075  ViewContext *vc,
3076  const rcti *rect,
3077  const eSelectOp sel_op)
3078 {
3079  r_data->vc = vc;
3080 
3081  r_data->rect = rect;
3082  r_data->rect_fl = &r_data->_rect_fl;
3083  BLI_rctf_rcti_copy(&r_data->_rect_fl, rect);
3084 
3085  r_data->sel_op = sel_op;
3086  /* SELECT by default, but can be changed if needed (only few cases use and respect this). */
3087  r_data->select_flag = SELECT;
3088 
3089  /* runtime */
3090  r_data->is_done = false;
3091  r_data->is_changed = false;
3092 }
3093 
3094 bool edge_inside_circle(const float cent[2],
3095  float radius,
3096  const float screen_co_a[2],
3097  const float screen_co_b[2])
3098 {
3099  const float radius_squared = radius * radius;
3100  return (dist_squared_to_line_segment_v2(cent, screen_co_a, screen_co_b) < radius_squared);
3101 }
3102 
3103 static void do_paintvert_box_select__doSelectVert(void *userData,
3104  MVert *mv,
3105  const float screen_co[2],
3106  int UNUSED(index))
3107 {
3108  BoxSelectUserData *data = userData;
3109  const bool is_select = mv->flag & SELECT;
3110  const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
3111  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
3112  if (sel_op_result != -1) {
3113  SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT);
3114  data->is_changed = true;
3115  }
3116 }
3118  wmGenericUserData *wm_userdata,
3119  const rcti *rect,
3120  const eSelectOp sel_op)
3121 {
3122  const bool use_zbuf = !XRAY_ENABLED(vc->v3d);
3123 
3124  Mesh *me;
3125 
3126  me = vc->obact->data;
3127  if ((me == NULL) || (me->totvert == 0)) {
3128  return OPERATOR_CANCELLED;
3129  }
3130 
3131  bool changed = false;
3132  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3133  changed |= paintvert_deselect_all_visible(vc->obact, SEL_DESELECT, false);
3134  }
3135 
3136  if (BLI_rcti_is_empty(rect)) {
3137  /* pass */
3138  }
3139  else if (use_zbuf) {
3140  struct EditSelectBuf_Cache *esel = wm_userdata->data;
3141  if (wm_userdata->data == NULL) {
3143  esel = wm_userdata->data;
3145  vc->depsgraph, vc->region, vc->v3d, rect, NULL);
3146  }
3147  if (esel->select_bitmap != NULL) {
3148  changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op);
3149  }
3150  }
3151  else {
3153 
3154  view3d_userdata_boxselect_init(&data, vc, rect, sel_op);
3155 
3157 
3160  changed |= data.is_changed;
3161  }
3162 
3163  if (changed) {
3164  if (SEL_OP_CAN_DESELECT(sel_op)) {
3166  }
3169  }
3170  return changed;
3171 }
3172 
3174  wmGenericUserData *wm_userdata,
3175  const rcti *rect,
3176  int sel_op)
3177 {
3178  Object *ob = vc->obact;
3179  Mesh *me;
3180 
3181  me = BKE_mesh_from_object(ob);
3182  if ((me == NULL) || (me->totpoly == 0)) {
3183  return false;
3184  }
3185 
3186  bool changed = false;
3187  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3188  changed |= paintface_deselect_all_visible(vc->C, vc->obact, SEL_DESELECT, false);
3189  }
3190 
3191  if (BLI_rcti_is_empty(rect)) {
3192  /* pass */
3193  }
3194  else {
3195  struct EditSelectBuf_Cache *esel = wm_userdata->data;
3196  if (wm_userdata->data == NULL) {
3198  esel = wm_userdata->data;
3200  vc->depsgraph, vc->region, vc->v3d, rect, NULL);
3201  }
3202  if (esel->select_bitmap != NULL) {
3203  changed |= edbm_backbuf_check_and_select_faces_obmode(me, esel, sel_op);
3204  }
3205  }
3206 
3207  if (changed) {
3208  paintface_flush_flags(vc->C, vc->obact, SELECT);
3209  }
3210  return changed;
3211 }
3212 
3213 static void do_nurbs_box_select__doSelect(void *userData,
3214  Nurb *UNUSED(nu),
3215  BPoint *bp,
3216  BezTriple *bezt,
3217  int beztindex,
3218  bool handles_visible,
3219  const float screen_co[2])
3220 {
3221  BoxSelectUserData *data = userData;
3222 
3223  const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
3224  if (bp) {
3225  const bool is_select = bp->f1 & SELECT;
3226  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
3227  if (sel_op_result != -1) {
3228  SET_FLAG_FROM_TEST(bp->f1, sel_op_result, data->select_flag);
3229  data->is_changed = true;
3230  }
3231  }
3232  else {
3233  if (!handles_visible) {
3234  /* can only be (beztindex == 1) here since handles are hidden */
3235  const bool is_select = bezt->f2 & SELECT;
3236  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
3237  if (sel_op_result != -1) {
3238  SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, data->select_flag);
3239  data->is_changed = true;
3240  }
3241  bezt->f1 = bezt->f3 = bezt->f2;
3242  }
3243  else {
3244  uint8_t *flag_p = (&bezt->f1) + beztindex;
3245  const bool is_select = *flag_p & SELECT;
3246  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
3247  if (sel_op_result != -1) {
3248  SET_FLAG_FROM_TEST(*flag_p, sel_op_result, data->select_flag);
3249  data->is_changed = true;
3250  }
3251  }
3252  }
3253 }
3254 static bool do_nurbs_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op)
3255 {
3256  const bool deselect_all = (sel_op == SEL_OP_SET);
3258 
3259  view3d_userdata_boxselect_init(&data, vc, rect, sel_op);
3260 
3261  Curve *curve = (Curve *)vc->obedit->data;
3263 
3264  /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */
3265  if (deselect_all) {
3267  data.select_flag = BEZT_FLAG_TEMP_TAG;
3268  }
3269 
3270  ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
3272 
3273  /* Deselect items that were not added to selection (indicated by temp flag). */
3274  if (deselect_all) {
3276  }
3277 
3279 
3280  return data.is_changed;
3281 }
3282 
3283 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, const float screen_co[2])
3284 {
3285  BoxSelectUserData *data = userData;
3286  const bool is_select = bp->f1 & SELECT;
3287  const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
3288  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
3289  if (sel_op_result != -1) {
3290  SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT);
3291  data->is_changed = true;
3292  }
3293 }
3294 static bool do_lattice_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op)
3295 {
3297 
3298  view3d_userdata_boxselect_init(&data, vc, rect, sel_op);
3299 
3300  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3301  data.is_changed |= ED_lattice_flags_set(vc->obedit, 0);
3302  }
3303 
3304  ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
3307 
3308  return data.is_changed;
3309 }
3310 
3311 static void do_mesh_box_select__doSelectVert(void *userData,
3312  BMVert *eve,
3313  const float screen_co[2],
3314  int UNUSED(index))
3315 {
3316  BoxSelectUserData *data = userData;
3317  const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
3318  const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
3319  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
3320  if (sel_op_result != -1) {
3321  BM_vert_select_set(data->vc->em->bm, eve, sel_op_result);
3322  data->is_changed = true;
3323  }
3324 }
3329 };
3334  void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
3335 {
3336  struct BoxSelectUserData_ForMeshEdge *data_for_edge = userData;
3337  BoxSelectUserData *data = data_for_edge->data;
3338  bool is_visible = true;
3339  if (data_for_edge->backbuf_offset) {
3340  uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1;
3341  is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx);
3342  }
3343 
3344  const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
3345  const bool is_inside = (is_visible &&
3346  edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b));
3347  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
3348  if (sel_op_result != -1) {
3349  BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
3350  data->is_done = true;
3351  data->is_changed = true;
3352  }
3353 }
3358  void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
3359 {
3360  struct BoxSelectUserData_ForMeshEdge *data_for_edge = userData;
3361  BoxSelectUserData *data = data_for_edge->data;
3362  bool is_visible = true;
3363  if (data_for_edge->backbuf_offset) {
3364  uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1;
3365  is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx);
3366  }
3367 
3368  const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
3369  const bool is_inside = (is_visible && edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b));
3370  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
3371  if (sel_op_result != -1) {
3372  BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
3373  data->is_changed = true;
3374  }
3375 }
3376 static void do_mesh_box_select__doSelectFace(void *userData,
3377  BMFace *efa,
3378  const float screen_co[2],
3379  int UNUSED(index))
3380 {
3381  BoxSelectUserData *data = userData;
3382  const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
3383  const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
3384  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
3385  if (sel_op_result != -1) {
3386  BM_face_select_set(data->vc->em->bm, efa, sel_op_result);
3387  data->is_changed = true;
3388  }
3389 }
3391  wmGenericUserData *wm_userdata,
3392  const rcti *rect,
3393  const eSelectOp sel_op)
3394 {
3396  ToolSettings *ts = vc->scene->toolsettings;
3397 
3398  view3d_userdata_boxselect_init(&data, vc, rect, sel_op);
3399 
3400  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3401  if (vc->em->bm->totvertsel) {
3403  data.is_changed = true;
3404  }
3405  }
3406 
3407  /* for non zbuf projections, don't change the GL state */
3409 
3410  GPU_matrix_set(vc->rv3d->viewmat);
3411 
3412  const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d);
3413 
3414  struct EditSelectBuf_Cache *esel = wm_userdata->data;
3415  if (use_zbuf) {
3416  if (wm_userdata->data == NULL) {
3418  esel = wm_userdata->data;
3420  vc->depsgraph, vc->region, vc->v3d, rect, NULL);
3421  }
3422  }
3423 
3424  if (ts->selectmode & SCE_SELECT_VERTEX) {
3425  if (use_zbuf) {
3427  esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
3428  }
3429  else {
3432  }
3433  }
3434  if (ts->selectmode & SCE_SELECT_EDGE) {
3435  /* Does both use_zbuf and non-use_zbuf versions (need screen cos for both) */
3436  struct BoxSelectUserData_ForMeshEdge cb_data = {
3437  .data = &data,
3438  .esel = use_zbuf ? esel : NULL,
3439  .backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem(
3440  vc->depsgraph, vc->obedit, SCE_SELECT_EDGE) :
3441  0,
3442  };
3443 
3444  const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR |
3445  (use_zbuf ? 0 : V3D_PROJ_TEST_CLIP_BB);
3446  /* Fully inside. */
3448  vc, do_mesh_box_select__doSelectEdge_pass0, &cb_data, clip_flag);
3449  if (data.is_done == false) {
3450  /* Fall back to partially inside.
3451  * Clip content to account for edges partially behind the view. */
3454  &cb_data,
3456  }
3457  }
3458 
3459  if (ts->selectmode & SCE_SELECT_FACE) {
3460  if (use_zbuf) {
3462  esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
3463  }
3464  else {
3467  }
3468  }
3469 
3470  if (data.is_changed) {
3472  }
3473  return data.is_changed;
3474 }
3475 
3476 static bool do_meta_box_select(ViewContext *vc, const rcti *rect, const eSelectOp sel_op)
3477 {
3478  Object *ob = vc->obedit;
3479  MetaBall *mb = (MetaBall *)ob->data;
3480  MetaElem *ml;
3481  int a;
3482  bool changed = false;
3483 
3485  int hits;
3486 
3487  hits = view3d_opengl_select(
3489 
3490  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3491  changed |= BKE_mball_deselect_all(mb);
3492  }
3493 
3494  int metaelem_id = 0;
3495  for (ml = mb->editelems->first; ml; ml = ml->next, metaelem_id += 0x10000) {
3496  bool is_inside_radius = false;
3497  bool is_inside_stiff = false;
3498 
3499  for (a = 0; a < hits; a++) {
3500  const int hitresult = buffer[a].id;
3501 
3502  if (hitresult == -1) {
3503  continue;
3504  }
3505 
3506  const uint hit_object = hitresult & 0xFFFF;
3507  if (vc->obedit->runtime.select_id != hit_object) {
3508  continue;
3509  }
3510 
3511  if (metaelem_id != (hitresult & 0xFFFF0000 & ~MBALLSEL_ANY)) {
3512  continue;
3513  }
3514 
3515  if (hitresult & MBALLSEL_RADIUS) {
3516  is_inside_radius = true;
3517  break;
3518  }
3519 
3520  if (hitresult & MBALLSEL_STIFF) {
3521  is_inside_stiff = true;
3522  break;
3523  }
3524  }
3525  const int flag_prev = ml->flag;
3526  if (is_inside_radius) {
3527  ml->flag |= MB_SCALE_RAD;
3528  }
3529  if (is_inside_stiff) {
3530  ml->flag &= ~MB_SCALE_RAD;
3531  }
3532 
3533  const bool is_select = (ml->flag & SELECT);
3534  const bool is_inside = is_inside_radius || is_inside_stiff;
3535 
3536  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
3537  if (sel_op_result != -1) {
3538  SET_FLAG_FROM_TEST(ml->flag, sel_op_result, SELECT);
3539  }
3540  changed |= (flag_prev != ml->flag);
3541  }
3542 
3543  return changed;
3544 }
3545 
3546 static bool do_armature_box_select(ViewContext *vc, const rcti *rect, const eSelectOp sel_op)
3547 {
3548  bool changed = false;
3549  int a;
3550 
3552  int hits;
3553 
3554  hits = view3d_opengl_select(
3556 
3557  uint bases_len = 0;
3559  vc->view_layer, vc->v3d, &bases_len);
3560 
3561  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3562  changed |= ED_armature_edit_deselect_all_visible_multi_ex(bases, bases_len);
3563  }
3564 
3565  for (uint base_index = 0; base_index < bases_len; base_index++) {
3566  Object *obedit = bases[base_index]->object;
3567  obedit->id.tag &= ~LIB_TAG_DOIT;
3568 
3569  bArmature *arm = obedit->data;
3571  }
3572 
3573  /* first we only check points inside the border */
3574  for (a = 0; a < hits; a++) {
3575  const int select_id = buffer[a].id;
3576  if (select_id != -1) {
3577  if ((select_id & 0xFFFF0000) == 0) {
3578  continue;
3579  }
3580 
3581  EditBone *ebone;
3583  bases, bases_len, select_id, &ebone);
3584  ebone->temp.i |= select_id & BONESEL_ANY;
3585  base_edit->object->id.tag |= LIB_TAG_DOIT;
3586  }
3587  }
3588 
3589  for (uint base_index = 0; base_index < bases_len; base_index++) {
3590  Object *obedit = bases[base_index]->object;
3591  if (obedit->id.tag & LIB_TAG_DOIT) {
3592  obedit->id.tag &= ~LIB_TAG_DOIT;
3593  changed |= ED_armature_edit_select_op_from_tagged(obedit->data, sel_op);
3594  }
3595  }
3596 
3597  MEM_freeN(bases);
3598 
3599  return changed;
3600 }
3601 
3606 static int opengl_bone_select_buffer_cmp(const void *sel_a_p, const void *sel_b_p)
3607 {
3608  uint sel_a = ((GPUSelectResult *)sel_a_p)->id;
3609  uint sel_b = ((GPUSelectResult *)sel_b_p)->id;
3610 
3611 #ifdef __BIG_ENDIAN__
3612  BLI_endian_switch_uint32(&sel_a);
3613  BLI_endian_switch_uint32(&sel_b);
3614 #endif
3615 
3616  if (sel_a < sel_b) {
3617  return -1;
3618  }
3619  if (sel_a > sel_b) {
3620  return 1;
3621  }
3622  return 0;
3623 }
3624 
3625 static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const eSelectOp sel_op)
3626 {
3627  View3D *v3d = vc->v3d;
3628  int totobj = MAXPICKELEMS; /* XXX solve later */
3629 
3630  /* Selection buffer has bones potentially too, so we add #MAXPICKELEMS. */
3632  "selection buffer");
3634  vc->obact);
3635  const int hits = view3d_opengl_select(
3636  vc, buffer, (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter);
3637 
3638  LISTBASE_FOREACH (Base *, base, &vc->view_layer->object_bases) {
3639  base->object->id.tag &= ~LIB_TAG_DOIT;
3640  }
3641 
3642  Base **bases = NULL;
3643  BLI_array_declare(bases);
3644 
3645  bool changed = false;
3646  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3647  changed |= object_deselect_all_visible(vc->view_layer, vc->v3d);
3648  }
3649 
3650  if ((hits == -1) && !SEL_OP_USE_OUTSIDE(sel_op)) {
3651  goto finally;
3652  }
3653 
3654  LISTBASE_FOREACH (Base *, base, &vc->view_layer->object_bases) {
3655  if (BASE_SELECTABLE(v3d, base)) {
3656  if ((base->object->runtime.select_id & 0x0000FFFF) != 0) {
3657  BLI_array_append(bases, base);
3658  }
3659  }
3660  }
3661 
3662  /* The draw order doesn't always match the order we populate the engine, see: T51695. */
3663  qsort(buffer, hits, sizeof(GPUSelectResult), opengl_bone_select_buffer_cmp);
3664 
3665  for (const GPUSelectResult *buf_iter = buffer, *buf_end = buf_iter + hits; buf_iter < buf_end;
3666  buf_iter++) {
3667  bPoseChannel *pchan_dummy;
3669  bases, BLI_array_len(bases), buf_iter->id, &pchan_dummy);
3670  if (base != NULL) {
3671  base->object->id.tag |= LIB_TAG_DOIT;
3672  }
3673  }
3674 
3675  for (Base *base = vc->view_layer->object_bases.first; base && hits; base = base->next) {
3676  if (BASE_SELECTABLE(v3d, base)) {
3677  const bool is_select = base->flag & BASE_SELECTED;
3678  const bool is_inside = base->object->id.tag & LIB_TAG_DOIT;
3679  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
3680  if (sel_op_result != -1) {
3681  ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT);
3682  changed = true;
3683  }
3684  }
3685  }
3686 
3687 finally:
3688  if (bases != NULL) {
3689  MEM_freeN(bases);
3690  }
3691 
3692  MEM_freeN(buffer);
3693 
3694  if (changed) {
3697  }
3698  return changed;
3699 }
3700 
3701 static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const eSelectOp sel_op)
3702 {
3703  uint bases_len;
3704  Base **bases = do_pose_tag_select_op_prepare(vc, &bases_len);
3705 
3706  int totobj = MAXPICKELEMS; /* XXX solve later */
3707 
3708  /* Selection buffer has bones potentially too, so add #MAXPICKELEMS. */
3710  "selection buffer");
3712  vc->obact);
3713  const int hits = view3d_opengl_select(
3714  vc, buffer, (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter);
3715  /*
3716  * LOGIC NOTES (theeth):
3717  * The buffer and ListBase have the same relative order, which makes the selection
3718  * very simple. Loop through both data sets at the same time, if the color
3719  * is the same as the object, we have a hit and can move to the next color
3720  * and object pair, if not, just move to the next object,
3721  * keeping the same color until we have a hit.
3722  */
3723 
3724  if (hits > 0) {
3725  /* no need to loop if there's no hit */
3726 
3727  /* The draw order doesn't always match the order we populate the engine, see: T51695. */
3728  qsort(buffer, hits, sizeof(GPUSelectResult), opengl_bone_select_buffer_cmp);
3729 
3730  for (const GPUSelectResult *buf_iter = buffer, *buf_end = buf_iter + hits; buf_iter < buf_end;
3731  buf_iter++) {
3732  Bone *bone;
3734  bases, bases_len, buf_iter->id, &bone);
3735 
3736  if (base == NULL) {
3737  continue;
3738  }
3739 
3740  /* Loop over contiguous bone hits for 'base'. */
3741  for (; buf_iter != buf_end; buf_iter++) {
3742  /* should never fail */
3743  if (bone != NULL) {
3744  base->object->id.tag |= LIB_TAG_DOIT;
3745  bone->flag |= BONE_DONE;
3746  }
3747 
3748  /* Select the next bone if we're not switching bases. */
3749  if (buf_iter + 1 != buf_end) {
3750  const GPUSelectResult *col_next = buf_iter + 1;
3751  if ((base->object->runtime.select_id & 0x0000FFFF) != (col_next->id & 0x0000FFFF)) {
3752  break;
3753  }
3754  if (base->object->pose != NULL) {
3755  const uint hit_bone = (col_next->id & ~BONESEL_ANY) >> 16;
3756  bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone);
3757  bone = pchan ? pchan->bone : NULL;
3758  }
3759  else {
3760  bone = NULL;
3761  }
3762  }
3763  }
3764  }
3765  }
3766 
3767  const bool changed_multi = do_pose_tag_select_op_exec(bases, bases_len, sel_op);
3768  if (changed_multi) {
3771  }
3772 
3773  if (bases != NULL) {
3774  MEM_freeN(bases);
3775  }
3776  MEM_freeN(buffer);
3777 
3778  return changed_multi;
3779 }
3780 
3782 {
3784  ViewContext vc;
3785  rcti rect;
3786  bool changed_multi = false;
3787 
3788  wmGenericUserData wm_userdata_buf = {0};
3789  wmGenericUserData *wm_userdata = &wm_userdata_buf;
3790 
3793 
3794  /* setup view context for argument to callbacks */
3796 
3797  eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
3799 
3800  if (vc.obedit) {
3802  vc.view_layer, vc.v3d, vc.obedit->type, vc.obedit->mode, ob_iter) {
3803  ED_view3d_viewcontext_init_object(&vc, ob_iter);
3804  bool changed = false;
3805 
3806  switch (vc.obedit->type) {
3807  case OB_MESH:
3809  changed = do_mesh_box_select(&vc, wm_userdata, &rect, sel_op);
3810  if (changed) {
3813  }
3814  break;
3815  case OB_CURVES_LEGACY:
3816  case OB_SURF:
3817  changed = do_nurbs_box_select(&vc, &rect, sel_op);
3818  if (changed) {
3821  }
3822  break;
3823  case OB_MBALL:
3824  changed = do_meta_box_select(&vc, &rect, sel_op);
3825  if (changed) {
3828  }
3829  break;
3830  case OB_ARMATURE:
3831  changed = do_armature_box_select(&vc, &rect, sel_op);
3832  if (changed) {
3836  }
3837  break;
3838  case OB_LATTICE:
3839  changed = do_lattice_box_select(&vc, &rect, sel_op);
3840  if (changed) {
3843  }
3844  break;
3845  default:
3846  BLI_assert_msg(0, "box select on incorrect object type");
3847  break;
3848  }
3849  changed_multi |= changed;
3850  }
3852  }
3853  else { /* No edit-mode, unified for bones and objects. */
3854  if (vc.obact && BKE_paint_select_face_test(vc.obact)) {
3855  changed_multi = do_paintface_box_select(&vc, wm_userdata, &rect, sel_op);
3856  }
3857  else if (vc.obact && BKE_paint_select_vert_test(vc.obact)) {
3858  changed_multi = do_paintvert_box_select(&vc, wm_userdata, &rect, sel_op);
3859  }
3860  else if (vc.obact && vc.obact->mode & OB_MODE_PARTICLE_EDIT) {
3861  changed_multi = PE_box_select(C, &rect, sel_op);
3862  }
3863  else if (vc.obact && vc.obact->mode & OB_MODE_POSE) {
3864  changed_multi = do_pose_box_select(C, &vc, &rect, sel_op);
3865  if (changed_multi) {
3867  }
3868  }
3869  else { /* object mode with none active */
3870  changed_multi = do_object_box_select(C, &vc, &rect, sel_op);
3871  if (changed_multi) {
3873  }
3874  }
3875  }
3876 
3877  WM_generic_user_data_free(wm_userdata);
3878 
3879  if (changed_multi) {
3880  return OPERATOR_FINISHED;
3881  }
3882  return OPERATOR_CANCELLED;
3883 }
3884 
3886 {
3887  /* identifiers */
3888  ot->name = "Box Select";
3889  ot->description = "Select items using box selection";
3890  ot->idname = "VIEW3D_OT_select_box";
3891 
3892  /* api callbacks */
3898 
3899  /* flags */
3900  ot->flag = OPTYPE_UNDO;
3901 
3902  /* rna */
3905 }
3906 
3909 /* -------------------------------------------------------------------- */
3913 typedef struct CircleSelectUserData {
3915  bool select;
3916  int mval[2];
3917  float mval_fl[2];
3918  float radius;
3921 
3922  /* runtime */
3925 
3927  ViewContext *vc,
3928  const bool select,
3929  const int mval[2],
3930  const float rad)
3931 {
3932  r_data->vc = vc;
3933  r_data->select = select;
3934  copy_v2_v2_int(r_data->mval, mval);
3935  r_data->mval_fl[0] = mval[0];
3936  r_data->mval_fl[1] = mval[1];
3937 
3938  r_data->radius = rad;
3939  r_data->radius_squared = rad * rad;
3940 
3941  /* SELECT by default, but can be changed if needed (only few cases use and respect this). */
3942  r_data->select_flag = SELECT;
3943 
3944  /* runtime */
3945  r_data->is_changed = false;
3946 }
3947 
3948 static void mesh_circle_doSelectVert(void *userData,
3949  BMVert *eve,
3950  const float screen_co[2],
3951  int UNUSED(index))
3952 {
3953  CircleSelectUserData *data = userData;
3954 
3955  if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
3956  BM_vert_select_set(data->vc->em->bm, eve, data->select);
3957  data->is_changed = true;
3958  }
3959 }
3960 static void mesh_circle_doSelectEdge(void *userData,
3961  BMEdge *eed,
3962  const float screen_co_a[2],
3963  const float screen_co_b[2],
3964  int UNUSED(index))
3965 {
3966  CircleSelectUserData *data = userData;
3967 
3968  if (edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) {
3969  BM_edge_select_set(data->vc->em->bm, eed, data->select);
3970  data->is_changed = true;
3971  }
3972 }
3973 static void mesh_circle_doSelectFace(void *userData,
3974  BMFace *efa,
3975  const float screen_co[2],
3976  int UNUSED(index))
3977 {
3978  CircleSelectUserData *data = userData;
3979 
3980  if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
3981  BM_face_select_set(data->vc->em->bm, efa, data->select);
3982  data->is_changed = true;
3983  }
3984 }
3985 
3987  wmGenericUserData *wm_userdata,
3988  eSelectOp sel_op,
3989  const int mval[2],
3990  float rad)
3991 {
3992  ToolSettings *ts = vc->scene->toolsettings;
3994  vc->em = BKE_editmesh_from_object(vc->obedit);
3995 
3996  bool changed = false;
3997  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
3998  if (vc->em->bm->totvertsel) {
4000  vc->em->bm->totvertsel = 0;
4001  vc->em->bm->totedgesel = 0;
4002  vc->em->bm->totfacesel = 0;
4003  changed = true;
4004  }
4005  }
4006  const bool select = (sel_op != SEL_OP_SUB);
4007 
4008  ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
4009 
4010  view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
4011 
4012  const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d);
4013 
4014  if (use_zbuf) {
4015  if (wm_userdata->data == NULL) {
4017  }
4018  }
4019  struct EditSelectBuf_Cache *esel = wm_userdata->data;
4020 
4021  if (use_zbuf) {
4022  if (esel->select_bitmap == NULL) {
4024  vc->depsgraph, vc->region, vc->v3d, mval, (int)(rad + 1.0f), NULL);
4025  }
4026  }
4027 
4028  if (ts->selectmode & SCE_SELECT_VERTEX) {
4029  if (use_zbuf) {
4030  if (esel->select_bitmap != NULL) {
4032  esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
4033  }
4034  }
4035  else {
4037  }
4038  }
4039 
4040  if (ts->selectmode & SCE_SELECT_EDGE) {
4041  if (use_zbuf) {
4042  if (esel->select_bitmap != NULL) {
4044  esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
4045  }
4046  }
4047  else {
4049  vc,
4051  &data,
4053  }
4054  }
4055 
4056  if (ts->selectmode & SCE_SELECT_FACE) {
4057  if (use_zbuf) {
4058  if (esel->select_bitmap != NULL) {
4060  esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
4061  }
4062  }
4063  else {
4065  }
4066  }
4067 
4068  changed |= data.is_changed;
4069 
4070  if (changed) {
4073  }
4074  return changed;
4075 }
4076 
4078  wmGenericUserData *wm_userdata,
4079  const eSelectOp sel_op,
4080  const int mval[2],
4081  float rad)
4082 {
4084  Object *ob = vc->obact;
4085  Mesh *me = ob->data;
4086 
4087  bool changed = false;
4088  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
4089  /* flush selection at the end */
4090  changed |= paintface_deselect_all_visible(vc->C, ob, SEL_DESELECT, false);
4091  }
4092 
4093  if (wm_userdata->data == NULL) {
4095  }
4096 
4097  {
4098  struct EditSelectBuf_Cache *esel = wm_userdata->data;
4100  vc->depsgraph, vc->region, vc->v3d, mval, (int)(rad + 1.0f), NULL);
4101  if (esel->select_bitmap != NULL) {
4102  changed |= edbm_backbuf_check_and_select_faces_obmode(me, esel, sel_op);
4103  MEM_freeN(esel->select_bitmap);
4104  esel->select_bitmap = NULL;
4105  }
4106  }
4107 
4108  if (changed) {
4109  paintface_flush_flags(vc->C, ob, SELECT);
4110  }
4111  return changed;
4112 }
4113 
4114 static void paint_vertsel_circle_select_doSelectVert(void *userData,
4115  MVert *mv,
4116  const float screen_co[2],
4117  int UNUSED(index))
4118 {
4119  CircleSelectUserData *data = userData;
4120 
4121  if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
4122  SET_FLAG_FROM_TEST(mv->flag, data->select, SELECT);
4123  data->is_changed = true;
4124  }
4125 }
4127  wmGenericUserData *wm_userdata,
4128  const eSelectOp sel_op,
4129  const int mval[2],
4130  float rad)
4131 {
4133  const bool use_zbuf = !XRAY_ENABLED(vc->v3d);
4134  Object *ob = vc->obact;
4135  Mesh *me = ob->data;
4136  /* CircleSelectUserData data = {NULL}; */ /* UNUSED */
4137 
4138  bool changed = false;
4139  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
4140  /* Flush selection at the end. */
4141  changed |= paintvert_deselect_all_visible(ob, SEL_DESELECT, false);
4142  }
4143 
4144  const bool select = (sel_op != SEL_OP_SUB);
4145 
4146  if (use_zbuf) {
4147  if (wm_userdata->data == NULL) {
4149  }
4150  }
4151 
4152  if (use_zbuf) {
4153  struct EditSelectBuf_Cache *esel = wm_userdata->data;
4155  vc->depsgraph, vc->region, vc->v3d, mval, (int)(rad + 1.0f), NULL);
4156  if (esel->select_bitmap != NULL) {
4157  changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op);
4158  MEM_freeN(esel->select_bitmap);
4159  esel->select_bitmap = NULL;
4160  }
4161  }
4162  else {
4164 
4165  ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */
4166 
4167  view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
4170  changed |= data.is_changed;
4171  }
4172 
4173  if (changed) {
4174  if (sel_op == SEL_OP_SUB) {
4176  }
4178  paintvert_tag_select_update(vc->C, ob);
4179  }
4180  return changed;
4181 }
4182 
4183 static void nurbscurve_circle_doSelect(void *userData,
4184  Nurb *UNUSED(nu),
4185  BPoint *bp,
4186  BezTriple *bezt,
4187  int beztindex,
4188  bool UNUSED(handles_visible),
4189  const float screen_co[2])
4190 {
4191  CircleSelectUserData *data = userData;
4192 
4193  if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
4194  if (bp) {
4195  SET_FLAG_FROM_TEST(bp->f1, data->select, data->select_flag);
4196  }
4197  else {
4198  if (beztindex == 0) {
4199  SET_FLAG_FROM_TEST(bezt->f1, data->select, data->select_flag);
4200  }
4201  else if (beztindex == 1) {
4202  SET_FLAG_FROM_TEST(bezt->f2, data->select, data->select_flag);
4203  }
4204  else {
4205  SET_FLAG_FROM_TEST(bezt->f3, data->select, data->select_flag);
4206  }
4207  }
4208  data->is_changed = true;
4209  }
4210 }
4212  const eSelectOp sel_op,
4213  const int mval[2],
4214  float rad)
4215 {
4216  const bool select = (sel_op != SEL_OP_SUB);
4217  const bool deselect_all = (sel_op == SEL_OP_SET);
4219 
4220  view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
4221 
4222  Curve *curve = (Curve *)vc->obedit->data;
4224 
4225  /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */
4226  if (deselect_all) {
4228  data.select_flag = BEZT_FLAG_TEMP_TAG;
4229  }
4230 
4231  ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
4233 
4234  /* Deselect items that were not added to selection (indicated by temp flag). */
4235  if (deselect_all) {
4237  }
4238 
4240 
4241  return data.is_changed;
4242 }
4243 
4244 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, const float screen_co[2])
4245 {
4246  CircleSelectUserData *data = userData;
4247 
4248  if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
4249  bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
4250  data->is_changed = true;
4251  }
4252 }
4254  const eSelectOp sel_op,
4255  const int mval[2],
4256  float rad)
4257 {
4259  const bool select = (sel_op != SEL_OP_SUB);
4260 
4261  view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
4262 
4263  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
4264  data.is_changed |= ED_lattice_flags_set(vc->obedit, 0);
4265  }
4266  ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
4267 
4269 
4270  return data.is_changed;
4271 }
4272 
4276 static bool pchan_circle_doSelectJoint(void *userData,
4277  bPoseChannel *pchan,
4278  const float screen_co[2])
4279 {
4280  CircleSelectUserData *data = userData;
4281 
4282  if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
4283  if (data->select) {
4284  pchan->bone->flag |= BONE_SELECTED;
4285  }
4286  else {
4287  pchan->bone->flag &= ~BONE_SELECTED;
4288  }
4289  return 1;
4290  }
4291  return 0;
4292 }
4293 static void do_circle_select_pose__doSelectBone(void *userData,
4294  struct bPoseChannel *pchan,
4295  const float screen_co_a[2],
4296  const float screen_co_b[2])
4297 {
4298  CircleSelectUserData *data = userData;
4299  bArmature *arm = data->vc->obact->data;
4300  if (!PBONE_SELECTABLE(arm, pchan->bone)) {
4301  return;
4302  }
4303 
4304  bool is_point_done = false;
4305  int points_proj_tot = 0;
4306 
4307  /* project head location to screenspace */
4308  if (screen_co_a[0] != IS_CLIPPED) {
4309  points_proj_tot++;
4310  if (pchan_circle_doSelectJoint(data, pchan, screen_co_a)) {
4311  is_point_done = true;
4312  }
4313  }
4314 
4315  /* project tail location to screenspace */
4316  if (screen_co_b[0] != IS_CLIPPED) {
4317  points_proj_tot++;
4318  if (pchan_circle_doSelectJoint(data, pchan, screen_co_b)) {
4319  is_point_done = true;
4320  }
4321  }
4322 
4323  /* check if the head and/or tail is in the circle
4324  * - the call to check also does the selection already
4325  */
4326 
4327  /* only if the endpoints didn't get selected, deal with the middle of the bone too
4328  * It works nicer to only do this if the head or tail are not in the circle,
4329  * otherwise there is no way to circle select joints alone */
4330  if ((is_point_done == false) && (points_proj_tot == 2) &&
4331  edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) {
4332  if (data->select) {
4333  pchan->bone->flag |= BONE_SELECTED;
4334  }
4335  else {
4336  pchan->bone->flag &= ~BONE_SELECTED;
4337  }
4338  data->is_changed = true;
4339  }
4340 
4341  data->is_changed |= is_point_done;
4342 }
4344  const eSelectOp sel_op,
4345  const int mval[2],
4346  float rad)
4347 {
4350  const bool select = (sel_op != SEL_OP_SUB);
4351 
4352  view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
4353 
4354  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
4355  data.is_changed |= ED_pose_deselect_all(vc->obact, SEL_DESELECT, false);
4356  }
4357 
4358  ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */
4359 
4360  /* Treat bones as clipped segments (no joints). */
4363  &data,
4365 
4366  if (data.is_changed) {
4368  }
4369  return data.is_changed;
4370 }
4371 
4375 static bool armature_circle_doSelectJoint(void *userData,
4376  EditBone *ebone,
4377  const float screen_co[2],
4378  bool head)
4379 {
4380  CircleSelectUserData *data = userData;
4381 
4382  if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
4383  if (head) {
4384  if (data->select) {
4385  ebone->flag |= BONE_ROOTSEL;
4386  }
4387  else {
4388  ebone->flag &= ~BONE_ROOTSEL;
4389  }
4390  }
4391  else {
4392  if (data->select) {
4393  ebone->flag |= BONE_TIPSEL;
4394  }
4395  else {
4396  ebone->flag &= ~BONE_TIPSEL;
4397  }
4398  }
4399  return 1;
4400  }
4401  return 0;
4402 }
4403 static void do_circle_select_armature__doSelectBone(void *userData,
4404  struct EditBone *ebone,
4405  const float screen_co_a[2],
4406  const float screen_co_b[2])
4407 {
4408  CircleSelectUserData *data = userData;
4409  const bArmature *arm = data->vc->obedit->data;
4410  if (!(data->select ? EBONE_SELECTABLE(arm, ebone) : EBONE_VISIBLE(arm, ebone))) {
4411  return;
4412  }
4413 
4414  /* When true, ignore in the next pass. */
4415  ebone->temp.i = false;
4416 
4417  bool is_point_done = false;
4418  bool is_edge_done = false;
4419  int points_proj_tot = 0;
4420 
4421  /* project head location to screenspace */
4422  if (screen_co_a[0] != IS_CLIPPED) {
4423  points_proj_tot++;
4424  if (armature_circle_doSelectJoint(data, ebone, screen_co_a, true)) {
4425  is_point_done = true;
4426  }
4427  }
4428 
4429  /* project tail location to screenspace */
4430  if (screen_co_b[0] != IS_CLIPPED) {
4431  points_proj_tot++;
4432  if (armature_circle_doSelectJoint(data, ebone, screen_co_b, false)) {
4433  is_point_done = true;
4434  }
4435  }
4436 
4437  /* check if the head and/or tail is in the circle
4438  * - the call to check also does the selection already
4439  */
4440 
4441  /* only if the endpoints didn't get selected, deal with the middle of the bone too
4442  * It works nicer to only do this if the head or tail are not in the circle,
4443  * otherwise there is no way to circle select joints alone */
4444  if ((is_point_done == false) && (points_proj_tot == 2) &&
4445  edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) {
4447  is_edge_done = true;
4448  data->is_changed = true;
4449  }
4450 
4451  if (is_point_done || is_edge_done) {
4452  ebone->temp.i = true;
4453  }
4454 
4455  data->is_changed |= is_point_done;
4456 }
4458  struct EditBone *ebone,
4459  const float screen_co_a[2],
4460  const float screen_co_b[2])
4461 {
4462  CircleSelectUserData *data = userData;
4463  bArmature *arm = data->vc->obedit->data;
4464 
4465  if (!(data->select ? EBONE_SELECTABLE(arm, ebone) : EBONE_VISIBLE(arm, ebone))) {
4466  return;
4467  }
4468 
4469  /* Set in the first pass, needed so circle select prioritizes joints. */
4470  if (ebone->temp.i == true) {
4471  return;
4472  }
4473 
4474  if (edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) {
4476  data->is_changed = true;
4477  }
4478 }
4480  const eSelectOp sel_op,
4481  const int mval[2],
4482  float rad)
4483 {
4485  bArmature *arm = vc->obedit->data;
4486 
4487  const bool select = (sel_op != SEL_OP_SUB);
4488 
4489  view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
4490 
4491  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
4493  }
4494 
4496 
4497  /* Operate on fully visible (non-clipped) points. */
4500 
4501  /* Operate on bones as segments clipped to the viewport bounds
4502  * (needed to handle bones with both points outside the view).
4503  * A separate pass is needed since clipped coordinates can't be used for selecting joints. */
4506  &data,
4508 
4509  if (data.is_changed) {
4513  }
4514  return data.is_changed;
4515 }
4516 
4517 static void do_circle_select_mball__doSelectElem(void *userData,
4518  struct MetaElem *ml,
4519  const float screen_co[2])
4520 {
4521  CircleSelectUserData *data = userData;
4522 
4523  if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
4524  if (data->select) {
4525  ml->flag |= SELECT;
4526  }
4527  else {
4528  ml->flag &= ~SELECT;
4529  }
4530  data->is_changed = true;
4531  }
4532 }
4534  const eSelectOp sel_op,
4535  const int mval[2],
4536  float rad)
4537 {
4539 
4540  const bool select = (sel_op != SEL_OP_SUB);
4541 
4542  view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
4543 
4544  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
4545  data.is_changed |= BKE_mball_deselect_all(vc->obedit->data);
4546  }
4547 
4549 
4552  return data.is_changed;
4553 }
4554 
4559  ViewContext *vc,
4560  wmGenericUserData *wm_userdata,
4561  const eSelectOp sel_op,
4562  const int mval[2],
4563  float rad)
4564 {
4565  bool changed = false;
4567  switch (vc->obedit->type) {
4568  case OB_MESH:
4569  changed = mesh_circle_select(vc, wm_userdata, sel_op, mval, rad);
4570  break;
4571  case OB_CURVES_LEGACY:
4572  case OB_SURF:
4573  changed = nurbscurve_circle_select(vc, sel_op, mval, rad);
4574  break;
4575  case OB_LATTICE:
4576  changed = lattice_circle_select(vc, sel_op, mval, rad);
4577  break;
4578  case OB_ARMATURE:
4579  changed = armature_circle_select(vc, sel_op, mval, rad);
4580  if (changed) {
4582  }
4583  break;
4584  case OB_MBALL:
4585  changed = mball_circle_select(vc, sel_op, mval, rad);
4586  break;
4587  default:
4588  BLI_assert(0);
4589  break;
4590  }
4591 
4592  if (changed) {
4595  }
4596  return changed;
4597 }
4598 
4600  const eSelectOp sel_op,
4601  const int mval[2],
4602  float rad)
4603 {
4605  ViewLayer *view_layer = vc->view_layer;
4606  View3D *v3d = vc->v3d;
4607 
4608  const float radius_squared = rad * rad;
4609  const float mval_fl[2] = {mval[0], mval[1]};
4610 
4611  bool changed = false;
4612  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
4613  changed |= object_deselect_all_visible(vc->view_layer, vc->v3d);
4614  }
4615  const bool select = (sel_op != SEL_OP_SUB);
4616  const int select_flag = select ? BASE_SELECTED : 0;
4617 
4618  Base *base;
4619  for (base = FIRSTBASE(view_layer); base; base = base->next) {
4620  if (BASE_SELECTABLE(v3d, base) && ((base->flag & BASE_SELECTED) != select_flag)) {
4621  float screen_co[2];
4623  vc->region, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_DEFAULT) ==
4624  V3D_PROJ_RET_OK) {
4625  if (len_squared_v2v2(mval_fl, screen_co) <= radius_squared) {
4627  changed = true;
4628  }
4629  }
4630  }
4631  }
4632 
4633  return changed;
4634 }
4635 
4636 /* not a real operator, only for circle test */
4638 {
4639  bContext *C = user_data;
4641  ViewContext vc;
4643  em_setup_viewcontext(C, &vc);
4644 
4645  if (vc.obedit) {
4646  switch (vc.obedit->type) {
4647  case OB_MESH: {
4649  vc.view_layer, vc.v3d, vc.obact->type, vc.obact->mode, ob_iter) {
4650  ED_view3d_viewcontext_init_object(&vc, ob_iter);
4653  }
4655  break;
4656  }
4657 
4658  default:
4659  break;
4660  }
4661  }
4662 }
4663 
4664 static int view3d_circle_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
4665 {
4666  int result = WM_gesture_circle_modal(C, op, event);
4667  if (result & OPERATOR_FINISHED) {
4669  }
4670  return result;
4671 }
4672 
4674 {
4677 }
4678 
4680 {
4682  ViewContext vc;
4683  const int radius = RNA_int_get(op->ptr, "radius");
4684  const int mval[2] = {RNA_int_get(op->ptr, "x"), RNA_int_get(op->ptr, "y")};
4685 
4686  /* Allow each selection type to allocate their own data that's used between executions. */
4687  wmGesture *gesture = op->customdata; /* NULL when non-modal. */
4688  wmGenericUserData wm_userdata_buf = {0};
4689  wmGenericUserData *wm_userdata = gesture ? &gesture->user_data : &wm_userdata_buf;
4690 
4691  const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
4692  WM_gesture_is_modal_first(gesture));
4693 
4695 
4696  Object *obact = vc.obact;
4697  Object *obedit = vc.obedit;
4698 
4699  if (obedit || BKE_paint_select_elem_test(obact) || (obact && (obact->mode & OB_MODE_POSE))) {
4701  if (obedit == NULL) {
4703  }
4704 
4705  FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, vc.v3d, obact->type, obact->mode, ob_iter) {
4706  ED_view3d_viewcontext_init_object(&vc, ob_iter);
4707 
4708  obact = vc.obact;
4709  obedit = vc.obedit;
4710 
4711  if (obedit) {
4712  obedit_circle_select(C, &vc, wm_userdata, sel_op, mval, (float)radius);
4713  }
4714  else if (BKE_paint_select_face_test(obact)) {
4715  paint_facesel_circle_select(&vc, wm_userdata, sel_op, mval, (float)radius);
4716  }
4717  else if (BKE_paint_select_vert_test(obact)) {
4718  paint_vertsel_circle_select(&vc, wm_userdata, sel_op, mval, (float)radius);
4719  }
4720  else if (obact->mode & OB_MODE_POSE) {
4721  pose_circle_select(&vc, sel_op, mval, (float)radius);
4723  }
4724  else {
4725  BLI_assert(0);
4726  }
4727  }
4729  }
4730  else if (obact && (obact->mode & OB_MODE_PARTICLE_EDIT)) {
4731  if (PE_circle_select(C, wm_userdata, sel_op, mval, (float)radius)) {
4732  return OPERATOR_FINISHED;
4733  }
4734  return OPERATOR_CANCELLED;
4735  }
4736  else if (obact && obact->mode & OB_MODE_SCULPT) {
4737  return OPERATOR_CANCELLED;
4738  }
4739  else {
4740  if (object_circle_select(&vc, sel_op, mval, (float)radius)) {
4743 
4745  }
4746  }
4747 
4748  /* Otherwise this is freed by the gesture. */
4749  if (wm_userdata == &wm_userdata_buf) {
4750  WM_generic_user_data_free(wm_userdata);
4751  }
4752  else {
4753  struct EditSelectBuf_Cache *esel = wm_userdata->data;
4754  if (esel && esel->select_bitmap) {
4755  MEM_freeN(esel->select_bitmap);
4756  esel->select_bitmap = NULL;
4757  }
4758  }
4759 
4760  return OPERATOR_FINISHED;
4761 }
4762 
4764 {
4765  ot->name = "Circle Select";
4766  ot->description = "Select items using circle selection";
4767  ot->idname = "VIEW3D_OT_select_circle";
4768 
4775 
4776  /* flags */
4777  ot->flag = OPTYPE_UNDO;
4778 
4779  /* properties */
4782 }
4783 
typedef float(TangentPoint)[2]
Blender kernel action and pose functionality.
#define PBONE_SELECTABLE(arm, bone)
Definition: BKE_armature.h:554
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1370
#define CTX_DATA_BEGIN(C, Type, instance, member)
Definition: BKE_context.h:269
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1528
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:784
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct RegionView3D * CTX_wm_region_view3d(const bContext *C)
Definition: context.c:793
#define CTX_DATA_END
Definition: BKE_context.h:278
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
bool BKE_nurbList_flag_set_from_flag(ListBase *editnurb, uint8_t from_flag, uint8_t flag)
Definition: curve.cc:4389
struct ListBase * BKE_curve_editNurbs_get(struct Curve *cu)
Definition: curve.cc:426
void BKE_curve_nurb_vert_active_validate(struct Curve *cu)
Definition: curve.cc:5076
void BKE_nurbList_flag_set(ListBase *editnurb, uint8_t flag, bool set)
Definition: curve.cc:4354
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:58
#define FOREACH_BASE_IN_MODE_END
Definition: BKE_layer.h:370
#define BKE_view_layer_array_from_bases_in_edit_mode(view_layer, v3d, r_len)
Definition: BKE_layer.h:539
#define FOREACH_OBJECT_IN_MODE_END
Definition: BKE_layer.h:384
struct Base * BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob)
Definition: layer.c:379
#define BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:546
#define FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _v3d, _object_type, _object_mode, _instance)
Definition: BKE_layer.h:354
#define FOREACH_OBJECT_IN_MODE_BEGIN(_view_layer, _v3d, _object_type, _object_mode, _instance)
Definition: BKE_layer.h:380
bool BKE_mball_deselect_all(struct MetaBall *mb)
Definition: mball.c:691
struct Mesh * BKE_mesh_from_object(struct Object *ob)
Definition: mesh.cc:1365
void BKE_mesh_mselect_active_set(struct Mesh *me, int index, int type)
Definition: mesh.cc:1784
void BKE_mesh_mselect_validate(struct Mesh *me)
Definition: mesh.cc:1701
General operations, lookup, etc. for blender objects.
struct MovieClip * BKE_object_movieclip_get(struct Scene *scene, struct Object *ob, bool use_default)
Definition: object.cc:5042
struct Object * BKE_object_pose_armature_get_with_wpaint_check(struct Object *ob)
Definition: object.cc:2531
void BKE_object_update_select_id(struct Main *bmain)
Definition: object.cc:5504
struct Object * BKE_object_pose_armature_get(struct Object *ob)
Definition: object.cc:2511
bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode)
Definition: object.cc:2034
bool BKE_object_is_in_editmode(const struct Object *ob)
bool BKE_paint_select_elem_test(struct Object *ob)
Definition: paint.c:994
bool BKE_paint_select_vert_test(struct Object *ob)
Definition: paint.c:987
bool BKE_paint_select_face_test(struct Object *ob)
Definition: paint.c:980
void BKE_tracking_track_deselect(struct MovieTrackingTrack *track, int area)
Definition: tracking.c:1284
@ TRACK_AREA_ALL
Definition: BKE_tracking.h:43
#define TRACK_SELECTED(track)
Definition: BKE_tracking.h:823
void BKE_tracking_track_select(struct ListBase *tracksbase, struct MovieTrackingTrack *track, int area, bool extend)
Definition: tracking.c:1257
struct MovieTrackingTrack * BKE_tracking_track_get_indexed(struct MovieTracking *tracking, int tracknr, struct ListBase **r_tracksbase)
Definition: tracking.c:1056
struct ListBase * BKE_tracking_object_get_tracks(struct MovieTracking *tracking, struct MovieTrackingObject *object)
Definition: tracking.c:2112
A (mainly) macro array library.
#define BLI_array_append(arr, item)
Definition: BLI_array.h:98
#define BLI_array_declare(arr)
Definition: BLI_array.h:50
#define BLI_array_len(arr)
Definition: BLI_array.h:63
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
#define BLI_BITMAP_TEST_BOOL(_bitmap, _index)
Definition: BLI_bitmap.h:74
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:16
BLI_INLINE void BLI_endian_switch_uint32(unsigned int *val) ATTR_NONNULL(1)
struct GSet GSet
Definition: BLI_ghash.h:340
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1007
GSet * BLI_gset_ptr_new(const char *info)
void BLI_gset_insert(GSet *gs, void *key)
Definition: BLI_ghash.c:962
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1037
bool BLI_lasso_is_point_inside(const int mcoords[][2], unsigned int mcoords_len, int sx, int sy, int error_value)
Definition: lasso_2d.c:38
void BLI_lasso_boundbox(struct rcti *rect, const int mcoords[][2], unsigned int mcoords_len)
Definition: lasso_2d.c:15
bool BLI_lasso_is_edge_inside(const int mcoords[][2], unsigned int mcoords_len, int x0, int y0, int x1, int y1, int error_value)
Definition: lasso_2d.c:52
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
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:283
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 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_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:469
bool BLI_rcti_isect_pt(const struct rcti *rect, int x, int y)
bool BLI_rctf_isect_segment(const struct rctf *rect, const float s1[2], const float s2[2])
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, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNPACK2(a)
#define ARRAY_SIZE(arr)
#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:35
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_SELECT
Definition: DNA_ID.h:818
@ ID_RECALC_BASE_FLAGS
Definition: DNA_ID.h:821
#define MAX_ID_NAME
Definition: DNA_ID.h:337
@ LIB_TAG_DOIT
Definition: DNA_ID.h:707
@ BONE_ROOTSEL
@ BONE_SELECTED
@ BONE_UNSELECTABLE
@ BONE_DONE
@ BONE_TIPSEL
eBezTriple_Flag
@ BEZT_FLAG_TEMP_TAG
#define GPENCIL_ANY_MODE(gpd)
@ BASE_SELECTABLE
@ BASE_SELECTED
@ ME_VSEL
@ ME_HIDE
@ ME_FACE_SEL
#define MB_SCALE_RAD
#define OB_MODE_ALL_WEIGHT_PAINT
eObjectMode
@ OB_MODE_PARTICLE_EDIT
@ OB_MODE_EDIT
@ OB_MODE_WEIGHT_PAINT
@ OB_MODE_SCULPT
@ OB_MODE_POSE
@ OB_MODE_TEXTURE_PAINT
@ OB_MODE_OBJECT
@ OB_MODE_VERTEX_PAINT
Object is a sort of wrapper for general info.
@ OB_LATTICE
@ OB_MBALL
@ OB_SURF
@ OB_CAMERA
@ OB_FONT
@ OB_ARMATURE
@ OB_MESH
@ OB_CURVES_LEGACY
@ OB_GPENCIL
#define FIRSTBASE(_view_layer)
#define SCE_SELECT_FACE
@ SCE_OBJECT_MODE_LOCK
#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_circle(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, const int center[2], int radius, uint *r_bitmap_len)
uint * DRW_select_buffer_bitmap_from_poly(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, const int poly[][2], int poly_len, const struct rcti *rect, uint *r_bitmap_len)
void DRW_select_buffer_context_create(struct Base **bases, uint bases_len, short select_mode)
#define BONESEL_ANY
Definition: ED_armature.h:44
#define EBONE_VISIBLE(arm, ebone)
Definition: ED_armature.h:47
#define BONESEL_ROOT
Definition: ED_armature.h:41
#define BONESEL_TIP
Definition: ED_armature.h:42
#define BONESEL_BONE
Definition: ED_armature.h:43
#define EBONE_SELECTABLE(arm, ebone)
Definition: ED_armature.h:52
bool ED_lattice_flags_set(struct Object *obedit, int flag)
bool ED_lattice_select_pick(struct bContext *C, const int mval[2], const struct SelectPick_Params *params)
#define MBALLSEL_ANY
Definition: ED_mball.h:74
#define MBALLSEL_STIFF
Definition: ED_mball.h:72
bool ED_mball_select_pick(struct bContext *C, const int mval[2], const struct SelectPick_Params *params)
Definition: mball_edit.c:847
#define MBALLSEL_RADIUS
Definition: ED_mball.h:73
bool paintvert_deselect_all_visible(struct Object *ob, int action, bool flush_flags)
Definition: editface.cc:464
#define ED_MESH_PICK_DEFAULT_VERT_DIST
Definition: ED_mesh.h:677
bool EDBM_select_pick(struct bContext *C, const int mval[2], const struct SelectPick_Params *params)
bool paintface_deselect_all_visible(struct bContext *C, struct Object *ob, int action, bool flush_flags)
Definition: editface.cc:255
void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc)
void paintface_flush_flags(struct bContext *C, struct Object *ob, short flag)
Definition: editface.cc:39
void paintvert_flush_flags(struct Object *ob)
Definition: editface.cc:412
bool paintface_mouse_select(struct bContext *C, const int mval[2], const struct SelectPick_Params *params, struct Object *ob)
void EDBM_flag_disable_all(struct BMEditMesh *em, char hflag)
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.cc:1359
void paintvert_tag_select_update(struct bContext *C, struct Object *ob)
Definition: editface.cc:458
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:387
void ED_object_base_select(struct Base *base, eObjectSelect_Mode mode)
Definition: object_select.c:76
void ED_object_base_activate(struct bContext *C, struct Base *base)
@ BA_DESELECT
Definition: ED_object.h:154
@ BA_SELECT
Definition: ED_object.h:155
void ED_outliner_select_sync_from_object_tag(struct bContext *C)
void ED_outliner_select_sync_from_edit_bone_tag(struct bContext *C)
void ED_outliner_select_sync_from_pose_bone_tag(struct bContext *C)
int PE_lasso_select(struct bContext *C, const int mcoords[][2], int mcoords_len, int sel_op)
bool PE_circle_select(struct bContext *C, struct wmGenericUserData *wm_userdata, int sel_op, const int mval[2], float rad)
bool PE_box_select(struct bContext *C, const struct rcti *rect, int sel_op)
bool PE_mouse_particles(struct bContext *C, const int mval[2], const struct SelectPick_Params *params)
bool ED_operator_view3d_active(struct bContext *C)
Definition: screen_ops.c:225
bool ED_operator_region_view3d_active(struct bContext *C)
Definition: screen_ops.c:230
int ED_select_op_action_deselected(eSelectOp sel_op, bool is_select, bool is_inside)
Definition: select_utils.c:38
eSelectOp ED_select_op_modal(eSelectOp sel_op, bool is_first)
Definition: select_utils.c:59
void ED_select_pick_params_from_operator(struct PointerRNA *ptr, struct SelectPick_Params *params) ATTR_NONNULL(1
#define SEL_OP_USE_PRE_DESELECT(sel_op)
const char * ED_select_circle_get_name(struct wmOperatorType *ot, PointerRNA *ptr)
#define SEL_OP_CAN_DESELECT(sel_op)
@ SEL_DESELECT
eSelectOp ED_select_op_from_operator(struct PointerRNA *ptr) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
Definition: select_utils.c:128
void const char * ED_select_pick_get_name(struct wmOperatorType *ot, PointerRNA *ptr)
#define SEL_OP_USE_OUTSIDE(sel_op)
eSelectOp
@ SEL_OP_ADD
@ SEL_OP_SUB
@ SEL_OP_SET
@ SEL_OP_AND
@ SEL_OP_XOR
#define V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT
Definition: ED_view3d.h:270
#define XRAY_ENABLED(v3d)
Definition: ED_view3d.h:1299
int view3d_opengl_select_ex(struct ViewContext *vc, struct GPUSelectResult *buffer, unsigned int buffer_len, const struct rcti *input, eV3DSelectMode select_mode, eV3DSelectObjectFilter select_filter, bool do_material_slot_selection)
void view3d_opengl_select_cache_end(void)
Definition: view3d_view.c:470
eV3DProjStatus ED_view3d_project_base(const struct ARegion *region, struct Base *base)
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, eV3DProjTest clip_flag)
eV3DProjTest
Definition: ED_view3d.h:233
@ V3D_PROJ_TEST_CLIP_NEAR
Definition: ED_view3d.h:237
@ V3D_PROJ_TEST_CLIP_BB
Definition: ED_view3d.h:235
void mball_foreachScreenElem(struct ViewContext *vc, void(*func)(void *userData, struct MetaElem *ml, const float screen_co[2]), void *userData, eV3DProjTest clip_flag)
int view3d_opengl_select(struct ViewContext *vc, struct GPUSelectResult *buffer, unsigned int buffer_len, const struct rcti *input, eV3DSelectMode select_mode, eV3DSelectObjectFilter select_filter)
eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
@ V3D_PROJ_RET_OK
Definition: ED_view3d.h:217
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, 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, eV3DProjTest clip_flag)
#define XRAY_ACTIVE(v3d)
Definition: ED_view3d.h:1300
void meshobject_foreachScreenVert(struct ViewContext *vc, void(*func)(void *userData, struct MVert *eve, const float screen_co[2], int index), void *userData, eV3DProjTest clip_flag)
#define IS_CLIPPED
Definition: ED_view3d.h:213
void view3d_opengl_select_cache_begin(void)
Definition: view3d_view.c:465
void lattice_foreachScreenVert(struct ViewContext *vc, void(*func)(void *userData, struct BPoint *bp, const float screen_co[2]), void *userData, eV3DProjTest clip_flag)
#define V3D_PROJ_TEST_CLIP_DEFAULT
Definition: ED_view3d.h:264
#define MAXPICKELEMS
Definition: ED_view3d.h:894
@ VIEW3D_SELECT_PICK_ALL
Definition: ED_view3d.h:900
@ VIEW3D_SELECT_PICK_NEAREST
Definition: ED_view3d.h:902
@ VIEW3D_SELECT_ALL
Definition: ED_view3d.h:898
eV3DSelectObjectFilter ED_view3d_select_filter_from_mode(const struct Scene *scene, const struct Object *obact)
#define XRAY_FLAG_ENABLED(v3d)
Definition: ED_view3d.h:1298
void view3d_operator_needs_opengl(const struct bContext *C)
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, eV3DProjTest clip_flag)
void ED_view3d_init_mats_rv3d(const struct Object *ob, struct RegionView3D *rv3d)
Definition: space_view3d.c:166
eV3DSelectObjectFilter
Definition: ED_view3d.h:905
@ VIEW3D_SELECT_FILTER_NOP
Definition: ED_view3d.h:907
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, eV3DProjTest clip_flag)
void mesh_foreachScreenFace(struct ViewContext *vc, void(*func)(void *userData, struct BMFace *efa, const float screen_co[2], int index), void *userData, eV3DProjTest clip_flag)
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:225
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:294
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
@ PROP_HIDDEN
Definition: RNA_types.h:216
#define C
Definition: RandGen.cpp:25
int UI_icon_from_id(const struct ID *id)
#define UI_DPI_FAC
Definition: UI_interface.h:305
@ OPTYPE_DEPENDS_ON_CURSOR
Definition: WM_types.h:184
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define NC_GEOM
Definition: WM_types.h:343
#define NC_MOVIECLIP
Definition: WM_types.h:347
#define ND_OB_SELECT
Definition: WM_types.h:390
#define NC_SCENE
Definition: WM_types.h:328
#define ND_SELECT
Definition: WM_types.h:455
#define ND_BONE_ACTIVE
Definition: WM_types.h:408
@ WM_OP_INVOKE_DEFAULT
Definition: WM_types.h:201
#define ND_BONE_SELECT
Definition: WM_types.h:409
#define NC_OBJECT
Definition: WM_types.h:329
bool ED_armature_edit_select_pick_bone(bContext *C, Base *basact, EditBone *ebone, const int selmask, const struct SelectPick_Params *params)
bool ED_armature_edit_deselect_all_visible(Object *obedit)
bool ED_armature_edit_select_pick(bContext *C, const int mval[2], const struct SelectPick_Params *params)
Base * ED_armature_base_and_bone_from_select_buffer(Base **bases, uint bases_len, const uint select_id, Bone **r_bone)
Base * ED_armature_base_and_pchan_from_select_buffer(Base **bases, uint bases_len, const uint select_id, bPoseChannel **r_pchan)
Base * ED_armature_base_and_ebone_from_select_buffer(Base **bases, uint bases_len, const uint select_id, EditBone **r_ebone)
bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
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)
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: avxb.h:154
@ 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:12
#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_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, eBMSelectionFlushFLags flags)
Select Mode Flush.
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.
@ BM_SELECT_LEN_FLUSH_RECALC_ALL
Definition: bmesh_marking.h:20
@ BM_SELECT_LEN_FLUSH_RECALC_NOTHING
Definition: bmesh_marking.h:16
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], const int dist_px, const bool vert_without_handles, const struct SelectPick_Params *params)
Definition: editcurve.c:4729
bool ED_curve_editfont_select_pick(bContext *C, const int mval[2], const struct SelectPick_Params *params)
Definition: editfont.c:2174
static bool is_inside(int x, int y, int cols, int rows)
Definition: filesel.c:706
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_global float * buffer
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static unsigned a[3]
Definition: RandGen.cpp:78
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
bool ED_armature_pose_select_pick_bone(ViewLayer *view_layer, View3D *v3d, Object *ob, Bone *bone, const struct SelectPick_Params *params)
Definition: pose_select.c:124
void ED_pose_bone_select_tag_update(Object *ob)
Definition: pose_select.c:80
bool ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibility)
Definition: pose_select.c:315
bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer, View3D *v3d, Base *base, const struct GPUSelectResult *buffer, const short hits, const struct SelectPick_Params *params, bool do_nearest)
Definition: pose_select.c:246
void ED_armature_pose_select_in_wpaint_mode(ViewLayer *view_layer, Base *base_select)
Definition: pose_select.c:269
void RNA_int_set_array(PointerRNA *ptr, const char *name, const int *values)
Definition: rna_access.c:4945
void RNA_int_get_array(PointerRNA *ptr, const char *name, int *values)
Definition: rna_access.c:4933
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:4874
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
PropertyRNA * RNA_def_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:3623
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
Definition: rna_define.c:4487
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
Definition: rna_define.c:4436
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
Definition: rna_define.c:3830
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3783
const EnumPropertyItem DummyRNA_NULL_items[]
Definition: rna_rna.c:26
#define min(a, b)
Definition: sort.c:35
unsigned char uint8_t
Definition: stdint.h:78
short selectmode
Definition: BKE_editmesh.h:52
struct BMesh * bm
Definition: BKE_editmesh.h:40
int totfacesel
Definition: bmesh_class.h:298
int totvertsel
Definition: bmesh_class.h:298
int totedgesel
Definition: bmesh_class.h:298
uint8_t f1
struct Base * next
short flag
short sy
struct Object * object
short sx
uint8_t f3
uint8_t f1
uint8_t f2
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:43
union EditBone::@3 temp
BLI_bitmap * select_bitmap
const char * name
Definition: RNA_types.h:465
unsigned int id
Definition: GPU_select.h:34
int tag
Definition: DNA_ID.h:387
char name[66]
Definition: DNA_ID.h:378
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:34
void * link
Definition: BLI_linklist.h:24
struct LinkNode * next
Definition: BLI_linklist.h:23
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
struct MVert * mvert
int totvert
int totpoly
struct MPoly * mpoly
ListBase * editelems
short flag
struct MovieTracking tracking
struct Object * track
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 Depsgraph * depsgraph
Definition: ED_view3d.h:64
struct Scene * scene
Definition: ED_view3d.h:65
struct ARegion * region
Definition: ED_view3d.h:69
struct ViewLayer * view_layer
Definition: ED_view3d.h:66
struct BMEditMesh * em
Definition: ED_view3d.h:73
struct Main * bmain
Definition: ED_view3d.h:59
struct bContext * C
Definition: ED_view3d.h:58
struct Object * obact
Definition: ED_view3d.h:67
struct Object * obedit
Definition: ED_view3d.h:68
struct wmWindow * win
Definition: ED_view3d.h:71
struct View3D * v3d
Definition: ED_view3d.h:70
struct RegionView3D * rv3d
Definition: ED_view3d.h:72
ListBase object_bases
ListBase * edbo
struct Bone * bone
ListBase chanbase
float xmax
Definition: DNA_vec_types.h:69
float xmin
Definition: DNA_vec_types.h:69
float ymax
Definition: DNA_vec_types.h:70
float ymin
Definition: DNA_vec_types.h:70
int mval[2]
Definition: WM_types.h:684
wmGenericUserDataFreeFn free_fn
Definition: WM_types.h:129
wmGenericUserData user_data
Definition: WM_types.h:595
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:927
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
PropertyRNA * prop
Definition: WM_types.h:981
const char *(* get_name)(struct wmOperatorType *, struct PointerRNA *)
Definition: WM_types.h:960
struct PointerRNA * ptr
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 bool bone_mouse_select_menu(bContext *C, const GPUSelectResult *buffer, const int hits, const bool is_editmode, const struct SelectPick_Params *params)
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 int mixed_bones_object_selectbuffer_extended(ViewContext *vc, GPUSelectResult *buffer, const int buffer_len, const int mval[2], eV3DSelectObjectFilter select_filter, bool use_cycle, bool enumerate, bool *r_do_nearest)
static bool armature_circle_doSelectJoint(void *userData, EditBone *ebone, const float screen_co[2], bool head)
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 ed_wpaint_vertex_select_pick(bContext *C, const int mval[2], const struct SelectPick_Params *params, Object *obact)
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 int gpu_select_buffer_depth_id_cmp(const void *sel_a_p, const void *sel_b_p)
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 bool object_mouse_select_menu(bContext *C, ViewContext *vc, const GPUSelectResult *buffer, const int hits, const int mval[2], const struct SelectPick_Params *params, Base **r_basact)
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 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 bool edge_inside_rect(const rctf *rect, const float v1[2], const float v2[2])
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 int view3d_circle_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
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 int selectbuffer_ret_hits_15(GPUSelectResult *UNUSED(buffer), const int hits15)
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 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_armature__doSelectBone_clip_content(void *userData, EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
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 int mixed_bones_object_selectbuffer(ViewContext *vc, GPUSelectResult *buffer, const int buffer_len, const int mval[2], eV3DSelectObjectFilter select_filter, bool do_nearest, bool do_nearest_xray_if_supported, const bool do_material_slot_selection)
static int selectbuffer_ret_hits_9(GPUSelectResult *buffer, const int hits15, const int hits9)
static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const eSelectOp sel_op)
static int selectbuffer_ret_hits_5(GPUSelectResult *buffer, const int hits15, const int hits9, const int hits5)
static void paint_vertsel_circle_select_doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
#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)
struct CircleSelectUserData CircleSelectUserData
static bool pose_circle_select(ViewContext *vc, const eSelectOp sel_op, const int mval[2], float rad)
static void do_circle_select_armature__doSelectBone_clip_content(void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
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 void view3d_circle_select_cancel(bContext *C, wmOperator *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)
struct Object * ED_view3d_give_material_slot_under_cursor(struct bContext *C, const int mval[2], int *r_material_slot)
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 Base * mouse_select_object_center(ViewContext *vc, Base *startbase, const int mval[2])
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 Base * mouse_select_eval_buffer(ViewContext *vc, const GPUSelectResult *buffer, int hits, bool do_nearest, bool has_bones, bool do_bones_get_priotity, int *r_select_id_subelem)
static Base * ed_view3d_give_base_under_cursor_ex(bContext *C, const int mval[2], int *r_material_slot)
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)
static bool ed_object_select_pick_camera_track(bContext *C, Scene *scene, Base *basact, MovieClip *clip, const struct GPUSelectResult *buffer, const short hits, const struct SelectPick_Params *params)
struct LassoSelectUserData LassoSelectUserData
static bool mesh_circle_select(ViewContext *vc, wmGenericUserData *wm_userdata, eSelectOp sel_op, const int mval[2], float rad)
static void view3d_circle_select_recalc(void *user_data)
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 selectbuffer_has_bones(const GPUSelectResult *buffer, const uint hits)
static bool view3d_selectable_data(bContext *C)
static int bone_select_menu_exec(bContext *C, wmOperator *op)
static bool ed_object_select_pick(bContext *C, const int mval[2], const struct SelectPick_Params *params, const bool center, const bool enumerate, const bool object_only)
static int view3d_select_exec(bContext *C, wmOperator *op)
bool WM_cursor_test_motion_and_update(const int mval[2])
void WM_main_add_notifier(unsigned int type, void *reference)
int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition: wm_files.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479
bool WM_gesture_is_modal_first(const wmGesture *gesture)
Definition: wm_gesture.c:108
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)
int WM_operator_flag_only_pass_through_on_press(int retval, const struct wmEvent *event)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
Definition: wm_operators.c:661
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
void WM_operator_properties_free(PointerRNA *ptr)
Definition: wm_operators.c:783
void WM_toolsystem_update_from_context_view3d(bContext *C)
void WM_generic_user_data_free(wmGenericUserData *wm_userdata)
Definition: wm_utils.c:45