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"
80 #include "ED_object.h"
81 #include "ED_screen.h"
84 #include "UI_interface.h"
85 #include "UI_resources.h"
86 #include "UI_view2d.h"
88 #include "PIL_time.h" /* smoothview */
90 #include "view3d_intern.h" // own include
93 void view3d_set_viewcontext(bContext *C, ViewContext *vc)
95 memset(vc, 0, sizeof(ViewContext));
96 vc->ar= CTX_wm_region(C);
97 vc->scene= CTX_data_scene(C);
98 vc->v3d= CTX_wm_view3d(C);
99 vc->obact= CTX_data_active_object(C);
100 vc->obedit= CTX_data_edit_object(C);
103 /* ********************** view3d_select: selection manipulations ********************* */
105 /* XXX to solve *************** */
106 static void BIF_undo_push() {}
107 /* XXX end ********************* */
109 /* local prototypes */
111 void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select)
114 int index= em_wireoffs;
116 for(eve= em->verts.first; eve; eve= eve->next, index++) {
118 if(EM_check_backbuf(index)) {
119 eve->f = select?(eve->f|1):(eve->f&~1);
125 void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select)
128 int index= em_solidoffs;
130 for(eed= em->edges.first; eed; eed= eed->next, index++) {
132 if(EM_check_backbuf(index)) {
133 EM_select_edge(eed, select);
139 void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select)
144 for(efa= em->faces.first; efa; efa= efa->next, index++) {
146 if(EM_check_backbuf(index)) {
147 EM_select_face_fgon(em, efa, select);
153 void EM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
155 MFace *mface = me->mface;
159 for(a=1; a<=me->totface; a++, mface++) {
160 if(EM_check_backbuf(a)) {
161 mface->flag = select?(mface->flag|ME_FACE_SEL):(mface->flag&~ME_FACE_SEL);
167 void arrows_move_cursor(unsigned short event)
174 if(event==UPARROWKEY) {
175 warp_pointer(mval[0], mval[1]+1);
176 } else if(event==DOWNARROWKEY) {
177 warp_pointer(mval[0], mval[1]-1);
178 } else if(event==LEFTARROWKEY) {
179 warp_pointer(mval[0]-1, mval[1]);
180 } else if(event==RIGHTARROWKEY) {
181 warp_pointer(mval[0]+1, mval[1]);
187 /* *********************** GESTURE AND LASSO ******************* */
189 /* helper also for borderselect */
190 static int edge_fully_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
192 return BLI_in_rcti(rect, x1, y1) && BLI_in_rcti(rect, x2, y2);
195 static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
199 /* check points in rect */
200 if(edge_fully_inside_rect(rect, x1, y1, x2, y2)) return 1;
202 /* check points completely out rect */
203 if(x1<rect->xmin && x2<rect->xmin) return 0;
204 if(x1>rect->xmax && x2>rect->xmax) return 0;
205 if(y1<rect->ymin && y2<rect->ymin) return 0;
206 if(y1>rect->ymax && y2>rect->ymax) return 0;
208 /* simple check lines intersecting. */
209 d1= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymin );
210 d2= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymax );
211 d3= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymax );
212 d4= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymin );
214 if(d1<0 && d2<0 && d3<0 && d4<0) return 0;
215 if(d1>0 && d2>0 && d3>0 && d4>0) return 0;
221 #define MOVES_GESTURE 50
222 #define MOVES_LASSO 500
224 int lasso_inside(short mcords[][2], short moves, short sx, short sy)
226 /* we do the angle rule, define that all added angles should be about zero or 2*PI */
227 float angletot=0.0, len, dot, ang, cross, fp1[2], fp2[2];
238 fp1[0]= (float)(p1[0]-sx);
239 fp1[1]= (float)(p1[1]-sy);
240 len= sqrt(fp1[0]*fp1[0] + fp1[1]*fp1[1]);
244 for(a=0; a<moves; a++) {
246 fp2[0]= (float)(p2[0]-sx);
247 fp2[1]= (float)(p2[1]-sy);
248 len= sqrt(fp2[0]*fp2[0] + fp2[1]*fp2[1]);
252 /* dot and angle and cross */
253 dot= fp1[0]*fp2[0] + fp1[1]*fp2[1];
254 ang= fabs(saacos(dot));
256 cross= (float)((p1[1]-p2[1])*(p1[0]-sx) + (p2[0]-p1[0])*(p1[1]-sy));
258 if(cross<0.0) angletot-= ang;
262 fp1[0]= fp2[0]; fp1[1]= fp2[1];
267 if( fabs(angletot) > 4.0 ) return 1;
271 /* edge version for lasso select. we assume boundbox check was done */
272 int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1)
277 if(x0==IS_CLIPPED || x1==IS_CLIPPED)
280 v1[0] = x0, v1[1] = y0;
281 v2[0] = x1, v2[1] = y1;
283 /* check points in lasso */
284 if(lasso_inside(mcords, moves, v1[0], v1[1])) return 1;
285 if(lasso_inside(mcords, moves, v2[0], v2[1])) return 1;
287 /* no points in lasso, so we have to intersect with lasso edge */
289 if( IsectLL2Ds(mcords[0], mcords[moves-1], v1, v2) > 0) return 1;
290 for(a=0; a<moves-1; a++) {
291 if( IsectLL2Ds(mcords[a], mcords[a+1], v1, v2) > 0) return 1;
298 /* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN)
299 and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK
301 static void do_lasso_select_pose(ViewContext *vc, short mcords[][2], short moves, short select)
303 Object *ob= vc->obact;
306 short sco1[2], sco2[2];
308 if(ob->type!=OB_ARMATURE || ob->pose==NULL) return;
310 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
311 VECCOPY(vec, pchan->pose_head);
312 Mat4MulVecfl(ob->obmat, vec);
313 project_short(vc->ar, vc->v3d, vec, sco1);
314 VECCOPY(vec, pchan->pose_tail);
315 Mat4MulVecfl(ob->obmat, vec);
316 project_short(vc->ar, vc->v3d, vec, sco2);
318 if(lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
319 if(select) pchan->bone->flag |= BONE_SELECTED;
320 else pchan->bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
326 static void do_lasso_select_objects(ViewContext *vc, short mcords[][2], short moves, short select)
330 for(base= vc->scene->base.first; base; base= base->next) {
331 if(base->lay & vc->v3d->lay) {
332 project_short(vc->ar, vc->v3d, base->object->obmat[3], &base->sx);
333 if(lasso_inside(mcords, moves, base->sx, base->sy)) {
335 if(select) ED_base_object_select(base, BA_SELECT);
336 else ED_base_object_select(base, BA_DESELECT);
337 base->object->flag= base->flag;
339 if(base->object->flag & OB_POSEMODE) {
340 do_lasso_select_pose(vc, mcords, moves, select);
346 void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
350 rect->xmin= rect->xmax= mcords[0][0];
351 rect->ymin= rect->ymax= mcords[0][1];
353 for(a=1; a<moves; a++) {
354 if(mcords[a][0]<rect->xmin) rect->xmin= mcords[a][0];
355 else if(mcords[a][0]>rect->xmax) rect->xmax= mcords[a][0];
356 if(mcords[a][1]<rect->ymin) rect->ymin= mcords[a][1];
357 else if(mcords[a][1]>rect->ymax) rect->ymax= mcords[a][1];
361 static void do_lasso_select_mesh__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
363 struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
365 if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
366 eve->f = data->select?(eve->f|1):(eve->f&~1);
369 static void do_lasso_select_mesh__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
371 struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
373 if (EM_check_backbuf(em_solidoffs+index)) {
375 if ( edge_fully_inside_rect(data->rect, x0, y0, x1, y1) &&
376 lasso_inside(data->mcords, data->moves, x0, y0) &&
377 lasso_inside(data->mcords, data->moves, x1, y1)) {
378 EM_select_edge(eed, data->select);
382 if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) {
383 EM_select_edge(eed, data->select);
388 static void do_lasso_select_mesh__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
390 struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
392 if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
393 EM_select_face_fgon(data->vc.em, efa, data->select);
397 static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves, short select)
399 struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } data;
403 lasso_select_boundbox(&rect, mcords, moves);
406 vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
410 data.mcords = mcords;
412 data.select = select;
416 bbsel= EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
418 if(vc->scene->selectmode & SCE_SELECT_VERTEX) {
420 EM_backbuf_checkAndSelectVerts(vc->em, select);
422 mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, 1);
425 if(vc->scene->selectmode & SCE_SELECT_EDGE) {
426 /* Does both bbsel and non-bbsel versions (need screen cos for both) */
429 mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0);
433 mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0);
437 if(vc->scene->selectmode & SCE_SELECT_FACE) {
439 EM_backbuf_checkAndSelectFaces(vc->em, select);
441 mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data);
446 EM_selectmode_flush(vc->em);
450 /* this is an exception in that its the only lasso that dosnt use the 3d view (uses space image view) */
451 static void do_lasso_select_mesh_uv(short mcords[][2], short moves, short select)
455 int screenUV[2], nverts, i, ok = 1;
458 lasso_select_boundbox(&rect, mcords, moves);
460 if (draw_uvs_face_check()) { /* Face Center Sel */
463 for (efa= em->faces.first; efa; efa= efa->next) {
464 /* assume not touched */
466 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
467 if ((select) != (simaFaceSel_Check(efa, tf))) {
468 uv_center(tf->uv, cent, (void *)efa->v4);
469 uvco_to_areaco_noclip(cent, screenUV);
470 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
475 /* (de)selects all tagged faces and deals with sticky modes */
477 uvface_setsel__internal(select);
479 } else { /* Vert Sel*/
480 for (efa= em->faces.first; efa; efa= efa->next) {
481 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
482 if (simaFaceDraw_Check(efa, tf)) {
483 nverts= efa->v4? 4: 3;
484 for(i=0; i<nverts; i++) {
485 if ((select) != (simaUVSel_Check(efa, tf, i))) {
486 uvco_to_areaco_noclip(tf->uv[i], screenUV);
487 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
489 simaUVSel_Set(efa, tf, i);
491 simaUVSel_UnSet(efa, tf, i);
499 if (ok && G.sima->flag & SI_SYNC_UVSEL) {
500 if (select) EM_select_flush(vc->em);
501 else EM_deselect_flush(vc->em);
506 static void do_lasso_select_curve__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
508 struct { short (*mcords)[2]; short moves; short select; } *data = userData;
510 if (lasso_inside(data->mcords, data->moves, x, y)) {
512 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
514 if (G.f & G_HIDDENHANDLES) {
515 /* can only be beztindex==0 here since handles are hidden */
516 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
519 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
520 } else if (beztindex==1) {
521 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
523 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
530 static void do_lasso_select_curve(ViewContext *vc, short mcords[][2], short moves, short select)
532 struct { short (*mcords)[2]; short moves; short select; } data;
534 /* set vc->editnurb */
535 data.mcords = mcords;
537 data.select = select;
539 nurbs_foreachScreenVert(vc, do_lasso_select_curve__doSelect, &data);
542 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, int y)
544 struct { short (*mcords)[2]; short moves; short select; } *data = userData;
546 if (lasso_inside(data->mcords, data->moves, x, y)) {
547 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
550 static void do_lasso_select_lattice(ViewContext *vc, short mcords[][2], short moves, short select)
552 struct { short (*mcords)[2]; short moves; short select; } data;
554 /* set editdata in vc */
555 data.mcords = mcords;
557 data.select = select;
559 lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data);
562 static void do_lasso_select_armature(ViewContext *vc, short mcords[][2], short moves, short select)
564 bArmature *arm= vc->obedit->data;
567 short sco1[2], sco2[2], didpoint;
569 /* set editdata in vc */
571 for (ebone= arm->edbo->first; ebone; ebone=ebone->next) {
573 VECCOPY(vec, ebone->head);
574 Mat4MulVecfl(vc->obedit->obmat, vec);
575 project_short(vc->ar, vc->v3d, vec, sco1);
576 VECCOPY(vec, ebone->tail);
577 Mat4MulVecfl(vc->obedit->obmat, vec);
578 project_short(vc->ar, vc->v3d, vec, sco2);
581 if(lasso_inside(mcords, moves, sco1[0], sco1[1])) {
582 if(select) ebone->flag |= BONE_ROOTSEL;
583 else ebone->flag &= ~BONE_ROOTSEL;
586 if(lasso_inside(mcords, moves, sco2[0], sco2[1])) {
587 if(select) ebone->flag |= BONE_TIPSEL;
588 else ebone->flag &= ~BONE_TIPSEL;
591 /* if one of points selected, we skip the bone itself */
592 if(didpoint==0 && lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
593 if(select) ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
594 else ebone->flag &= ~(BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
597 // XXX countall(); /* abused for flushing selection!!!! */
600 static void do_lasso_select_facemode(ViewContext *vc, short mcords[][2], short moves, short select)
602 Object *ob= vc->obact;
603 Mesh *me= ob?ob->data:NULL;
606 if(me==NULL || me->mtface==NULL) return;
607 if(me->totface==0) return;
609 em_vertoffs= me->totface+1; /* max index array */
611 lasso_select_boundbox(&rect, mcords, moves);
612 EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
614 EM_backbuf_checkAndSelectTFaces(me, select);
618 // XXX object_tface_flags_changed(ob, 0);
622 static void do_lasso_select_node(short mcords[][2], short moves, short select)
624 SpaceNode *snode = sa->spacedata.first;
631 lasso_select_boundbox(&rect, mcords, moves);
633 /* store selection in temp test flag */
634 for(node= snode->edittree->nodes.first; node; node= node->next) {
636 node_centf[0] = (node->totr.xmin+node->totr.xmax)/2;
637 node_centf[1] = (node->totr.ymin+node->totr.ymax)/2;
639 ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
640 if (BLI_in_rcti(&rect, node_cent[0], node_cent[1]) && lasso_inside(mcords, moves, node_cent[0], node_cent[1])) {
642 node->flag |= SELECT;
644 node->flag &= ~SELECT;
648 BIF_undo_push("Lasso select nodes");
652 void view3d_lasso_select(ViewContext *vc, short mcords[][2], short moves, short select)
654 if(vc->obedit==NULL) {
655 if(FACESEL_PAINT_TEST)
656 do_lasso_select_facemode(vc, mcords, moves, select);
657 else if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))
659 // XX else if(G.f & G_PARTICLEEDIT)
660 // PE_do_lasso_select(mcords, moves, select);
662 do_lasso_select_objects(vc, mcords, moves, select);
664 else if(vc->obedit->type==OB_MESH) {
665 do_lasso_select_mesh(vc, mcords, moves, select);
666 } else if(vc->obedit->type==OB_CURVE || vc->obedit->type==OB_SURF)
667 do_lasso_select_curve(vc, mcords, moves, select);
668 else if(vc->obedit->type==OB_LATTICE)
669 do_lasso_select_lattice(vc, mcords, moves, select);
670 else if(vc->obedit->type==OB_ARMATURE)
671 do_lasso_select_armature(vc, mcords, moves, select);
673 BIF_undo_push("Lasso select");
677 static EnumPropertyItem lasso_select_types[] = {
678 {0, "SELECT", "Select", ""},
679 {1, "DESELECT", "Deselect", ""},
680 {0, NULL, NULL, NULL}
684 /* lasso operator gives properties, but since old code works
685 with short array we convert */
686 static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
690 short mcords[1024][2];
692 RNA_BEGIN(op->ptr, itemptr, "path") {
695 RNA_float_get_array(&itemptr, "loc", loc);
696 mcords[i][0]= (short)loc[0];
697 mcords[i][1]= (short)loc[1];
703 /* setup view context for argument to callbacks */
704 view3d_set_viewcontext(C, &vc);
706 select= RNA_enum_is_equal(op->ptr, "type", "SELECT");
707 view3d_lasso_select(&vc, mcords, i, select);
709 return OPERATOR_FINISHED;
712 void VIEW3D_OT_lasso_select(wmOperatorType *ot)
714 ot->name= "Lasso Select";
715 ot->idname= "VIEW3D_OT_lasso_select";
717 ot->invoke= WM_gesture_lasso_invoke;
718 ot->modal= WM_gesture_lasso_modal;
719 ot->exec= view3d_lasso_select_exec;
720 ot->poll= WM_operator_winactive;
722 RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
723 RNA_def_enum(ot->srna, "type", lasso_select_types, 0, "Type", "");
727 /* ************************************************* */
730 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
731 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
734 unsigned int *bufmin,*bufmax;
735 int a,b,rc,tel,aantal,dirvec[4][2],maxob;
736 unsigned int retval=0;
739 if(base==0) return 0;
755 bufmax= buf+ size*size;
756 buf+= aantal*size+ aantal;
758 for(tel=1;tel<=size;tel++) {
763 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
764 if( *buf==dontdo ) retval= dontdo; /* if only color dontdo is available, still return dontdo */
766 buf+= (dirvec[rc][0]+dirvec[rc][1]);
768 if(buf<bufmin || buf>=bufmax) return retval;
778 /* ************************** mouse select ************************* */
781 /* The max number of menu items in an object select menu */
782 #define SEL_MENU_SIZE 22
784 static void deselectall_except(Scene *scene, Base *b) /* deselect all except b */
788 for(base= FIRSTBASE; base; base= base->next) {
789 if (base->flag & SELECT) {
791 ED_base_object_select(base, BA_DESELECT);
797 static Base *mouse_select_menu(ViewContext *vc, unsigned int *buffer, int hits, short *mval)
799 Scene *scene= vc->scene;
800 View3D *v3d= vc->v3d;
801 Base *baseList[SEL_MENU_SIZE]={NULL}; /*baseList is used to store all possible bases to bring up a menu */
804 char menuText[20 + SEL_MENU_SIZE*32] = "Select Object%t"; /* max ob name = 22 */
807 for(base=FIRSTBASE; base; base= base->next) {
808 if (BASE_SELECTABLE(v3d, base)) {
809 baseList[baseCount] = NULL;
811 /* two selection methods, the CTRL select uses max dist of 15 */
814 for(a=0; a<hits; a++) {
815 /* index was converted */
816 if(base->selcol==buffer[ (4 * a) + 3 ]) baseList[baseCount] = base;
822 project_short(vc->ar, vc->v3d, base->object->obmat[3], &base->sx);
824 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
825 if(temp<dist ) baseList[baseCount] = base;
828 if(baseList[baseCount]) {
829 if (baseCount < SEL_MENU_SIZE) {
830 baseList[baseCount] = base;
831 sprintf(str, "|%s %%x%d", base->object->id.name+2, baseCount+1); /* max ob name == 22 */
832 strcat(menuText, str);
839 if(baseCount<=1) return baseList[0];
841 baseCount = -1; // XXX = pupmenu(menuText);
843 if (baseCount != -1) { /* If nothing is selected then dont do anything */
844 return baseList[baseCount-1];
850 /* we want a select buffer with bones, if there are... */
851 /* so check three selection levels and compare */
852 static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, short *mval)
856 short a, hits15, hits9=0, hits5=0;
857 short has_bones15=0, has_bones9=0, has_bones5=0;
859 BLI_init_rcti(&rect, mval[0]-14, mval[0]+14, mval[1]-14, mval[1]+14);
860 hits15= view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
862 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
865 BLI_init_rcti(&rect, mval[0]-9, mval[0]+9, mval[1]-9, mval[1]+9);
866 hits9= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
868 for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
871 BLI_init_rcti(&rect, mval[0]-5, mval[0]+5, mval[1]-5, mval[1]+5);
872 hits5= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
874 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
879 offs= 4*hits15 + 4*hits9;
880 memcpy(buffer, buffer+offs, 4*offs);
885 memcpy(buffer, buffer+offs, 4*offs);
893 offs= 4*hits15 + 4*hits9;
894 memcpy(buffer, buffer+offs, 4*offs);
899 memcpy(buffer, buffer+offs, 4*offs);
909 /* mval is region coords */
910 static void mouse_select(bContext *C, short *mval, short extend, short obcenter)
913 ARegion *ar= CTX_wm_region(C);
914 View3D *v3d= CTX_wm_view3d(C);
915 Scene *scene= CTX_data_scene(C);
916 Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
917 unsigned int buffer[4*MAXPICKBUF];
918 int temp, a, dist=100;
921 /* setup view context for argument to callbacks */
922 view3d_set_viewcontext(C, &vc);
924 /* always start list from basact in wire mode */
925 startbase= FIRSTBASE;
926 if(BASACT && BASACT->next) startbase= BASACT->next;
928 /* This block uses the control key to make the object selected by its center point rather then its contents */
929 /* XXX later on, in editmode do not activate */
930 if(vc.obedit==NULL && obcenter) {
932 /* note; shift+alt goes to group-flush-selecting */
935 basact= mouse_select_menu(&vc, NULL, 0, mval);
939 if (BASE_SELECTABLE(v3d, base)) {
940 project_short(ar, v3d, base->object->obmat[3], &base->sx);
942 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
943 if(base==BASACT) temp+=10;
952 if(base==0) base= FIRSTBASE;
953 if(base==startbase) break;
958 /* if objects have posemode set, the bones are in the same selection buffer */
960 hits= mixed_bones_object_selectbuffer(&vc, buffer, mval);
965 for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
967 /* note; shift+alt goes to group-flush-selecting */
968 if(has_bones==0 && 0)
969 basact= mouse_select_menu(&vc, buffer, hits, mval);
971 static short lastmval[2]={-100, -100};
974 /* define if we use solid nearest select or not */
975 if(v3d->drawtype>OB_WIRE) {
977 if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
978 if(!has_bones) /* hrms, if theres bones we always do nearest */
982 lastmval[0]= mval[0]; lastmval[1]= mval[1];
985 unsigned int min= 0xFFFFFFFF;
986 int selcol= 0, notcol=0;
990 /* we skip non-bone hits */
991 for(a=0; a<hits; a++) {
992 if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
994 selcol= buffer[4*a+3] & 0xFFFF;
999 /* only exclude active object when it is selected... */
1000 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol;
1002 for(a=0; a<hits; a++) {
1003 if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1005 selcol= buffer[4*a+3] & 0xFFFF;
1012 if(base->lay & v3d->lay) {
1013 if(base->selcol==selcol) break;
1017 if(base) basact= base;
1023 /* skip objects with select restriction, to prevent prematurely ending this loop
1024 * with an un-selectable choice */
1025 if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1027 if(base==NULL) base= FIRSTBASE;
1028 if(base==startbase) break;
1031 if(base->lay & v3d->lay) {
1032 for(a=0; a<hits; a++) {
1034 /* skip non-bone objects */
1035 if((buffer[4*a+3] & 0xFFFF0000)) {
1036 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1041 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1050 if(base==NULL) base= FIRSTBASE;
1051 if(base==startbase) break;
1056 if(has_bones && basact) {
1057 if(ED_do_pose_selectbuffer(scene, basact, buffer, hits, extend) ) { /* then bone is found */
1059 /* we make the armature selected:
1060 not-selected active object in posemode won't work well for tools */
1061 basact->flag|= SELECT;
1062 basact->object->flag= basact->flag;
1064 WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, basact->object);
1065 WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, basact->object);
1067 /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1068 if(G.f & G_WEIGHTPAINT) {
1069 /* prevent activating */
1074 /* prevent bone selecting to pass on to object selecting */
1081 /* so, do we have something selected? */
1085 /* only do select */
1086 deselectall_except(scene, basact);
1087 ED_base_object_select(basact, BA_SELECT);
1089 /* also prevent making it active on mouse selection */
1090 else if (BASE_SELECTABLE(v3d, basact)) {
1096 deselectall_except(scene, basact);
1097 ED_base_object_select(basact, BA_SELECT);
1100 // XXX select_all_from_groups(basact);
1103 if(basact->flag & SELECT) {
1104 if(basact==oldbasact)
1105 ED_base_object_select(basact, BA_DESELECT);
1107 else ED_base_object_select(basact, BA_SELECT);
1110 if(oldbasact != basact) {
1111 ED_base_object_activate(C, basact); /* adds notifier */
1114 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1121 /* ******************** border and circle ************************************** */
1124 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1127 float v1[2], v2[2], v3[2];
1129 /* check points in circle itself */
1130 if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1131 if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1141 if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1146 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1148 struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1150 if (BLI_in_rcti(data->rect, x, y)) {
1152 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1154 if (G.f & G_HIDDENHANDLES) {
1155 /* can only be beztindex==0 here since handles are hidden */
1156 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1159 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1160 } else if (beztindex==1) {
1161 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1163 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1169 static void do_nurbs_box_select(ViewContext *vc, rcti *rect, int select)
1171 struct { ViewContext vc; rcti *rect; int select; } data;
1175 data.select = select;
1177 nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data);
1180 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1182 struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1184 if (BLI_in_rcti(data->rect, x, y)) {
1185 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1188 static void do_lattice_box_select(ViewContext *vc, rcti *rect, int select)
1190 struct { ViewContext vc; rcti *rect; int select, pass, done; } data;
1194 data.select = select;
1196 lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data);
1199 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1201 struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1203 if (BLI_in_rcti(data->rect, x, y)) {
1204 eve->f = data->select?(eve->f|1):(eve->f&~1);
1207 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1209 struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1211 if(EM_check_backbuf(em_solidoffs+index)) {
1212 if (data->pass==0) {
1213 if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1214 EM_select_edge(eed, data->select);
1218 if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1219 EM_select_edge(eed, data->select);
1224 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1226 struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1228 if (BLI_in_rcti(data->rect, x, y)) {
1229 EM_select_face_fgon(data->vc.em, efa, data->select);
1232 static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select)
1234 struct { ViewContext vc; rcti *rect; short select, pass, done; } data;
1239 data.select = select;
1243 bbsel= EM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1245 if(vc->scene->selectmode & SCE_SELECT_VERTEX) {
1247 EM_backbuf_checkAndSelectVerts(vc->em, select);
1249 mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1);
1252 if(vc->scene->selectmode & SCE_SELECT_EDGE) {
1253 /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1256 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1260 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1264 if(vc->scene->selectmode & SCE_SELECT_FACE) {
1266 EM_backbuf_checkAndSelectFaces(vc->em, select);
1268 mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data);
1274 EM_selectmode_flush(vc->em);
1277 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
1280 Scene *scene= CTX_data_scene(C);
1281 ScrArea *sa= CTX_wm_area(C);
1282 View3D *v3d= sa->spacedata.first;
1283 Object *obedit= CTX_data_edit_object(C);
1287 unsigned int buffer[4*MAXPICKBUF];
1291 view3d_operator_needs_opengl(C);
1293 /* setup view context for argument to callbacks */
1294 view3d_set_viewcontext(C, &vc);
1296 val= RNA_int_get(op->ptr, "event_type");
1297 rect.xmin= RNA_int_get(op->ptr, "xmin");
1298 rect.ymin= RNA_int_get(op->ptr, "ymin");
1299 rect.xmax= RNA_int_get(op->ptr, "xmax");
1300 rect.ymax= RNA_int_get(op->ptr, "ymax");
1302 if(obedit==NULL && (FACESEL_PAINT_TEST)) {
1303 // XXX face_borderselect();
1304 return OPERATOR_FINISHED;
1306 else if(obedit==NULL && (G.f & G_PARTICLEEDIT)) {
1307 // XXX PE_borderselect();
1308 return OPERATOR_FINISHED;
1312 if(obedit->type==OB_MESH) {
1313 Mesh *me= obedit->data;
1314 vc.em= me->edit_mesh;
1315 do_mesh_box_select(&vc, &rect, (val==LEFTMOUSE));
1316 // if (EM_texFaceCheck())
1317 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1320 else if(ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1321 do_nurbs_box_select(&vc, &rect, val==LEFTMOUSE);
1322 // allqueue(REDRAWVIEW3D, 0);
1324 else if(obedit->type==OB_MBALL) {
1325 hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1327 ml= NULL; // XXX editelems.first;
1330 for(a=0; a<hits; a++) {
1331 if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1332 ml->flag |= MB_SCALE_RAD;
1333 if(val==LEFTMOUSE) ml->flag |= SELECT;
1334 else ml->flag &= ~SELECT;
1337 if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1338 ml->flag &= ~MB_SCALE_RAD;
1339 if(val==LEFTMOUSE) ml->flag |= SELECT;
1340 else ml->flag &= ~SELECT;
1347 else if(obedit->type==OB_ARMATURE) {
1348 bArmature *arm= obedit->data;
1351 /* clear flag we use to detect point was affected */
1352 for(ebone= arm->edbo->first; ebone; ebone= ebone->next)
1353 ebone->flag &= ~BONE_DONE;
1355 hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1357 /* first we only check points inside the border */
1358 for (a=0; a<hits; a++){
1359 index = buffer[(4*a)+3];
1361 ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1362 if (index & BONESEL_TIP) {
1363 ebone->flag |= BONE_DONE;
1364 if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
1365 else ebone->flag &= ~BONE_TIPSEL;
1368 if (index & BONESEL_ROOT) {
1369 ebone->flag |= BONE_DONE;
1370 if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
1371 else ebone->flag &= ~BONE_ROOTSEL;
1376 /* now we have to flush tag from parents... */
1377 for(ebone= arm->edbo->first; ebone; ebone= ebone->next) {
1378 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1379 if(ebone->parent->flag & BONE_DONE)
1380 ebone->flag |= BONE_DONE;
1384 /* only select/deselect entire bones when no points where in the rect */
1385 for (a=0; a<hits; a++){
1386 index = buffer[(4*a)+3];
1388 ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1389 if (index & BONESEL_BONE) {
1390 if(!(ebone->flag & BONE_DONE)) {
1392 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1394 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1401 else if(obedit->type==OB_LATTICE) {
1402 do_lattice_box_select(&vc, &rect, val==LEFTMOUSE);
1405 else { /* no editmode, unified for bones and objects */
1408 unsigned int *vbuffer=NULL; /* selection buffer */
1409 unsigned int *col; /* color in buffer */
1410 short selecting = 0;
1412 int totobj= MAXPICKBUF; // XXX solve later
1414 if((ob) && (ob->flag & OB_POSEMODE))
1422 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1423 vbuffer = MEM_mallocN(4 * (totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1424 hits= view3d_opengl_select(&vc, vbuffer, 4*(totobj+MAXPICKBUF), &rect);
1426 LOGIC NOTES (theeth):
1427 The buffer and ListBase have the same relative order, which makes the selection
1428 very simple. Loop through both data sets at the same time, if the color
1429 is the same as the object, we have a hit and can move to the next color
1430 and object pair, if not, just move to the next object,
1431 keeping the same color until we have a hit.
1433 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1434 does it incorrectly.
1437 if (hits>0) { /* no need to loop if there's no hit */
1441 while(base && hits) {
1442 Base *next = base->next;
1443 if(base->lay & v3d->lay) {
1444 while (base->selcol == (*col & 0xFFFF)) { /* we got an object */
1446 if(*col & 0xFFFF0000) { /* we got a bone */
1447 bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1450 bone->flag |= BONE_SELECTED;
1451 // XXX select_actionchannel_by_name(base->object->action, bone->name, 1);
1454 bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1455 // XXX select_actionchannel_by_name(base->object->action, bone->name, 0);
1459 else if(!bone_only) {
1461 ED_base_object_select(base, BA_SELECT);
1463 ED_base_object_select(base, BA_DESELECT);
1466 col+=4; /* next color */
1475 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1480 ED_undo_push(C,"Border Select");
1481 return OPERATOR_FINISHED;
1485 /* *****************Selection Operators******************* */
1486 static EnumPropertyItem prop_select_types[] = {
1487 {0, "EXCLUSIVE", "Exclusive", ""},
1488 {1, "EXTEND", "Extend", ""},
1489 {0, NULL, NULL, NULL}
1492 /* ****** Border Select ****** */
1493 void VIEW3D_OT_borderselect(wmOperatorType *ot)
1496 ot->name= "Border Select";
1497 ot->idname= "VIEW3D_OT_borderselect";
1500 ot->invoke= WM_border_select_invoke;
1501 ot->exec= view3d_borderselect_exec;
1502 ot->modal= WM_border_select_modal;
1504 ot->poll= ED_operator_view3d_active;
1507 RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1508 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1509 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1510 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1511 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1513 RNA_def_enum(ot->srna, "type", prop_select_types, 0, "Type", "");
1516 /* ****** Mouse Select ****** */
1519 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1521 ARegion *ar= CTX_wm_region(C);
1522 Object *obedit= CTX_data_edit_object(C);
1523 short extend= RNA_enum_is_equal(op->ptr, "type", "EXTEND");
1526 mval[0]= event->x - ar->winrct.xmin;
1527 mval[1]= event->y - ar->winrct.ymin;
1529 view3d_operator_needs_opengl(C);
1532 if(obedit->type==OB_MESH)
1533 mouse_mesh(C, mval, extend);
1534 else if(obedit->type==OB_ARMATURE)
1535 mouse_armature(C, mval, extend);
1536 else if(obedit->type==OB_LATTICE)
1537 mouse_lattice(C, mval, extend);
1538 else if(ELEM(obedit->type, OB_CURVE, OB_SURF))
1539 mouse_nurb(C, mval, extend);
1543 mouse_select(C, mval, extend, 0);
1545 ED_undo_push(C,"Mouse Select");
1546 /* allowing tweaks */
1547 return OPERATOR_PASS_THROUGH;
1550 void VIEW3D_OT_select(wmOperatorType *ot)
1553 ot->name= "Activate/Select";
1554 ot->idname= "VIEW3D_OT_select";
1557 ot->invoke= view3d_select_invoke;
1558 ot->poll= ED_operator_view3d_active;
1561 RNA_def_enum(ot->srna, "type", prop_select_types, 0, "Type", "");
1565 /* -------------------- circle select --------------------------------------------- */
1567 static void mesh_circle_doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1569 struct { short select, mval[2]; float radius; } *data = userData;
1570 int mx = x - data->mval[0], my = y - data->mval[1];
1571 float r = sqrt(mx*mx + my*my);
1573 if (r<=data->radius) {
1574 eve->f = data->select?(eve->f|1):(eve->f&~1);
1577 static void mesh_circle_doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1579 struct { short select, mval[2]; float radius; } *data = userData;
1581 if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1582 EM_select_edge(eed, data->select);
1585 static void mesh_circle_doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1587 struct { short select, mval[2]; float radius; } *data = userData;
1588 int mx = x - data->mval[0], my = y - data->mval[1];
1589 float r = sqrt(mx*mx + my*my);
1590 EditMesh *em= NULL; // XXX
1592 if (r<=data->radius) {
1593 EM_select_face_fgon(em, efa, data->select);
1597 static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1601 if(vc->obedit==NULL && (FACESEL_PAINT_TEST)) {
1602 Object *ob= vc->obact;
1603 Mesh *me = ob?ob->data:NULL;
1606 em_vertoffs= me->totface+1; /* max index array */
1608 bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1609 EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1612 // XXX object_tface_flags_changed(OBACT, 0);
1616 struct { short select, mval[2]; float radius; } data;
1618 bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1619 vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
1621 data.select = selecting;
1622 data.mval[0] = mval[0];
1623 data.mval[1] = mval[1];
1626 if(vc->scene->selectmode & SCE_SELECT_VERTEX) {
1628 EM_backbuf_checkAndSelectVerts(vc->em, selecting==LEFTMOUSE);
1630 mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, 1);
1634 if(vc->scene->selectmode & SCE_SELECT_EDGE) {
1636 EM_backbuf_checkAndSelectEdges(vc->em, selecting==LEFTMOUSE);
1638 mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, 0);
1642 if(vc->scene->selectmode & SCE_SELECT_FACE) {
1644 EM_backbuf_checkAndSelectFaces(vc->em, selecting==LEFTMOUSE);
1646 mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data);
1651 EM_selectmode_flush(vc->em);
1656 static void nurbscurve_circle_doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1658 struct { short select, mval[2]; float radius; } *data = userData;
1659 int mx = x - data->mval[0], my = y - data->mval[1];
1660 float r = sqrt(mx*mx + my*my);
1662 if (r<=data->radius) {
1664 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1667 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1668 } else if (beztindex==1) {
1669 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1671 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1676 static void nurbscurve_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1678 struct { short select, mval[2]; float radius; } data;
1680 /* set vc-> edit data */
1682 data.select = selecting;
1683 data.mval[0] = mval[0];
1684 data.mval[1] = mval[1];
1687 nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data);
1691 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, int x, int y)
1693 struct { short select, mval[2]; float radius; } *data = userData;
1694 int mx = x - data->mval[0], my = y - data->mval[1];
1695 float r = sqrt(mx*mx + my*my);
1697 if (r<=data->radius) {
1698 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1701 static void lattice_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1703 struct { short select, mval[2]; float radius; } data;
1705 /* set vc-> edit data */
1707 data.select = selecting;
1708 data.mval[0] = mval[0];
1709 data.mval[1] = mval[1];
1712 lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data);
1715 /** Callbacks for circle selection in Editmode */
1717 static void obedit_circle_select(ViewContext *vc, short selecting, short *mval, float rad)
1719 switch(vc->obedit->type) {
1721 mesh_circle_select(vc, selecting, mval, rad);
1725 nurbscurve_circle_select(vc, selecting, mval, rad);
1728 lattice_circle_select(vc, selecting, mval, rad);
1735 /* not a real operator, only for circle test */
1736 static int view3d_circle_select_exec(bContext *C, wmOperator *op)
1738 ScrArea *sa= CTX_wm_area(C);
1739 ARegion *ar= CTX_wm_region(C);
1740 Scene *scene= CTX_data_scene(C);
1741 View3D *v3d= sa->spacedata.first;
1742 int x= RNA_int_get(op->ptr, "x");
1743 int y= RNA_int_get(op->ptr, "y");
1744 int radius= RNA_int_get(op->ptr, "radius");
1746 if(CTX_data_edit_object(C)) {
1748 short mval[2], selecting;
1750 view3d_set_viewcontext(C, &vc);
1753 selecting= LEFTMOUSE==RNA_int_get(op->ptr, "event_type"); // XXX solve
1754 obedit_circle_select(&vc, selecting, mval, (float)radius);
1759 for(base= FIRSTBASE; base; base= base->next) {
1760 if(base->lay & v3d->lay) {
1761 project_short(ar, v3d, base->object->obmat[3], &base->sx);
1762 if(base->sx!=IS_CLIPPED) {
1765 if( dx*dx + dy*dy < radius*radius)
1766 ED_base_object_select(base, BA_SELECT);
1771 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1774 ED_undo_push(C,"Circle Select");
1775 return OPERATOR_FINISHED;
1778 void VIEW3D_OT_circle_select(wmOperatorType *ot)
1780 ot->name= "Circle Select";
1781 ot->idname= "VIEW3D_OT_circle_select";
1783 ot->invoke= WM_gesture_circle_invoke;
1784 ot->modal= WM_gesture_circle_modal;
1785 ot->exec= view3d_circle_select_exec;
1786 ot->poll= ED_operator_view3d_active;
1788 RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
1789 RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
1790 RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
1791 RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);