4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2008 Blender Foundation.
21 * All rights reserved.
24 * Contributor(s): Blender Foundation
26 * ***** END GPL LICENSE BLOCK *****
34 #include "DNA_action_types.h"
35 #include "DNA_armature_types.h"
36 #include "DNA_curve_types.h"
37 #include "DNA_camera_types.h"
38 #include "DNA_lamp_types.h"
39 #include "DNA_meta_types.h"
40 #include "DNA_mesh_types.h"
41 #include "DNA_meshdata_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_space_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_userdef_types.h"
47 #include "DNA_view3d_types.h"
48 #include "DNA_world_types.h"
50 #include "MEM_guardedalloc.h"
52 #include "BLI_arithb.h"
53 #include "BLI_blenlib.h"
54 #include "BLI_editVert.h"
57 #include "BKE_action.h"
58 #include "BKE_context.h"
59 #include "BKE_depsgraph.h"
60 #include "BKE_object.h"
61 #include "BKE_global.h"
62 #include "BKE_scene.h"
63 #include "BKE_screen.h"
64 #include "BKE_utildefines.h"
66 #include "RE_pipeline.h" // make_stars
69 #include "BIF_retopo.h"
74 #include "RNA_access.h"
75 #include "RNA_define.h"
77 #include "ED_armature.h"
79 #include "ED_particle.h"
81 #include "ED_object.h"
82 #include "ED_screen.h"
86 #include "UI_interface.h"
87 #include "UI_resources.h"
88 #include "UI_view2d.h"
90 #include "PIL_time.h" /* smoothview */
92 #include "view3d_intern.h" // own include
95 void view3d_set_viewcontext(bContext *C, ViewContext *vc)
97 memset(vc, 0, sizeof(ViewContext));
98 vc->ar= CTX_wm_region(C);
99 vc->scene= CTX_data_scene(C);
100 vc->v3d= CTX_wm_view3d(C);
101 vc->rv3d= vc->ar->regiondata;
102 vc->obact= CTX_data_active_object(C);
103 vc->obedit= CTX_data_edit_object(C);
106 void view3d_get_view_aligned_coordinate(ViewContext *vc, float *fp, short mval[2])
114 project_short_noclip(vc->ar, fp, mval);
116 initgrabz(vc->rv3d, fp[0], fp[1], fp[2]);
118 if(mval[0]!=IS_CLIPPED) {
119 window_to_3d_delta(vc->ar, dvec, mval[0]-mx, mval[1]-my);
120 VecSubf(fp, fp, dvec);
124 void view3d_get_transformation(ViewContext *vc, Object *ob, bglMats *mats)
129 Mat4MulMat4(cpy, vc->rv3d->viewmat, ob->obmat);
131 for(i = 0; i < 4; ++i) {
132 for(j = 0; j < 4; ++j) {
133 mats->projection[i*4+j] = vc->rv3d->winmat[i][j];
134 mats->modelview[i*4+j] = cpy[i][j];
138 mats->viewport[0] = vc->ar->winrct.xmin;
139 mats->viewport[1] = vc->ar->winrct.ymin;
140 mats->viewport[2] = vc->ar->winx;
141 mats->viewport[3] = vc->ar->winy;
144 /* ********************** view3d_select: selection manipulations ********************* */
146 /* XXX to solve *************** */
147 static void BIF_undo_push() {}
148 /* XXX end ********************* */
150 /* local prototypes */
152 void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select)
155 int index= em_wireoffs;
157 for(eve= em->verts.first; eve; eve= eve->next, index++) {
159 if(EM_check_backbuf(index)) {
160 eve->f = select?(eve->f|1):(eve->f&~1);
166 void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select)
169 int index= em_solidoffs;
171 for(eed= em->edges.first; eed; eed= eed->next, index++) {
173 if(EM_check_backbuf(index)) {
174 EM_select_edge(eed, select);
180 void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select)
185 for(efa= em->faces.first; efa; efa= efa->next, index++) {
187 if(EM_check_backbuf(index)) {
188 EM_select_face_fgon(em, efa, select);
194 void EM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
196 MFace *mface = me->mface;
200 for(a=1; a<=me->totface; a++, mface++) {
201 if(EM_check_backbuf(a)) {
202 mface->flag = select?(mface->flag|ME_FACE_SEL):(mface->flag&~ME_FACE_SEL);
208 void arrows_move_cursor(unsigned short event)
215 if(event==UPARROWKEY) {
216 warp_pointer(mval[0], mval[1]+1);
217 } else if(event==DOWNARROWKEY) {
218 warp_pointer(mval[0], mval[1]-1);
219 } else if(event==LEFTARROWKEY) {
220 warp_pointer(mval[0]-1, mval[1]);
221 } else if(event==RIGHTARROWKEY) {
222 warp_pointer(mval[0]+1, mval[1]);
228 /* *********************** GESTURE AND LASSO ******************* */
230 /* helper also for borderselect */
231 static int edge_fully_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
233 return BLI_in_rcti(rect, x1, y1) && BLI_in_rcti(rect, x2, y2);
236 static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
240 /* check points in rect */
241 if(edge_fully_inside_rect(rect, x1, y1, x2, y2)) return 1;
243 /* check points completely out rect */
244 if(x1<rect->xmin && x2<rect->xmin) return 0;
245 if(x1>rect->xmax && x2>rect->xmax) return 0;
246 if(y1<rect->ymin && y2<rect->ymin) return 0;
247 if(y1>rect->ymax && y2>rect->ymax) return 0;
249 /* simple check lines intersecting. */
250 d1= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymin );
251 d2= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymax );
252 d3= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymax );
253 d4= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymin );
255 if(d1<0 && d2<0 && d3<0 && d4<0) return 0;
256 if(d1>0 && d2>0 && d3>0 && d4>0) return 0;
262 #define MOVES_GESTURE 50
263 #define MOVES_LASSO 500
265 int lasso_inside(short mcords[][2], short moves, short sx, short sy)
267 /* we do the angle rule, define that all added angles should be about zero or 2*PI */
268 float angletot=0.0, len, dot, ang, cross, fp1[2], fp2[2];
279 fp1[0]= (float)(p1[0]-sx);
280 fp1[1]= (float)(p1[1]-sy);
281 len= sqrt(fp1[0]*fp1[0] + fp1[1]*fp1[1]);
285 for(a=0; a<moves; a++) {
287 fp2[0]= (float)(p2[0]-sx);
288 fp2[1]= (float)(p2[1]-sy);
289 len= sqrt(fp2[0]*fp2[0] + fp2[1]*fp2[1]);
293 /* dot and angle and cross */
294 dot= fp1[0]*fp2[0] + fp1[1]*fp2[1];
295 ang= fabs(saacos(dot));
297 cross= (float)((p1[1]-p2[1])*(p1[0]-sx) + (p2[0]-p1[0])*(p1[1]-sy));
299 if(cross<0.0) angletot-= ang;
303 fp1[0]= fp2[0]; fp1[1]= fp2[1];
308 if( fabs(angletot) > 4.0 ) return 1;
312 /* edge version for lasso select. we assume boundbox check was done */
313 int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1)
318 if(x0==IS_CLIPPED || x1==IS_CLIPPED)
321 v1[0] = x0, v1[1] = y0;
322 v2[0] = x1, v2[1] = y1;
324 /* check points in lasso */
325 if(lasso_inside(mcords, moves, v1[0], v1[1])) return 1;
326 if(lasso_inside(mcords, moves, v2[0], v2[1])) return 1;
328 /* no points in lasso, so we have to intersect with lasso edge */
330 if( IsectLL2Ds(mcords[0], mcords[moves-1], v1, v2) > 0) return 1;
331 for(a=0; a<moves-1; a++) {
332 if( IsectLL2Ds(mcords[a], mcords[a+1], v1, v2) > 0) return 1;
339 /* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN)
340 and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK
342 static void do_lasso_select_pose(ViewContext *vc, short mcords[][2], short moves, short select)
344 Object *ob= vc->obact;
347 short sco1[2], sco2[2];
349 if(ob->type!=OB_ARMATURE || ob->pose==NULL) return;
351 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
352 VECCOPY(vec, pchan->pose_head);
353 Mat4MulVecfl(ob->obmat, vec);
354 project_short(vc->ar, vec, sco1);
355 VECCOPY(vec, pchan->pose_tail);
356 Mat4MulVecfl(ob->obmat, vec);
357 project_short(vc->ar, vec, sco2);
359 if(lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
360 if(select) pchan->bone->flag |= BONE_SELECTED;
361 else pchan->bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
367 static void do_lasso_select_objects(ViewContext *vc, short mcords[][2], short moves, short select)
371 for(base= vc->scene->base.first; base; base= base->next) {
372 if(base->lay & vc->v3d->lay) {
373 project_short(vc->ar, base->object->obmat[3], &base->sx);
374 if(lasso_inside(mcords, moves, base->sx, base->sy)) {
376 if(select) ED_base_object_select(base, BA_SELECT);
377 else ED_base_object_select(base, BA_DESELECT);
378 base->object->flag= base->flag;
380 if(base->object->flag & OB_POSEMODE) {
381 do_lasso_select_pose(vc, mcords, moves, select);
387 void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
391 rect->xmin= rect->xmax= mcords[0][0];
392 rect->ymin= rect->ymax= mcords[0][1];
394 for(a=1; a<moves; a++) {
395 if(mcords[a][0]<rect->xmin) rect->xmin= mcords[a][0];
396 else if(mcords[a][0]>rect->xmax) rect->xmax= mcords[a][0];
397 if(mcords[a][1]<rect->ymin) rect->ymin= mcords[a][1];
398 else if(mcords[a][1]>rect->ymax) rect->ymax= mcords[a][1];
402 static void do_lasso_select_mesh__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
404 struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
406 if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
407 eve->f = data->select?(eve->f|1):(eve->f&~1);
410 static void do_lasso_select_mesh__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
412 struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
414 if (EM_check_backbuf(em_solidoffs+index)) {
416 if ( edge_fully_inside_rect(data->rect, x0, y0, x1, y1) &&
417 lasso_inside(data->mcords, data->moves, x0, y0) &&
418 lasso_inside(data->mcords, data->moves, x1, y1)) {
419 EM_select_edge(eed, data->select);
423 if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) {
424 EM_select_edge(eed, data->select);
429 static void do_lasso_select_mesh__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
431 struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
433 if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
434 EM_select_face_fgon(data->vc.em, efa, data->select);
438 static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves, short select)
440 struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } data;
444 lasso_select_boundbox(&rect, mcords, moves);
447 vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
451 data.mcords = mcords;
453 data.select = select;
457 bbsel= EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
459 if(vc->scene->selectmode & SCE_SELECT_VERTEX) {
461 EM_backbuf_checkAndSelectVerts(vc->em, select);
463 mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, 1);
466 if(vc->scene->selectmode & SCE_SELECT_EDGE) {
467 /* Does both bbsel and non-bbsel versions (need screen cos for both) */
470 mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0);
474 mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0);
478 if(vc->scene->selectmode & SCE_SELECT_FACE) {
480 EM_backbuf_checkAndSelectFaces(vc->em, select);
482 mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data);
487 EM_selectmode_flush(vc->em);
491 /* this is an exception in that its the only lasso that dosnt use the 3d view (uses space image view) */
492 static void do_lasso_select_mesh_uv(short mcords[][2], short moves, short select)
496 int screenUV[2], nverts, i, ok = 1;
499 lasso_select_boundbox(&rect, mcords, moves);
501 if (draw_uvs_face_check()) { /* Face Center Sel */
504 for (efa= em->faces.first; efa; efa= efa->next) {
505 /* assume not touched */
507 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
508 if ((select) != (simaFaceSel_Check(efa, tf))) {
509 uv_center(tf->uv, cent, (void *)efa->v4);
510 uvco_to_areaco_noclip(cent, screenUV);
511 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
516 /* (de)selects all tagged faces and deals with sticky modes */
518 uvface_setsel__internal(select);
520 } else { /* Vert Sel*/
521 for (efa= em->faces.first; efa; efa= efa->next) {
522 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
523 if (simaFaceDraw_Check(efa, tf)) {
524 nverts= efa->v4? 4: 3;
525 for(i=0; i<nverts; i++) {
526 if ((select) != (simaUVSel_Check(efa, tf, i))) {
527 uvco_to_areaco_noclip(tf->uv[i], screenUV);
528 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
530 simaUVSel_Set(efa, tf, i);
532 simaUVSel_UnSet(efa, tf, i);
540 if (ok && G.sima->flag & SI_SYNC_UVSEL) {
541 if (select) EM_select_flush(vc->em);
542 else EM_deselect_flush(vc->em);
547 static void do_lasso_select_curve__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
549 struct { short (*mcords)[2]; short moves; short select; } *data = userData;
551 if (lasso_inside(data->mcords, data->moves, x, y)) {
553 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
555 if (G.f & G_HIDDENHANDLES) {
556 /* can only be beztindex==0 here since handles are hidden */
557 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
560 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
561 } else if (beztindex==1) {
562 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
564 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
571 static void do_lasso_select_curve(ViewContext *vc, short mcords[][2], short moves, short select)
573 struct { short (*mcords)[2]; short moves; short select; } data;
575 /* set vc->editnurb */
576 data.mcords = mcords;
578 data.select = select;
580 nurbs_foreachScreenVert(vc, do_lasso_select_curve__doSelect, &data);
583 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, int y)
585 struct { short (*mcords)[2]; short moves; short select; } *data = userData;
587 if (lasso_inside(data->mcords, data->moves, x, y)) {
588 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
591 static void do_lasso_select_lattice(ViewContext *vc, short mcords[][2], short moves, short select)
593 struct { short (*mcords)[2]; short moves; short select; } data;
595 /* set editdata in vc */
596 data.mcords = mcords;
598 data.select = select;
600 lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data);
603 static void do_lasso_select_armature(ViewContext *vc, short mcords[][2], short moves, short select)
605 bArmature *arm= vc->obedit->data;
608 short sco1[2], sco2[2], didpoint;
610 /* set editdata in vc */
612 for (ebone= arm->edbo->first; ebone; ebone=ebone->next) {
614 VECCOPY(vec, ebone->head);
615 Mat4MulVecfl(vc->obedit->obmat, vec);
616 project_short(vc->ar, vec, sco1);
617 VECCOPY(vec, ebone->tail);
618 Mat4MulVecfl(vc->obedit->obmat, vec);
619 project_short(vc->ar, vec, sco2);
622 if(lasso_inside(mcords, moves, sco1[0], sco1[1])) {
623 if(select) ebone->flag |= BONE_ROOTSEL;
624 else ebone->flag &= ~BONE_ROOTSEL;
627 if(lasso_inside(mcords, moves, sco2[0], sco2[1])) {
628 if(select) ebone->flag |= BONE_TIPSEL;
629 else ebone->flag &= ~BONE_TIPSEL;
632 /* if one of points selected, we skip the bone itself */
633 if(didpoint==0 && lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
634 if(select) ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
635 else ebone->flag &= ~(BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
640 static void do_lasso_select_facemode(ViewContext *vc, short mcords[][2], short moves, short select)
642 Object *ob= vc->obact;
643 Mesh *me= ob?ob->data:NULL;
646 if(me==NULL || me->mtface==NULL) return;
647 if(me->totface==0) return;
649 em_vertoffs= me->totface+1; /* max index array */
651 lasso_select_boundbox(&rect, mcords, moves);
652 EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
654 EM_backbuf_checkAndSelectTFaces(me, select);
658 // XXX object_tface_flags_changed(ob, 0);
662 static void do_lasso_select_node(short mcords[][2], short moves, short select)
664 SpaceNode *snode = sa->spacedata.first;
671 lasso_select_boundbox(&rect, mcords, moves);
673 /* store selection in temp test flag */
674 for(node= snode->edittree->nodes.first; node; node= node->next) {
676 node_centf[0] = (node->totr.xmin+node->totr.xmax)/2;
677 node_centf[1] = (node->totr.ymin+node->totr.ymax)/2;
679 ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
680 if (BLI_in_rcti(&rect, node_cent[0], node_cent[1]) && lasso_inside(mcords, moves, node_cent[0], node_cent[1])) {
682 node->flag |= SELECT;
684 node->flag &= ~SELECT;
688 BIF_undo_push("Lasso select nodes");
692 void view3d_lasso_select(bContext *C, ViewContext *vc, short mcords[][2], short moves, short select)
694 if(vc->obedit==NULL) {
695 if(FACESEL_PAINT_TEST)
696 do_lasso_select_facemode(vc, mcords, moves, select);
697 else if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))
699 else if(G.f & G_PARTICLEEDIT)
700 PE_lasso_select(C, mcords, moves, select);
702 do_lasso_select_objects(vc, mcords, moves, select);
704 else if(vc->obedit->type==OB_MESH) {
705 do_lasso_select_mesh(vc, mcords, moves, select);
706 } else if(vc->obedit->type==OB_CURVE || vc->obedit->type==OB_SURF)
707 do_lasso_select_curve(vc, mcords, moves, select);
708 else if(vc->obedit->type==OB_LATTICE)
709 do_lasso_select_lattice(vc, mcords, moves, select);
710 else if(vc->obedit->type==OB_ARMATURE)
711 do_lasso_select_armature(vc, mcords, moves, select);
713 BIF_undo_push("Lasso select");
717 static EnumPropertyItem lasso_select_types[] = {
718 {0, "SELECT", "Select", ""},
719 {1, "DESELECT", "Deselect", ""},
720 {0, NULL, NULL, NULL}
724 /* lasso operator gives properties, but since old code works
725 with short array we convert */
726 static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
730 short mcords[1024][2];
732 RNA_BEGIN(op->ptr, itemptr, "path") {
735 RNA_float_get_array(&itemptr, "loc", loc);
736 mcords[i][0]= (short)loc[0];
737 mcords[i][1]= (short)loc[1];
744 view3d_operator_needs_opengl(C);
746 /* setup view context for argument to callbacks */
747 view3d_set_viewcontext(C, &vc);
749 select= RNA_enum_is_equal(op->ptr, "type", "SELECT");
750 view3d_lasso_select(C, &vc, mcords, i, select);
752 return OPERATOR_FINISHED;
754 return OPERATOR_PASS_THROUGH;
757 void VIEW3D_OT_lasso_select(wmOperatorType *ot)
759 ot->name= "Lasso Select";
760 ot->idname= "VIEW3D_OT_lasso_select";
762 ot->invoke= WM_gesture_lasso_invoke;
763 ot->modal= WM_gesture_lasso_modal;
764 ot->exec= view3d_lasso_select_exec;
765 ot->poll= WM_operator_winactive;
768 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
770 RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
771 RNA_def_enum(ot->srna, "type", lasso_select_types, 0, "Type", "");
775 /* ************************************************* */
778 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
779 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
782 unsigned int *bufmin,*bufmax;
783 int a,b,rc,tel,aantal,dirvec[4][2],maxob;
784 unsigned int retval=0;
787 if(base==0) return 0;
803 bufmax= buf+ size*size;
804 buf+= aantal*size+ aantal;
806 for(tel=1;tel<=size;tel++) {
811 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
812 if( *buf==dontdo ) retval= dontdo; /* if only color dontdo is available, still return dontdo */
814 buf+= (dirvec[rc][0]+dirvec[rc][1]);
816 if(buf<bufmin || buf>=bufmax) return retval;
826 /* ************************** mouse select ************************* */
829 /* The max number of menu items in an object select menu */
830 #define SEL_MENU_SIZE 22
832 static void deselectall_except(Scene *scene, Base *b) /* deselect all except b */
836 for(base= FIRSTBASE; base; base= base->next) {
837 if (base->flag & SELECT) {
839 ED_base_object_select(base, BA_DESELECT);
845 static Base *mouse_select_menu(ViewContext *vc, unsigned int *buffer, int hits, short *mval)
847 Scene *scene= vc->scene;
848 View3D *v3d= vc->v3d;
849 Base *baseList[SEL_MENU_SIZE]={NULL}; /*baseList is used to store all possible bases to bring up a menu */
852 char menuText[20 + SEL_MENU_SIZE*32] = "Select Object%t"; /* max ob name = 22 */
855 for(base=FIRSTBASE; base; base= base->next) {
856 if (BASE_SELECTABLE(v3d, base)) {
857 baseList[baseCount] = NULL;
859 /* two selection methods, the CTRL select uses max dist of 15 */
862 for(a=0; a<hits; a++) {
863 /* index was converted */
864 if(base->selcol==buffer[ (4 * a) + 3 ]) baseList[baseCount] = base;
870 project_short(vc->ar, base->object->obmat[3], &base->sx);
872 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
873 if(temp<dist ) baseList[baseCount] = base;
876 if(baseList[baseCount]) {
877 if (baseCount < SEL_MENU_SIZE) {
878 baseList[baseCount] = base;
879 sprintf(str, "|%s %%x%d", base->object->id.name+2, baseCount+1); /* max ob name == 22 */
880 strcat(menuText, str);
887 if(baseCount<=1) return baseList[0];
889 baseCount = -1; // XXX = pupmenu(menuText);
891 if (baseCount != -1) { /* If nothing is selected then dont do anything */
892 return baseList[baseCount-1];
898 /* we want a select buffer with bones, if there are... */
899 /* so check three selection levels and compare */
900 static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, short *mval)
904 short a, hits15, hits9=0, hits5=0;
905 short has_bones15=0, has_bones9=0, has_bones5=0;
907 BLI_init_rcti(&rect, mval[0]-14, mval[0]+14, mval[1]-14, mval[1]+14);
908 hits15= view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
910 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
913 BLI_init_rcti(&rect, mval[0]-9, mval[0]+9, mval[1]-9, mval[1]+9);
914 hits9= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
916 for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
919 BLI_init_rcti(&rect, mval[0]-5, mval[0]+5, mval[1]-5, mval[1]+5);
920 hits5= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
922 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
927 offs= 4*hits15 + 4*hits9;
928 memcpy(buffer, buffer+offs, 4*offs);
933 memcpy(buffer, buffer+offs, 4*offs);
941 offs= 4*hits15 + 4*hits9;
942 memcpy(buffer, buffer+offs, 4*offs);
947 memcpy(buffer, buffer+offs, 4*offs);
957 /* mval is region coords */
958 static void mouse_select(bContext *C, short *mval, short extend, short obcenter)
961 ARegion *ar= CTX_wm_region(C);
962 View3D *v3d= CTX_wm_view3d(C);
963 Scene *scene= CTX_data_scene(C);
964 Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
965 unsigned int buffer[4*MAXPICKBUF];
966 int temp, a, dist=100;
969 /* setup view context for argument to callbacks */
970 view3d_set_viewcontext(C, &vc);
972 /* always start list from basact in wire mode */
973 startbase= FIRSTBASE;
974 if(BASACT && BASACT->next) startbase= BASACT->next;
976 /* This block uses the control key to make the object selected by its center point rather then its contents */
977 /* XXX later on, in editmode do not activate */
978 if(vc.obedit==NULL && obcenter) {
980 /* note; shift+alt goes to group-flush-selecting */
983 basact= mouse_select_menu(&vc, NULL, 0, mval);
987 if (BASE_SELECTABLE(v3d, base)) {
988 project_short(ar, base->object->obmat[3], &base->sx);
990 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
991 if(base==BASACT) temp+=10;
1000 if(base==0) base= FIRSTBASE;
1001 if(base==startbase) break;
1006 /* if objects have posemode set, the bones are in the same selection buffer */
1008 hits= mixed_bones_object_selectbuffer(&vc, buffer, mval);
1013 for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1015 /* note; shift+alt goes to group-flush-selecting */
1016 if(has_bones==0 && 0)
1017 basact= mouse_select_menu(&vc, buffer, hits, mval);
1019 static short lastmval[2]={-100, -100};
1022 /* define if we use solid nearest select or not */
1023 if(v3d->drawtype>OB_WIRE) {
1025 if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
1026 if(!has_bones) /* hrms, if theres bones we always do nearest */
1030 lastmval[0]= mval[0]; lastmval[1]= mval[1];
1033 unsigned int min= 0xFFFFFFFF;
1034 int selcol= 0, notcol=0;
1038 /* we skip non-bone hits */
1039 for(a=0; a<hits; a++) {
1040 if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
1042 selcol= buffer[4*a+3] & 0xFFFF;
1047 /* only exclude active object when it is selected... */
1048 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol;
1050 for(a=0; a<hits; a++) {
1051 if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1053 selcol= buffer[4*a+3] & 0xFFFF;
1060 if(base->lay & v3d->lay) {
1061 if(base->selcol==selcol) break;
1065 if(base) basact= base;
1071 /* skip objects with select restriction, to prevent prematurely ending this loop
1072 * with an un-selectable choice */
1073 if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1075 if(base==NULL) base= FIRSTBASE;
1076 if(base==startbase) break;
1079 if(base->lay & v3d->lay) {
1080 for(a=0; a<hits; a++) {
1082 /* skip non-bone objects */
1083 if((buffer[4*a+3] & 0xFFFF0000)) {
1084 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1089 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1098 if(base==NULL) base= FIRSTBASE;
1099 if(base==startbase) break;
1104 if(has_bones && basact) {
1105 if(ED_do_pose_selectbuffer(scene, basact, buffer, hits, extend) ) { /* then bone is found */
1107 /* we make the armature selected:
1108 not-selected active object in posemode won't work well for tools */
1109 basact->flag|= SELECT;
1110 basact->object->flag= basact->flag;
1112 WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, basact->object);
1113 WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, basact->object);
1115 /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1116 if(G.f & G_WEIGHTPAINT) {
1117 /* prevent activating */
1122 /* prevent bone selecting to pass on to object selecting */
1129 /* so, do we have something selected? */
1133 /* only do select */
1134 deselectall_except(scene, basact);
1135 ED_base_object_select(basact, BA_SELECT);
1137 /* also prevent making it active on mouse selection */
1138 else if (BASE_SELECTABLE(v3d, basact)) {
1143 deselectall_except(scene, basact);
1144 ED_base_object_select(basact, BA_SELECT);
1147 // XXX select_all_from_groups(basact);
1150 if(basact->flag & SELECT) {
1151 if(basact==oldbasact)
1152 ED_base_object_select(basact, BA_DESELECT);
1154 else ED_base_object_select(basact, BA_SELECT);
1157 if(oldbasact != basact) {
1158 ED_base_object_activate(C, basact); /* adds notifier */
1161 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1166 /* ******************** border and circle ************************************** */
1169 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1172 float v1[2], v2[2], v3[2];
1174 /* check points in circle itself */
1175 if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1176 if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1186 if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1191 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1193 struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1195 if (BLI_in_rcti(data->rect, x, y)) {
1197 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1199 if (G.f & G_HIDDENHANDLES) {
1200 /* can only be beztindex==0 here since handles are hidden */
1201 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1204 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1205 } else if (beztindex==1) {
1206 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1208 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1214 static void do_nurbs_box_select(ViewContext *vc, rcti *rect, int select)
1216 struct { ViewContext vc; rcti *rect; int select; } data;
1220 data.select = select;
1222 nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data);
1225 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1227 struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1229 if (BLI_in_rcti(data->rect, x, y)) {
1230 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1233 static void do_lattice_box_select(ViewContext *vc, rcti *rect, int select)
1235 struct { ViewContext vc; rcti *rect; int select, pass, done; } data;
1239 data.select = select;
1241 lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data);
1244 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1246 struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1248 if (BLI_in_rcti(data->rect, x, y)) {
1249 eve->f = data->select?(eve->f|1):(eve->f&~1);
1252 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1254 struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1256 if(EM_check_backbuf(em_solidoffs+index)) {
1257 if (data->pass==0) {
1258 if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1259 EM_select_edge(eed, data->select);
1263 if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1264 EM_select_edge(eed, data->select);
1269 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1271 struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1273 if (BLI_in_rcti(data->rect, x, y)) {
1274 EM_select_face_fgon(data->vc.em, efa, data->select);
1277 static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select)
1279 struct { ViewContext vc; rcti *rect; short select, pass, done; } data;
1284 data.select = select;
1288 bbsel= EM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1290 if(vc->scene->selectmode & SCE_SELECT_VERTEX) {
1292 EM_backbuf_checkAndSelectVerts(vc->em, select);
1294 mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1);
1297 if(vc->scene->selectmode & SCE_SELECT_EDGE) {
1298 /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1301 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1305 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1309 if(vc->scene->selectmode & SCE_SELECT_FACE) {
1311 EM_backbuf_checkAndSelectFaces(vc->em, select);
1313 mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data);
1319 EM_selectmode_flush(vc->em);
1322 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
1325 Scene *scene= CTX_data_scene(C);
1326 ScrArea *sa= CTX_wm_area(C);
1327 View3D *v3d= sa->spacedata.first;
1328 Object *obedit= CTX_data_edit_object(C);
1332 unsigned int buffer[4*MAXPICKBUF];
1336 view3d_operator_needs_opengl(C);
1338 /* setup view context for argument to callbacks */
1339 view3d_set_viewcontext(C, &vc);
1341 val= RNA_int_get(op->ptr, "event_type");
1342 rect.xmin= RNA_int_get(op->ptr, "xmin");
1343 rect.ymin= RNA_int_get(op->ptr, "ymin");
1344 rect.xmax= RNA_int_get(op->ptr, "xmax");
1345 rect.ymax= RNA_int_get(op->ptr, "ymax");
1347 if(obedit==NULL && (FACESEL_PAINT_TEST)) {
1348 // XXX face_borderselect();
1349 return OPERATOR_FINISHED;
1351 else if(obedit==NULL && (G.f & G_PARTICLEEDIT)) {
1352 return PE_border_select(C, &rect, (val==LEFTMOUSE));
1356 if(obedit->type==OB_MESH) {
1357 Mesh *me= obedit->data;
1358 vc.em= me->edit_mesh;
1359 do_mesh_box_select(&vc, &rect, (val==LEFTMOUSE));
1360 // if (EM_texFaceCheck())
1361 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1364 else if(ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1365 do_nurbs_box_select(&vc, &rect, val==LEFTMOUSE);
1367 else if(obedit->type==OB_MBALL) {
1368 hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1370 ml= NULL; // XXX editelems.first;
1373 for(a=0; a<hits; a++) {
1374 if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1375 ml->flag |= MB_SCALE_RAD;
1376 if(val==LEFTMOUSE) ml->flag |= SELECT;
1377 else ml->flag &= ~SELECT;
1380 if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1381 ml->flag &= ~MB_SCALE_RAD;
1382 if(val==LEFTMOUSE) ml->flag |= SELECT;
1383 else ml->flag &= ~SELECT;
1390 else if(obedit->type==OB_ARMATURE) {
1391 bArmature *arm= obedit->data;
1394 /* clear flag we use to detect point was affected */
1395 for(ebone= arm->edbo->first; ebone; ebone= ebone->next)
1396 ebone->flag &= ~BONE_DONE;
1398 hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1400 /* first we only check points inside the border */
1401 for (a=0; a<hits; a++){
1402 index = buffer[(4*a)+3];
1404 ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1405 if (index & BONESEL_TIP) {
1406 ebone->flag |= BONE_DONE;
1407 if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
1408 else ebone->flag &= ~BONE_TIPSEL;
1411 if (index & BONESEL_ROOT) {
1412 ebone->flag |= BONE_DONE;
1413 if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
1414 else ebone->flag &= ~BONE_ROOTSEL;
1419 /* now we have to flush tag from parents... */
1420 for(ebone= arm->edbo->first; ebone; ebone= ebone->next) {
1421 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1422 if(ebone->parent->flag & BONE_DONE)
1423 ebone->flag |= BONE_DONE;
1427 /* only select/deselect entire bones when no points where in the rect */
1428 for (a=0; a<hits; a++){
1429 index = buffer[(4*a)+3];
1431 ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1432 if (index & BONESEL_BONE) {
1433 if(!(ebone->flag & BONE_DONE)) {
1435 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1437 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1444 else if(obedit->type==OB_LATTICE) {
1445 do_lattice_box_select(&vc, &rect, val==LEFTMOUSE);
1448 else { /* no editmode, unified for bones and objects */
1451 unsigned int *vbuffer=NULL; /* selection buffer */
1452 unsigned int *col; /* color in buffer */
1453 short selecting = 0;
1455 int totobj= MAXPICKBUF; // XXX solve later
1457 if((ob) && (ob->flag & OB_POSEMODE))
1465 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1466 vbuffer = MEM_mallocN(4 * (totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1467 hits= view3d_opengl_select(&vc, vbuffer, 4*(totobj+MAXPICKBUF), &rect);
1469 LOGIC NOTES (theeth):
1470 The buffer and ListBase have the same relative order, which makes the selection
1471 very simple. Loop through both data sets at the same time, if the color
1472 is the same as the object, we have a hit and can move to the next color
1473 and object pair, if not, just move to the next object,
1474 keeping the same color until we have a hit.
1476 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1477 does it incorrectly.
1480 if (hits>0) { /* no need to loop if there's no hit */
1484 while(base && hits) {
1485 Base *next = base->next;
1486 if(base->lay & v3d->lay) {
1487 while (base->selcol == (*col & 0xFFFF)) { /* we got an object */
1489 if(*col & 0xFFFF0000) { /* we got a bone */
1490 bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1493 bone->flag |= BONE_SELECTED;
1494 // XXX select_actionchannel_by_name(base->object->action, bone->name, 1);
1497 bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1498 // XXX select_actionchannel_by_name(base->object->action, bone->name, 0);
1502 else if(!bone_only) {
1504 ED_base_object_select(base, BA_SELECT);
1506 ED_base_object_select(base, BA_DESELECT);
1509 col+=4; /* next color */
1518 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1523 return OPERATOR_FINISHED;
1527 /* *****************Selection Operators******************* */
1528 static EnumPropertyItem prop_select_types[] = {
1529 {0, "EXCLUSIVE", "Exclusive", ""},
1530 {1, "EXTEND", "Extend", ""},
1531 {0, NULL, NULL, NULL}
1534 /* ****** Border Select ****** */
1535 void VIEW3D_OT_borderselect(wmOperatorType *ot)
1538 ot->name= "Border Select";
1539 ot->idname= "VIEW3D_OT_borderselect";
1542 ot->invoke= WM_border_select_invoke;
1543 ot->exec= view3d_borderselect_exec;
1544 ot->modal= WM_border_select_modal;
1546 ot->poll= ED_operator_view3d_active;
1549 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1552 RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1553 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1554 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1555 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1556 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1558 RNA_def_enum(ot->srna, "type", prop_select_types, 0, "Type", "");
1561 /* ****** Mouse Select ****** */
1564 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1566 Object *obedit= CTX_data_edit_object(C);
1567 short extend= RNA_enum_is_equal(op->ptr, "type", "EXTEND");
1569 view3d_operator_needs_opengl(C);
1572 if(obedit->type==OB_MESH)
1573 mouse_mesh(C, event->mval, extend);
1574 else if(obedit->type==OB_ARMATURE)
1575 mouse_armature(C, event->mval, extend);
1576 else if(obedit->type==OB_LATTICE)
1577 mouse_lattice(C, event->mval, extend);
1578 else if(ELEM(obedit->type, OB_CURVE, OB_SURF))
1579 mouse_nurb(C, event->mval, extend);
1582 else if(G.f & G_PARTICLEEDIT)
1583 PE_mouse_particles(C, event->mval, extend);
1585 mouse_select(C, event->mval, extend, 0);
1587 /* allowing tweaks */
1588 return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED;
1591 void VIEW3D_OT_select(wmOperatorType *ot)
1594 ot->name= "Activate/Select";
1595 ot->idname= "VIEW3D_OT_select";
1598 ot->invoke= view3d_select_invoke;
1599 ot->poll= ED_operator_view3d_active;
1602 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1605 RNA_def_enum(ot->srna, "type", prop_select_types, 0, "Type", "");
1609 /* -------------------- circle select --------------------------------------------- */
1611 static void mesh_circle_doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1613 struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1614 int mx = x - data->mval[0], my = y - data->mval[1];
1615 float r = sqrt(mx*mx + my*my);
1617 if (r<=data->radius) {
1618 eve->f = data->select?(eve->f|1):(eve->f&~1);
1621 static void mesh_circle_doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1623 struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1625 if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1626 EM_select_edge(eed, data->select);
1629 static void mesh_circle_doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1631 struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1632 int mx = x - data->mval[0], my = y - data->mval[1];
1633 float r = sqrt(mx*mx + my*my);
1635 if (r<=data->radius) {
1636 EM_select_face_fgon(data->vc->em, efa, data->select);
1640 static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1644 if(vc->obedit==NULL && (FACESEL_PAINT_TEST)) {
1645 Object *ob= vc->obact;
1646 Mesh *me = ob?ob->data:NULL;
1649 em_vertoffs= me->totface+1; /* max index array */
1651 bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1652 EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1655 // XXX object_tface_flags_changed(OBACT, 0);
1659 struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1661 bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1662 vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
1664 data.select = selecting;
1665 data.mval[0] = mval[0];
1666 data.mval[1] = mval[1];
1669 if(vc->scene->selectmode & SCE_SELECT_VERTEX) {
1671 EM_backbuf_checkAndSelectVerts(vc->em, selecting==LEFTMOUSE);
1673 mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, 1);
1677 if(vc->scene->selectmode & SCE_SELECT_EDGE) {
1679 EM_backbuf_checkAndSelectEdges(vc->em, selecting==LEFTMOUSE);
1681 mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, 0);
1685 if(vc->scene->selectmode & SCE_SELECT_FACE) {
1687 EM_backbuf_checkAndSelectFaces(vc->em, selecting==LEFTMOUSE);
1689 mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data);
1694 EM_selectmode_flush(vc->em);
1699 static void nurbscurve_circle_doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1701 struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1702 int mx = x - data->mval[0], my = y - data->mval[1];
1703 float r = sqrt(mx*mx + my*my);
1705 if (r<=data->radius) {
1707 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1710 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1711 } else if (beztindex==1) {
1712 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1714 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1719 static void nurbscurve_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1721 struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1723 /* set vc-> edit data */
1725 data.select = selecting;
1726 data.mval[0] = mval[0];
1727 data.mval[1] = mval[1];
1730 nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data);
1734 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, int x, int y)
1736 struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1737 int mx = x - data->mval[0], my = y - data->mval[1];
1738 float r = sqrt(mx*mx + my*my);
1740 if (r<=data->radius) {
1741 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1744 static void lattice_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1746 struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1748 /* set vc-> edit data */
1750 data.select = selecting;
1751 data.mval[0] = mval[0];
1752 data.mval[1] = mval[1];
1755 lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data);
1758 /** Callbacks for circle selection in Editmode */
1760 static void obedit_circle_select(ViewContext *vc, short selecting, short *mval, float rad)
1762 switch(vc->obedit->type) {
1764 mesh_circle_select(vc, selecting, mval, rad);
1768 nurbscurve_circle_select(vc, selecting, mval, rad);
1771 lattice_circle_select(vc, selecting, mval, rad);
1778 /* not a real operator, only for circle test */
1779 static int view3d_circle_select_exec(bContext *C, wmOperator *op)
1781 ScrArea *sa= CTX_wm_area(C);
1782 ARegion *ar= CTX_wm_region(C);
1783 Scene *scene= CTX_data_scene(C);
1784 View3D *v3d= sa->spacedata.first;
1785 int x= RNA_int_get(op->ptr, "x");
1786 int y= RNA_int_get(op->ptr, "y");
1787 int radius= RNA_int_get(op->ptr, "radius");
1789 if(CTX_data_edit_object(C) || (G.f & G_PARTICLEEDIT)) {
1791 short mval[2], selecting;
1793 view3d_operator_needs_opengl(C);
1795 view3d_set_viewcontext(C, &vc);
1798 selecting= LEFTMOUSE==RNA_int_get(op->ptr, "event_type"); // XXX solve
1800 if(CTX_data_edit_object(C))
1801 obedit_circle_select(&vc, selecting, mval, (float)radius);
1803 return PE_circle_select(C, selecting, mval, (float)radius);
1808 for(base= FIRSTBASE; base; base= base->next) {
1809 if(base->lay & v3d->lay) {
1810 project_short(ar, base->object->obmat[3], &base->sx);
1811 if(base->sx!=IS_CLIPPED) {
1814 if( dx*dx + dy*dy < radius*radius)
1815 ED_base_object_select(base, BA_SELECT);
1820 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1823 return OPERATOR_FINISHED;
1826 void VIEW3D_OT_circle_select(wmOperatorType *ot)
1828 ot->name= "Circle Select";
1829 ot->idname= "VIEW3D_OT_circle_select";
1831 ot->invoke= WM_gesture_circle_invoke;
1832 ot->modal= WM_gesture_circle_modal;
1833 ot->exec= view3d_circle_select_exec;
1834 ot->poll= ED_operator_view3d_active;
1837 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1839 RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
1840 RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
1841 RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
1842 RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);