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"
70 #include "BIF_editarmature.h"
75 #include "RNA_access.h"
76 #include "RNA_define.h"
78 #include "ED_screen.h"
81 #include "UI_interface.h"
82 #include "UI_resources.h"
83 #include "UI_view2d.h"
85 #include "PIL_time.h" /* smoothview */
87 #include "view3d_intern.h" // own include
89 /* ********************** view3d_select: selection manipulations ********************* */
91 /* XXX to solve *************** */
92 unsigned int em_vertoffs=0, em_solidoffs=0, em_wireoffs=0;
93 int EM_check_backbuf() {return 0;}
94 void EM_select_edge() {}
95 void EM_select_face_fgon() {}
96 int EM_mask_init_backbuf_border() {return 0;}
97 void EM_free_backbuf() {}
98 void EM_selectmode_flush() {}
99 void EM_deselect_flush() {}
100 static void BIF_undo_push() {}
101 int EM_texFaceCheck() {return 0;}
102 int EM_init_backbuf_border() {return 0;}
103 int EM_init_backbuf_circle() {return 0;}
105 /* XXX end ********************* */
107 /* local prototypes */
109 void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select)
112 int index= em_wireoffs;
114 for(eve= em->verts.first; eve; eve= eve->next, index++) {
116 if(EM_check_backbuf(index)) {
117 eve->f = select?(eve->f|1):(eve->f&~1);
123 void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select)
126 int index= em_solidoffs;
128 for(eed= em->edges.first; eed; eed= eed->next, index++) {
130 if(EM_check_backbuf(index)) {
131 EM_select_edge(eed, select);
137 void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select)
142 for(efa= em->faces.first; efa; efa= efa->next, index++) {
144 if(EM_check_backbuf(index)) {
145 EM_select_face_fgon(efa, select);
151 void EM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
153 MFace *mface = me->mface;
157 for(a=1; a<=me->totface; a++, mface++) {
158 if(EM_check_backbuf(a)) {
159 mface->flag = select?(mface->flag|ME_FACE_SEL):(mface->flag&~ME_FACE_SEL);
165 void arrows_move_cursor(unsigned short event)
172 if(event==UPARROWKEY) {
173 warp_pointer(mval[0], mval[1]+1);
174 } else if(event==DOWNARROWKEY) {
175 warp_pointer(mval[0], mval[1]-1);
176 } else if(event==LEFTARROWKEY) {
177 warp_pointer(mval[0]-1, mval[1]);
178 } else if(event==RIGHTARROWKEY) {
179 warp_pointer(mval[0]+1, mval[1]);
184 /* simple API for object selection, rather than just using the flag
185 * this takes into account the 'restrict selection in 3d view' flag.
186 * deselect works always, the restriction just prevents selection */
187 void select_base_v3d(Base *base, short mode)
190 if (mode==BA_SELECT) {
191 if (!(base->object->restrictflag & OB_RESTRICT_SELECT))
192 if (mode==BA_SELECT) base->flag |= SELECT;
194 else if (mode==BA_DESELECT) {
195 base->flag &= ~SELECT;
197 base->object->flag= base->flag;
201 /* *********************** GESTURE AND LASSO ******************* */
203 /* helper also for borderselect */
204 static int edge_fully_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
206 return BLI_in_rcti(rect, x1, y1) && BLI_in_rcti(rect, x2, y2);
209 static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
213 /* check points in rect */
214 if(edge_fully_inside_rect(rect, x1, y1, x2, y2)) return 1;
216 /* check points completely out rect */
217 if(x1<rect->xmin && x2<rect->xmin) return 0;
218 if(x1>rect->xmax && x2>rect->xmax) return 0;
219 if(y1<rect->ymin && y2<rect->ymin) return 0;
220 if(y1>rect->ymax && y2>rect->ymax) return 0;
222 /* simple check lines intersecting. */
223 d1= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymin );
224 d2= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymax );
225 d3= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymax );
226 d4= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymin );
228 if(d1<0 && d2<0 && d3<0 && d4<0) return 0;
229 if(d1>0 && d2>0 && d3>0 && d4>0) return 0;
235 #define MOVES_GESTURE 50
236 #define MOVES_LASSO 500
238 int lasso_inside(short mcords[][2], short moves, short sx, short sy)
240 /* we do the angle rule, define that all added angles should be about zero or 2*PI */
241 float angletot=0.0, len, dot, ang, cross, fp1[2], fp2[2];
252 fp1[0]= (float)(p1[0]-sx);
253 fp1[1]= (float)(p1[1]-sy);
254 len= sqrt(fp1[0]*fp1[0] + fp1[1]*fp1[1]);
258 for(a=0; a<moves; a++) {
260 fp2[0]= (float)(p2[0]-sx);
261 fp2[1]= (float)(p2[1]-sy);
262 len= sqrt(fp2[0]*fp2[0] + fp2[1]*fp2[1]);
266 /* dot and angle and cross */
267 dot= fp1[0]*fp2[0] + fp1[1]*fp2[1];
268 ang= fabs(saacos(dot));
270 cross= (float)((p1[1]-p2[1])*(p1[0]-sx) + (p2[0]-p1[0])*(p1[1]-sy));
272 if(cross<0.0) angletot-= ang;
276 fp1[0]= fp2[0]; fp1[1]= fp2[1];
281 if( fabs(angletot) > 4.0 ) return 1;
285 /* edge version for lasso select. we assume boundbox check was done */
286 int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1)
291 if(x0==IS_CLIPPED || x1==IS_CLIPPED)
294 v1[0] = x0, v1[1] = y0;
295 v2[0] = x1, v2[1] = y1;
297 /* check points in lasso */
298 if(lasso_inside(mcords, moves, v1[0], v1[1])) return 1;
299 if(lasso_inside(mcords, moves, v2[0], v2[1])) return 1;
301 /* no points in lasso, so we have to intersect with lasso edge */
303 if( IsectLL2Ds(mcords[0], mcords[moves-1], v1, v2) > 0) return 1;
304 for(a=0; a<moves-1; a++) {
305 if( IsectLL2Ds(mcords[a], mcords[a+1], v1, v2) > 0) return 1;
312 /* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN)
313 and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK
315 static void do_lasso_select_pose(ARegion *ar, View3D *v3d, Object *ob, short mcords[][2], short moves, short select)
319 short sco1[2], sco2[2];
321 if(ob->type!=OB_ARMATURE || ob->pose==NULL) return;
323 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
324 VECCOPY(vec, pchan->pose_head);
325 Mat4MulVecfl(ob->obmat, vec);
326 project_short(ar, v3d, vec, sco1);
327 VECCOPY(vec, pchan->pose_tail);
328 Mat4MulVecfl(ob->obmat, vec);
329 project_short(ar, v3d, vec, sco2);
331 if(lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
332 if(select) pchan->bone->flag |= BONE_SELECTED;
333 else pchan->bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
339 static void do_lasso_select_objects(Scene *scene, ARegion *ar, View3D *v3d, short mcords[][2], short moves, short select)
343 for(base= scene->base.first; base; base= base->next) {
344 if(base->lay & v3d->lay) {
345 project_short(ar, v3d, base->object->obmat[3], &base->sx);
346 if(lasso_inside(mcords, moves, base->sx, base->sy)) {
348 if(select) select_base_v3d(base, BA_SELECT);
349 else select_base_v3d(base, BA_DESELECT);
350 base->object->flag= base->flag;
352 if(base->object->flag & OB_POSEMODE) {
353 do_lasso_select_pose(ar, v3d, base->object, mcords, moves, select);
359 void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
363 rect->xmin= rect->xmax= mcords[0][0];
364 rect->ymin= rect->ymax= mcords[0][1];
366 for(a=1; a<moves; a++) {
367 if(mcords[a][0]<rect->xmin) rect->xmin= mcords[a][0];
368 else if(mcords[a][0]>rect->xmax) rect->xmax= mcords[a][0];
369 if(mcords[a][1]<rect->ymin) rect->ymin= mcords[a][1];
370 else if(mcords[a][1]>rect->ymax) rect->ymax= mcords[a][1];
374 static void do_lasso_select_mesh__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
376 struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
378 if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
379 eve->f = data->select?(eve->f|1):(eve->f&~1);
382 static void do_lasso_select_mesh__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
384 struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
386 if (EM_check_backbuf(em_solidoffs+index)) {
388 if ( edge_fully_inside_rect(data->rect, x0, y0, x1, y1) &&
389 lasso_inside(data->mcords, data->moves, x0, y0) &&
390 lasso_inside(data->mcords, data->moves, x1, y1)) {
391 EM_select_edge(eed, data->select);
395 if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) {
396 EM_select_edge(eed, data->select);
401 static void do_lasso_select_mesh__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
403 struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
405 if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
406 EM_select_face_fgon(efa, data->select);
410 static void do_lasso_select_mesh(Scene *scene, ARegion *ar, View3D *v3d, short mcords[][2], short moves, short select)
412 struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } data;
413 EditMesh *em = G.editMesh;
417 lasso_select_boundbox(&rect, mcords, moves);
420 data.mcords = mcords;
422 data.select = select;
426 bbsel= EM_mask_init_backbuf_border(mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
428 if(scene->selectmode & SCE_SELECT_VERTEX) {
430 EM_backbuf_checkAndSelectVerts(em, select);
432 mesh_foreachScreenVert(ar, v3d, do_lasso_select_mesh__doSelectVert, &data, 1);
435 if(scene->selectmode & SCE_SELECT_EDGE) {
436 /* Does both bbsel and non-bbsel versions (need screen cos for both) */
439 mesh_foreachScreenEdge(ar, v3d, do_lasso_select_mesh__doSelectEdge, &data, 0);
443 mesh_foreachScreenEdge(ar, v3d, do_lasso_select_mesh__doSelectEdge, &data, 0);
447 if(scene->selectmode & SCE_SELECT_FACE) {
449 EM_backbuf_checkAndSelectFaces(em, select);
451 mesh_foreachScreenFace(ar, v3d, do_lasso_select_mesh__doSelectFace, &data);
456 EM_selectmode_flush();
460 /* this is an exception in that its the only lasso that dosnt use the 3d view (uses space image view) */
461 static void do_lasso_select_mesh_uv(short mcords[][2], short moves, short select)
463 EditMesh *em = G.editMesh;
466 int screenUV[2], nverts, i, ok = 1;
469 lasso_select_boundbox(&rect, mcords, moves);
471 if (draw_uvs_face_check()) { /* Face Center Sel */
474 for (efa= em->faces.first; efa; efa= efa->next) {
475 /* assume not touched */
477 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
478 if ((select) != (simaFaceSel_Check(efa, tf))) {
479 uv_center(tf->uv, cent, (void *)efa->v4);
480 uvco_to_areaco_noclip(cent, screenUV);
481 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
486 /* (de)selects all tagged faces and deals with sticky modes */
488 uvface_setsel__internal(select);
490 } else { /* Vert Sel*/
491 for (efa= em->faces.first; efa; efa= efa->next) {
492 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
493 if (simaFaceDraw_Check(efa, tf)) {
494 nverts= efa->v4? 4: 3;
495 for(i=0; i<nverts; i++) {
496 if ((select) != (simaUVSel_Check(efa, tf, i))) {
497 uvco_to_areaco_noclip(tf->uv[i], screenUV);
498 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
500 simaUVSel_Set(efa, tf, i);
502 simaUVSel_UnSet(efa, tf, i);
510 if (ok && G.sima->flag & SI_SYNC_UVSEL) {
511 if (select) EM_select_flush();
512 else EM_deselect_flush();
517 static void do_lasso_select_curve__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
519 struct { short (*mcords)[2]; short moves; short select; } *data = userData;
521 if (lasso_inside(data->mcords, data->moves, x, y)) {
523 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
525 if (G.f & G_HIDDENHANDLES) {
526 /* can only be beztindex==0 here since handles are hidden */
527 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
530 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
531 } else if (beztindex==1) {
532 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
534 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
541 static void do_lasso_select_curve(ARegion *ar, View3D *v3d, short mcords[][2], short moves, short select)
543 struct { short (*mcords)[2]; short moves; short select; } data;
545 data.mcords = mcords;
547 data.select = select;
549 nurbs_foreachScreenVert(ar, v3d, do_lasso_select_curve__doSelect, &data);
552 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, int y)
554 struct { short (*mcords)[2]; short moves; short select; } *data = userData;
556 if (lasso_inside(data->mcords, data->moves, x, y)) {
557 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
560 static void do_lasso_select_lattice(short mcords[][2], short moves, short select)
562 struct { short (*mcords)[2]; short moves; short select; } data;
564 data.mcords = mcords;
566 data.select = select;
568 lattice_foreachScreenVert(do_lasso_select_lattice__doSelect, &data);
571 static void do_lasso_select_armature(ARegion *ar, View3D *v3d, short mcords[][2], short moves, short select)
575 short sco1[2], sco2[2], didpoint;
577 for (ebone=G.edbo.first; ebone; ebone=ebone->next) {
579 VECCOPY(vec, ebone->head);
580 Mat4MulVecfl(G.obedit->obmat, vec);
581 project_short(ar, v3d, vec, sco1);
582 VECCOPY(vec, ebone->tail);
583 Mat4MulVecfl(G.obedit->obmat, vec);
584 project_short(ar, v3d, vec, sco2);
587 if(lasso_inside(mcords, moves, sco1[0], sco1[1])) {
588 if(select) ebone->flag |= BONE_ROOTSEL;
589 else ebone->flag &= ~BONE_ROOTSEL;
592 if(lasso_inside(mcords, moves, sco2[0], sco2[1])) {
593 if(select) ebone->flag |= BONE_TIPSEL;
594 else ebone->flag &= ~BONE_TIPSEL;
597 /* if one of points selected, we skip the bone itself */
598 if(didpoint==0 && lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
599 if(select) ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
600 else ebone->flag &= ~(BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
603 // XXX countall(); /* abused for flushing selection!!!! */
606 static void do_lasso_select_facemode(Scene *scene, short mcords[][2], short moves, short select)
609 Mesh *me= ob?ob->data:NULL;
612 if(me==NULL || me->mtface==NULL) return;
613 if(me->totface==0) return;
615 em_vertoffs= me->totface+1; /* max index array */
617 lasso_select_boundbox(&rect, mcords, moves);
618 EM_mask_init_backbuf_border(mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
620 EM_backbuf_checkAndSelectTFaces(me, select);
624 // XXX object_tface_flags_changed(ob, 0);
628 static void do_lasso_select_node(short mcords[][2], short moves, short select)
630 SpaceNode *snode = sa->spacedata.first;
637 lasso_select_boundbox(&rect, mcords, moves);
639 /* store selection in temp test flag */
640 for(node= snode->edittree->nodes.first; node; node= node->next) {
642 node_centf[0] = (node->totr.xmin+node->totr.xmax)/2;
643 node_centf[1] = (node->totr.ymin+node->totr.ymax)/2;
645 ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
646 if (BLI_in_rcti(&rect, node_cent[0], node_cent[1]) && lasso_inside(mcords, moves, node_cent[0], node_cent[1])) {
648 node->flag |= SELECT;
650 node->flag &= ~SELECT;
654 BIF_undo_push("Lasso select nodes");
658 void view3d_lasso_select(Scene *scene, ARegion *ar, View3D *v3d, short mcords[][2], short moves, short select)
661 if(FACESEL_PAINT_TEST)
662 do_lasso_select_facemode(scene, mcords, moves, select);
663 else if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))
665 // XX else if(G.f & G_PARTICLEEDIT)
666 // PE_do_lasso_select(mcords, moves, select);
668 do_lasso_select_objects(scene, ar, v3d, mcords, moves, select);
670 else if(G.obedit->type==OB_MESH) {
671 do_lasso_select_mesh(scene, ar, v3d, mcords, moves, select);
672 } else if(G.obedit->type==OB_CURVE || G.obedit->type==OB_SURF)
673 do_lasso_select_curve(ar, v3d, mcords, moves, select);
674 else if(G.obedit->type==OB_LATTICE)
675 do_lasso_select_lattice(mcords, moves, select);
676 else if(G.obedit->type==OB_ARMATURE)
677 do_lasso_select_armature(ar, v3d, mcords, moves, select);
679 BIF_undo_push("Lasso select");
684 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
685 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
688 unsigned int *bufmin,*bufmax;
689 int a,b,rc,tel,aantal,dirvec[4][2],maxob;
690 unsigned int retval=0;
693 if(base==0) return 0;
709 bufmax= buf+ size*size;
710 buf+= aantal*size+ aantal;
712 for(tel=1;tel<=size;tel++) {
717 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
718 if( *buf==dontdo ) retval= dontdo; /* if only color dontdo is available, still return dontdo */
720 buf+= (dirvec[rc][0]+dirvec[rc][1]);
722 if(buf<bufmin || buf>=bufmax) return retval;
732 /* ************************** mouse select ************************* */
735 #define MAXPICKBUF 10000
736 /* The max number of menu items in an object select menu */
737 #define SEL_MENU_SIZE 22
739 void set_active_base(Scene *scene, Base *base)
743 /* activating a non-mesh, should end a couple of modes... */
744 // if(base && base->object->type!=OB_MESH)
745 // XXX exit_paint_modes();
747 /* sets scene->basact */
752 /* signals to buttons */
753 // redraw_test_buttons(base->object);
756 // allqueue(REDRAWIPO, base->object->ipowin);
758 // allqueue(REDRAWACTION, 0);
759 // allqueue(REDRAWNLA, 0);
760 // allqueue(REDRAWNODE, 0);
762 /* signal to action */
763 // select_actionchannel_by_name(base->object->action, "Object", 1);
765 /* disable temporal locks */
766 for(tbase=FIRSTBASE; tbase; tbase= tbase->next) {
767 if(base!=tbase && (tbase->object->shapeflag & OB_SHAPE_TEMPLOCK)) {
768 tbase->object->shapeflag &= ~OB_SHAPE_TEMPLOCK;
769 DAG_object_flush_update(scene, tbase->object, OB_RECALC_DATA);
776 static void deselectall_except(Scene *scene, Base *b) /* deselect all except b */
780 for(base= FIRSTBASE; base; base= base->next) {
781 if (base->flag & SELECT) {
783 select_base_v3d(base, BA_DESELECT);
789 static Base *mouse_select_menu(Scene *scene, ARegion *ar, View3D *v3d, unsigned int *buffer, int hits, short *mval)
791 Base *baseList[SEL_MENU_SIZE]={NULL}; /*baseList is used to store all possible bases to bring up a menu */
794 char menuText[20 + SEL_MENU_SIZE*32] = "Select Object%t"; /* max ob name = 22 */
797 for(base=FIRSTBASE; base; base= base->next) {
798 if (BASE_SELECTABLE(v3d, base)) {
799 baseList[baseCount] = NULL;
801 /* two selection methods, the CTRL select uses max dist of 15 */
804 for(a=0; a<hits; a++) {
805 /* index was converted */
806 if(base->selcol==buffer[ (4 * a) + 3 ]) baseList[baseCount] = base;
812 project_short(ar, v3d, base->object->obmat[3], &base->sx);
814 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
815 if(temp<dist ) baseList[baseCount] = base;
818 if(baseList[baseCount]) {
819 if (baseCount < SEL_MENU_SIZE) {
820 baseList[baseCount] = base;
821 sprintf(str, "|%s %%x%d", base->object->id.name+2, baseCount+1); /* max ob name == 22 */
822 strcat(menuText, str);
829 if(baseCount<=1) return baseList[0];
831 baseCount = -1; // XXX = pupmenu(menuText);
833 if (baseCount != -1) { /* If nothing is selected then dont do anything */
834 return baseList[baseCount-1];
840 /* we want a select buffer with bones, if there are... */
841 /* so check three selection levels and compare */
842 static short mixed_bones_object_selectbuffer(Scene *scene, ARegion *ar, View3D *v3d, unsigned int *buffer, short *mval)
846 short a, hits15, hits9=0, hits5=0;
847 short has_bones15=0, has_bones9=0, has_bones5=0;
849 BLI_init_rcti(&rect, mval[0]-14, mval[0]+14, mval[1]-14, mval[1]+14);
850 hits15= view3d_opengl_select(scene, ar, v3d, buffer, MAXPICKBUF, &rect);
852 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
855 BLI_init_rcti(&rect, mval[0]-9, mval[0]+9, mval[1]-9, mval[1]+9);
856 hits9= view3d_opengl_select(scene, ar, v3d, buffer+offs, MAXPICKBUF-offs, &rect);
858 for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
861 BLI_init_rcti(&rect, mval[0]-5, mval[0]+5, mval[1]-5, mval[1]+5);
862 hits5= view3d_opengl_select(scene, ar, v3d, buffer+offs, MAXPICKBUF-offs, &rect);
864 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
869 offs= 4*hits15 + 4*hits9;
870 memcpy(buffer, buffer+offs, 4*offs);
875 memcpy(buffer, buffer+offs, 4*offs);
883 offs= 4*hits15 + 4*hits9;
884 memcpy(buffer, buffer+offs, 4*offs);
889 memcpy(buffer, buffer+offs, 4*offs);
898 /* mval is region coords */
899 static void mouse_select(Scene *scene, ARegion *ar, View3D *v3d, short *mval)
901 Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
902 unsigned int buffer[4*MAXPICKBUF];
903 int temp, a, dist=100;
905 short ctrl=0, shift=0, alt=0;
907 /* always start list from basact in wire mode */
908 startbase= FIRSTBASE;
909 if(BASACT && BASACT->next) startbase= BASACT->next;
911 /* This block uses the control key to make the object selected by its center point rather then its contents */
912 if(G.obedit==0 && ctrl) {
914 /* note; shift+alt goes to group-flush-selecting */
916 basact= mouse_select_menu(scene, ar, v3d, NULL, 0, mval);
920 if (BASE_SELECTABLE(v3d, base)) {
921 project_short(ar, v3d, base->object->obmat[3], &base->sx);
923 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
924 if(base==BASACT) temp+=10;
933 if(base==0) base= FIRSTBASE;
934 if(base==startbase) break;
939 /* if objects have posemode set, the bones are in the same selection buffer */
941 hits= mixed_bones_object_selectbuffer(scene, ar, v3d, buffer, mval);
946 for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
948 /* note; shift+alt goes to group-flush-selecting */
949 if(has_bones==0 && (alt))
950 basact= mouse_select_menu(scene, ar, v3d, buffer, hits, mval);
952 static short lastmval[2]={-100, -100};
955 /* define if we use solid nearest select or not */
956 if(v3d->drawtype>OB_WIRE) {
958 if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
959 if(!has_bones) /* hrms, if theres bones we always do nearest */
963 lastmval[0]= mval[0]; lastmval[1]= mval[1];
966 unsigned int min= 0xFFFFFFFF;
967 int selcol= 0, notcol=0;
971 /* we skip non-bone hits */
972 for(a=0; a<hits; a++) {
973 if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
975 selcol= buffer[4*a+3] & 0xFFFF;
980 /* only exclude active object when it is selected... */
981 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol;
983 for(a=0; a<hits; a++) {
984 if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
986 selcol= buffer[4*a+3] & 0xFFFF;
993 if(base->lay & v3d->lay) {
994 if(base->selcol==selcol) break;
998 if(base) basact= base;
1004 /* skip objects with select restriction, to prevent prematurely ending this loop
1005 * with an un-selectable choice */
1006 if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1008 if(base==NULL) base= FIRSTBASE;
1009 if(base==startbase) break;
1012 if(base->lay & v3d->lay) {
1013 for(a=0; a<hits; a++) {
1015 /* skip non-bone objects */
1016 if((buffer[4*a+3] & 0xFFFF0000)) {
1017 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1022 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1031 if(base==NULL) base= FIRSTBASE;
1032 if(base==startbase) break;
1037 if(has_bones && basact) {
1038 if(0) {// XXX do_pose_selectbuffer(basact, buffer, hits) ) { /* then bone is found */
1040 /* we make the armature selected:
1041 not-selected active object in posemode won't work well for tools */
1042 basact->flag|= SELECT;
1043 basact->object->flag= basact->flag;
1045 /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1046 if(G.f & G_WEIGHTPAINT) {
1047 /* prevent activating */
1051 /* prevent bone selecting to pass on to object selecting */
1058 /* so, do we have something selected? */
1062 /* only do select */
1063 deselectall_except(scene, basact);
1064 select_base_v3d(basact, BA_SELECT);
1066 /* also prevent making it active on mouse selection */
1067 else if (BASE_SELECTABLE(v3d, basact)) {
1073 deselectall_except(scene, basact);
1074 select_base_v3d(basact, BA_SELECT);
1076 else if(shift && alt) {
1077 // XXX select_all_from_groups(basact);
1080 if(basact->flag & SELECT) {
1081 if(basact==oldbasact)
1082 select_base_v3d(basact, BA_DESELECT);
1084 else select_base_v3d(basact, BA_SELECT);
1087 if(oldbasact != basact) {
1088 set_active_base(scene, basact);
1091 /* for visual speed, only in wire mode */
1092 if(v3d->drawtype==OB_WIRE) {
1093 /* however, not for posemodes */
1094 // XXX if(basact->object->flag & OB_POSEMODE);
1095 // else if(oldbasact && (oldbasact->object->flag & OB_POSEMODE));
1097 // if(oldbasact && oldbasact != basact && (oldbasact->lay & v3d->lay))
1098 // draw_object_ext(oldbasact);
1099 // draw_object_ext(basact);
1106 /* note; make it notifier! */
1107 ED_region_tag_redraw(ar);
1111 /* ******************** border and circle ************************************** */
1114 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1117 float v1[2], v2[2], v3[2];
1119 /* check points in circle itself */
1120 if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1121 if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1131 if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1136 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1138 struct { rcti *rect; int select; } *data = userData;
1140 if (BLI_in_rcti(data->rect, x, y)) {
1142 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1144 if (G.f & G_HIDDENHANDLES) {
1145 /* can only be beztindex==0 here since handles are hidden */
1146 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1149 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1150 } else if (beztindex==1) {
1151 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1153 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1159 static void do_nurbs_box_select(ARegion *ar, View3D *v3d, rcti *rect, int select)
1161 struct { rcti *rect; int select; } data;
1164 data.select = select;
1166 nurbs_foreachScreenVert(ar, v3d, do_nurbs_box_select__doSelect, &data);
1169 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1171 struct { rcti *rect; int select; } *data = userData;
1173 if (BLI_in_rcti(data->rect, x, y)) {
1174 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1177 static void do_lattice_box_select(rcti *rect, int select)
1179 struct { rcti *rect; int select, pass, done; } data;
1182 data.select = select;
1184 lattice_foreachScreenVert(do_lattice_box_select__doSelect, &data);
1187 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1189 struct { rcti *rect; short select, pass, done; } *data = userData;
1191 if (BLI_in_rcti(data->rect, x, y)) {
1192 eve->f = data->select?(eve->f|1):(eve->f&~1);
1195 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1197 struct { rcti *rect; short select, pass, done; } *data = userData;
1199 if(EM_check_backbuf(em_solidoffs+index)) {
1200 if (data->pass==0) {
1201 if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1202 EM_select_edge(eed, data->select);
1206 if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1207 EM_select_edge(eed, data->select);
1212 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1214 struct { rcti *rect; short select, pass, done; } *data = userData;
1216 if (BLI_in_rcti(data->rect, x, y)) {
1217 EM_select_face_fgon(efa, data->select);
1220 static void do_mesh_box_select(Scene *scene, ARegion *ar, View3D *v3d, rcti *rect, int select)
1222 struct { rcti *rect; short select, pass, done; } data;
1223 EditMesh *em = G.editMesh;
1227 data.select = select;
1231 bbsel= EM_init_backbuf_border(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1233 if(scene->selectmode & SCE_SELECT_VERTEX) {
1235 EM_backbuf_checkAndSelectVerts(em, select);
1237 mesh_foreachScreenVert(ar, v3d, do_mesh_box_select__doSelectVert, &data, 1);
1240 if(scene->selectmode & SCE_SELECT_EDGE) {
1241 /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1244 mesh_foreachScreenEdge(ar, v3d, do_mesh_box_select__doSelectEdge, &data, 0);
1248 mesh_foreachScreenEdge(ar, v3d, do_mesh_box_select__doSelectEdge, &data, 0);
1252 if(scene->selectmode & SCE_SELECT_FACE) {
1254 EM_backbuf_checkAndSelectFaces(em, select);
1256 mesh_foreachScreenFace(ar, v3d, do_mesh_box_select__doSelectFace, &data);
1262 EM_selectmode_flush();
1265 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
1267 Scene *scene= CTX_data_scene(C);
1268 ScrArea *sa= CTX_wm_area(C);
1269 ARegion *ar= CTX_wm_region(C);
1270 View3D *v3d= sa->spacedata.first;
1274 unsigned int buffer[4*MAXPICKBUF];
1278 val= RNA_int_get(op->ptr, "event_type");
1279 rect.xmin= RNA_int_get(op->ptr, "xmin");
1280 rect.ymin= RNA_int_get(op->ptr, "ymin");
1281 rect.xmax= RNA_int_get(op->ptr, "xmax");
1282 rect.ymax= RNA_int_get(op->ptr, "ymax");
1284 if(G.obedit==NULL && (FACESEL_PAINT_TEST)) {
1285 // XXX face_borderselect();
1286 return OPERATOR_FINISHED;
1288 else if(G.obedit==NULL && (G.f & G_PARTICLEEDIT)) {
1289 // XXX PE_borderselect();
1290 return OPERATOR_FINISHED;
1294 if(G.obedit->type==OB_MESH) {
1295 do_mesh_box_select(scene, ar, v3d, &rect, (val==LEFTMOUSE));
1296 // allqueue(REDRAWVIEW3D, 0);
1297 // if (EM_texFaceCheck())
1298 // allqueue(REDRAWIMAGE, 0);
1301 else if(ELEM(G.obedit->type, OB_CURVE, OB_SURF)) {
1302 do_nurbs_box_select(ar, v3d, &rect, val==LEFTMOUSE);
1303 // allqueue(REDRAWVIEW3D, 0);
1305 else if(G.obedit->type==OB_MBALL) {
1306 hits= view3d_opengl_select(scene, ar, v3d, buffer, MAXPICKBUF, &rect);
1308 ml= NULL; // XXX editelems.first;
1311 for(a=0; a<hits; a++) {
1312 if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1313 ml->flag |= MB_SCALE_RAD;
1314 if(val==LEFTMOUSE) ml->flag |= SELECT;
1315 else ml->flag &= ~SELECT;
1318 if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1319 ml->flag &= ~MB_SCALE_RAD;
1320 if(val==LEFTMOUSE) ml->flag |= SELECT;
1321 else ml->flag &= ~SELECT;
1328 else if(G.obedit->type==OB_ARMATURE) {
1331 /* clear flag we use to detect point was affected */
1332 for(ebone= G.edbo.first; ebone; ebone= ebone->next)
1333 ebone->flag &= ~BONE_DONE;
1335 hits= view3d_opengl_select(scene, ar, v3d, buffer, MAXPICKBUF, &rect);
1337 /* first we only check points inside the border */
1338 for (a=0; a<hits; a++){
1339 index = buffer[(4*a)+3];
1341 ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1342 if (index & BONESEL_TIP) {
1343 ebone->flag |= BONE_DONE;
1344 if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
1345 else ebone->flag &= ~BONE_TIPSEL;
1348 if (index & BONESEL_ROOT) {
1349 ebone->flag |= BONE_DONE;
1350 if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
1351 else ebone->flag &= ~BONE_ROOTSEL;
1356 /* now we have to flush tag from parents... */
1357 for(ebone= G.edbo.first; ebone; ebone= ebone->next) {
1358 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1359 if(ebone->parent->flag & BONE_DONE)
1360 ebone->flag |= BONE_DONE;
1364 /* only select/deselect entire bones when no points where in the rect */
1365 for (a=0; a<hits; a++){
1366 index = buffer[(4*a)+3];
1368 ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1369 if (index & BONESEL_BONE) {
1370 if(!(ebone->flag & BONE_DONE)) {
1372 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1374 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1381 else if(G.obedit->type==OB_LATTICE) {
1382 do_lattice_box_select(&rect, val==LEFTMOUSE);
1385 else { /* no editmode, unified for bones and objects */
1387 unsigned int *vbuffer=NULL; /* selection buffer */
1388 unsigned int *col; /* color in buffer */
1389 short selecting = 0;
1393 if((ob) && (ob->flag & OB_POSEMODE))
1401 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1402 vbuffer = MEM_mallocN(4 * (G.totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1403 hits= view3d_opengl_select(scene, ar, v3d, vbuffer, 4*(G.totobj+MAXPICKBUF), &rect);
1405 LOGIC NOTES (theeth):
1406 The buffer and ListBase have the same relative order, which makes the selection
1407 very simple. Loop through both data sets at the same time, if the color
1408 is the same as the object, we have a hit and can move to the next color
1409 and object pair, if not, just move to the next object,
1410 keeping the same color until we have a hit.
1412 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1413 does it incorrectly.
1416 if (hits>0) { /* no need to loop if there's no hit */
1419 while(base && hits) {
1420 Base *next = base->next;
1421 if(base->lay & v3d->lay) {
1422 while (base->selcol == (*col & 0xFFFF)) { /* we got an object */
1424 if(*col & 0xFFFF0000) { /* we got a bone */
1425 bone = NULL; // XXX get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1428 bone->flag |= BONE_SELECTED;
1429 // XXX select_actionchannel_by_name(base->object->action, bone->name, 1);
1432 bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1433 // XXX select_actionchannel_by_name(base->object->action, bone->name, 0);
1437 else if(!bone_only) {
1439 select_base_v3d(base, BA_SELECT);
1441 select_base_v3d(base, BA_DESELECT);
1444 col+=4; /* next color */
1456 BIF_undo_push("Border select");
1458 return OPERATOR_FINISHED;
1462 /* *****************Selection Operators******************* */
1464 /* ****** Border Select ****** */
1465 void VIEW3D_OT_borderselect(wmOperatorType *ot)
1469 ot->name= "Border Select";
1470 ot->idname= "VIEW3D_OT_borderselect";
1473 ot->invoke= WM_border_select_invoke;
1474 ot->exec= view3d_borderselect_exec;
1475 ot->modal= WM_border_select_modal;
1477 ot->poll= ED_operator_view3d_active;
1480 RNA_def_property(ot->srna, "event_type", PROP_INT, PROP_NONE);
1481 RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
1482 RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
1483 RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
1484 RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
1487 /* ****** Mouse Select ****** */
1489 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1491 ScrArea *sa= CTX_wm_area(C);
1492 ARegion *ar= CTX_wm_region(C);
1493 View3D *v3d= sa->spacedata.first;
1494 Scene *scene= CTX_data_scene(C);
1497 mval[0]= event->x - ar->winrct.xmin;
1498 mval[1]= event->y - ar->winrct.ymin;
1500 view3d_operator_needs_opengl(C);
1502 mouse_select(scene, ar, v3d, mval);
1504 return OPERATOR_FINISHED;
1507 void VIEW3D_OT_select(wmOperatorType *ot)
1511 ot->name= "Activate/Select";
1512 ot->idname= "VIEW3D_OT_select";
1515 ot->invoke= view3d_select_invoke;
1516 ot->poll= ED_operator_view3d_active;
1520 /* ****** Select by Type ****** */
1521 static EnumPropertyItem prop_select_object_types[] = {
1522 {OB_EMPTY, "EMPTY", "Empty", ""},
1523 {OB_MESH, "MESH", "Mesh", ""},
1524 {OB_CURVE, "CURVE", "Curve", ""},
1525 {OB_SURF, "SURFACE", "Surface", ""},
1526 {OB_FONT, "TEXT", "Text", ""},
1527 {OB_MBALL, "META", "Meta", ""},
1528 {OB_LAMP, "LAMP", "Lamp", ""},
1529 {OB_CAMERA, "CAMERA", "Camera", ""},
1530 {OB_LATTICE, "LATTICE", "Lattice", ""},
1531 {0, NULL, NULL, NULL}
1534 static int view3d_select_by_type_exec(bContext *C, wmOperator *op)
1536 ARegion *ar= CTX_wm_region(C);
1539 obtype = RNA_enum_get(op->ptr, "type");
1541 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1542 if(base->object->type==obtype) {
1543 select_base_v3d(base, BA_SELECT);
1549 ED_region_tag_redraw(ar);
1551 return OPERATOR_FINISHED;
1554 void VIEW3D_OT_select_by_type(wmOperatorType *ot)
1559 ot->name= "Select By Type";
1560 ot->idname= "VIEW3D_OT_select_by_type";
1563 ot->invoke= WM_menu_invoke;
1564 ot->exec= view3d_select_by_type_exec;
1565 ot->poll= ED_operator_view3d_active;
1567 prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
1568 RNA_def_property_enum_items(prop, prop_select_object_types);
1572 /* ****** selection by layer *******/
1574 static int view3d_select_by_layer_exec(bContext *C, wmOperator *op)
1576 ARegion *ar= CTX_wm_region(C);
1577 unsigned int layernum;
1579 layernum = RNA_int_get(op->ptr, "layer");
1581 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1582 if(base->lay == (1<< (layernum -1)))
1583 select_base_v3d(base, BA_SELECT);
1588 ED_region_tag_redraw(ar);
1590 return OPERATOR_FINISHED;
1593 void VIEW3D_OT_select_by_layer(wmOperatorType *ot)
1598 ot->name= "Selection by layer";
1599 ot->idname= "VIEW3D_OT_select_by_layer";
1602 /*ot->invoke = XXX - need a int grid popup*/
1603 ot->exec= view3d_select_by_layer_exec;
1604 ot->poll= ED_operator_view3d_active;
1606 prop = RNA_def_property(ot->srna, "layer", PROP_INT, PROP_UNSIGNED);
1607 RNA_def_property_ui_range(prop, 1, 20,1, 1);
1608 RNA_def_property_ui_text(prop, "layer", "The layer to select objects in");
1609 RNA_def_property_int_default(prop, 2);
1613 /* ****** invert selection *******/
1614 static int view3d_select_invert_exec(bContext *C, wmOperator *op)
1616 ScrArea *sa= CTX_wm_area(C);
1617 View3D *v3d= sa->spacedata.first;
1618 ARegion *ar= CTX_wm_region(C);
1620 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1621 if (TESTBASE(v3d, base))
1622 select_base_v3d(base, BA_DESELECT);
1624 select_base_v3d(base, BA_SELECT);
1629 ED_region_tag_redraw(ar);
1631 return OPERATOR_FINISHED;
1634 void VIEW3D_OT_select_invert(wmOperatorType *ot)
1638 ot->name= "Invert selection";
1639 ot->idname= "VIEW3D_OT_select_invert";
1642 ot->exec= view3d_select_invert_exec;
1643 ot->poll= ED_operator_view3d_active;
1646 /* ****** (de)select All *******/
1648 static int view3d_de_select_all_exec(bContext *C, wmOperator *op)
1650 ScrArea *sa= CTX_wm_area(C);
1651 View3D *v3d= sa->spacedata.first;
1652 ARegion *ar= CTX_wm_region(C);
1655 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1656 if (TESTBASE(v3d, base)) {
1664 if (!ok) return OPERATOR_PASS_THROUGH;
1666 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1667 if (a) select_base_v3d(base, BA_DESELECT);
1668 else select_base_v3d(base, BA_SELECT);
1673 ED_region_tag_redraw(ar);
1675 return OPERATOR_FINISHED;
1678 void VIEW3D_OT_de_select_all(wmOperatorType *ot)
1682 ot->name= "deselect all";
1683 ot->idname= "VIEW3D_OT_de_select_all";
1686 ot->exec= view3d_de_select_all_exec;
1687 ot->poll= ED_operator_view3d_active;
1690 /* ****** random selection *******/
1692 static int view3d_select_random_exec(bContext *C, wmOperator *op)
1694 ScrArea *sa= CTX_wm_area(C);
1695 View3D *v3d= sa->spacedata.first;
1696 ARegion *ar= CTX_wm_region(C);
1699 percent = RNA_int_get(op->ptr, "percent");
1701 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1702 if ((!TESTBASE(v3d, base) && (BLI_frand() * 100) < percent)) {
1703 select_base_v3d(base, BA_SELECT);
1709 ED_region_tag_redraw(ar);
1711 return OPERATOR_FINISHED;
1714 void VIEW3D_OT_select_random(wmOperatorType *ot)
1719 ot->name= "Random selection";
1720 ot->idname= "VIEW3D_OT_select_random";
1723 /*ot->invoke= view3d_select_random_invoke XXX - need a number popup ;*/
1724 ot->exec = view3d_select_random_exec;
1725 ot->poll= ED_operator_view3d_active;
1727 prop = RNA_def_property(ot->srna, "percent", PROP_INT, PROP_NONE);
1728 RNA_def_property_ui_range(prop, 1, 100,1, 1);
1729 RNA_def_property_ui_text(prop, "Percent", "Max persentage that will be selected");
1730 RNA_def_property_int_default(prop, 50);
1732 /* ------------------------------------------------------------------------- */
1734 /** The following functions are quick & dirty callback functions called
1735 * on the Circle select function (press B twice in Editmode)
1736 * They were torn out of the circle_select to make the latter more reusable
1737 * The callback version of circle_select (called circle_selectCB) was moved
1738 * to edit.c because of it's (wanted) generality.
1740 XXX These callback functions are still dirty, because they call globals...
1743 static void mesh_selectionCB__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1745 struct { short select, mval[2]; float radius; } *data = userData;
1746 int mx = x - data->mval[0], my = y - data->mval[1];
1747 float r = sqrt(mx*mx + my*my);
1749 if (r<=data->radius) {
1750 eve->f = data->select?(eve->f|1):(eve->f&~1);
1753 static void mesh_selectionCB__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1755 struct { short select, mval[2]; float radius; } *data = userData;
1757 if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1758 EM_select_edge(eed, data->select);
1761 static void mesh_selectionCB__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1763 struct { short select, mval[2]; float radius; } *data = userData;
1764 int mx = x - data->mval[0], my = y - data->mval[1];
1765 float r = sqrt(mx*mx + my*my);
1767 if (r<=data->radius) {
1768 EM_select_face_fgon(efa, data->select);
1772 static void mesh_selectionCB(Scene *scene, ARegion *ar, View3D *v3d, int selecting, Object *editobj, short *mval, float rad)
1774 struct { short select, mval[2]; float radius; } data;
1775 EditMesh *em = G.editMesh;
1778 if(!G.obedit && (FACESEL_PAINT_TEST)) {
1780 Mesh *me = ob?ob->data:NULL;
1783 em_vertoffs= me->totface+1; /* max index array */
1785 bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
1786 EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1789 // XXX object_tface_flags_changed(OBACT, 0);
1795 bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
1797 data.select = (selecting==LEFTMOUSE);
1798 data.mval[0] = mval[0];
1799 data.mval[1] = mval[1];
1802 if(scene->selectmode & SCE_SELECT_VERTEX) {
1804 EM_backbuf_checkAndSelectVerts(em, selecting==LEFTMOUSE);
1806 mesh_foreachScreenVert(ar, v3d, mesh_selectionCB__doSelectVert, &data, 1);
1810 if(scene->selectmode & SCE_SELECT_EDGE) {
1812 EM_backbuf_checkAndSelectEdges(em, selecting==LEFTMOUSE);
1814 mesh_foreachScreenEdge(ar, v3d, mesh_selectionCB__doSelectEdge, &data, 0);
1818 if(scene->selectmode & SCE_SELECT_FACE) {
1820 EM_backbuf_checkAndSelectFaces(em, selecting==LEFTMOUSE);
1822 mesh_foreachScreenFace(ar, v3d, mesh_selectionCB__doSelectFace, &data);
1827 EM_selectmode_flush();
1831 static void nurbscurve_selectionCB__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1833 struct { short select, mval[2]; float radius; } *data = userData;
1834 int mx = x - data->mval[0], my = y - data->mval[1];
1835 float r = sqrt(mx*mx + my*my);
1837 if (r<=data->radius) {
1839 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1842 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1843 } else if (beztindex==1) {
1844 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1846 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1851 static void nurbscurve_selectionCB(ARegion *ar, View3D *v3d, int selecting, Object *editobj, short *mval, float rad)
1853 struct { short select, mval[2]; float radius; } data;
1855 data.select = (selecting==LEFTMOUSE);
1856 data.mval[0] = mval[0];
1857 data.mval[1] = mval[1];
1860 nurbs_foreachScreenVert(ar, v3d, nurbscurve_selectionCB__doSelect, &data);
1864 static void latticecurve_selectionCB__doSelect(void *userData, BPoint *bp, int x, int y)
1866 struct { short select, mval[2]; float radius; } *data = userData;
1867 int mx = x - data->mval[0], my = y - data->mval[1];
1868 float r = sqrt(mx*mx + my*my);
1870 if (r<=data->radius) {
1871 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1874 static void lattice_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1876 struct { short select, mval[2]; float radius; } data;
1878 data.select = (selecting==LEFTMOUSE);
1879 data.mval[0] = mval[0];
1880 data.mval[1] = mval[1];
1883 lattice_foreachScreenVert(latticecurve_selectionCB__doSelect, &data);
1886 /** Callbacks for selection in Editmode */
1888 void obedit_selectionCB(Scene *scene, ARegion *ar, View3D *v3d, short selecting, Object *editobj, short *mval, float rad)
1890 switch(editobj->type) {
1892 mesh_selectionCB(scene, ar, v3d, selecting, editobj, mval, rad);
1896 nurbscurve_selectionCB(ar, v3d, selecting, editobj, mval, rad);
1899 lattice_selectionCB(selecting, editobj, mval, rad);
1905 // draw_sel_circle(0, 0, 0, 0, 0); /* signal */
1909 static int view3d_circle_select(bContext *C, wmOperator *op)
1911 ScrArea *sa= CTX_wm_area(C);
1912 ARegion *ar= CTX_wm_region(C);
1913 Scene *scene= CTX_data_scene(C);
1914 View3D *v3d= sa->spacedata.first;
1917 int x= RNA_int_get(op->ptr, "x");
1918 int y= RNA_int_get(op->ptr, "y");
1919 int radius= RNA_int_get(op->ptr, "radius");
1921 for(base= FIRSTBASE; base; base= base->next) {
1922 if(base->lay & v3d->lay) {
1923 project_short(ar, v3d, base->object->obmat[3], &base->sx);
1924 if(base->sx!=IS_CLIPPED) {
1927 if( dx*dx + dy*dy < radius*radius)
1928 select_base_v3d(base, BA_SELECT);
1935 void VIEW3D_OT_circle_select(wmOperatorType *ot)
1937 ot->name= "Circle Select";
1938 ot->idname= "VIEW3D_OT_circle_select";
1940 ot->invoke= WM_gesture_circle_invoke;
1941 ot->modal= WM_gesture_circle_modal;
1942 ot->exec= view3d_circle_select;
1943 ot->poll= ED_operator_view3d_active;
1945 RNA_def_property(ot->srna, "x", PROP_INT, PROP_NONE);
1946 RNA_def_property(ot->srna, "y", PROP_INT, PROP_NONE);
1947 RNA_def_property(ot->srna, "radius", PROP_INT, PROP_NONE);