correct fsf address
[blender.git] / source / blender / editors / space_view3d / view3d_select.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
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. 
10  *
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.
15  *
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31 #include <math.h>
32 #include <float.h>
33
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"
49
50 #include "MEM_guardedalloc.h"
51
52 #include "BLI_math.h"
53 #include "BLI_blenlib.h"
54 #include "BLI_editVert.h"
55 #include "BLI_rand.h"
56 #include "BLI_linklist.h"
57
58 #include "BKE_action.h"
59 #include "BKE_context.h"
60 #include "BKE_depsgraph.h"
61 #include "BKE_object.h"
62 #include "BKE_global.h"
63 #include "BKE_paint.h"
64 #include "BKE_scene.h"
65 #include "BKE_screen.h"
66 #include "BKE_utildefines.h"
67
68 #include "RE_pipeline.h"        // make_stars
69
70 #include "BIF_gl.h"
71
72 #include "WM_api.h"
73 #include "WM_types.h"
74
75 #include "RNA_access.h"
76 #include "RNA_define.h"
77
78 #include "ED_armature.h"
79 #include "ED_curve.h"
80 #include "ED_particle.h"
81 #include "ED_mesh.h"
82 #include "ED_object.h"
83 #include "ED_retopo.h"
84 #include "ED_screen.h"
85 #include "ED_types.h"
86 #include "ED_util.h"
87 #include "ED_mball.h"
88
89 #include "UI_interface.h"
90 #include "UI_resources.h"
91 #include "UI_view2d.h"
92
93 #include "PIL_time.h" /* smoothview */
94
95 #include "view3d_intern.h"      // own include
96
97 // TODO: should return whether there is valid context to continue
98 void view3d_set_viewcontext(bContext *C, ViewContext *vc)
99 {
100         memset(vc, 0, sizeof(ViewContext));
101         vc->ar= CTX_wm_region(C);
102         vc->scene= CTX_data_scene(C);
103         vc->v3d= CTX_wm_view3d(C);
104         vc->rv3d= CTX_wm_region_view3d(C);
105         vc->obact= CTX_data_active_object(C);
106         vc->obedit= CTX_data_edit_object(C); 
107 }
108
109 void view3d_get_view_aligned_coordinate(ViewContext *vc, float *fp, short mval[2])
110 {
111         float dvec[3];
112         short mx, my;
113         
114         mx= mval[0];
115         my= mval[1];
116         
117         project_short_noclip(vc->ar, fp, mval);
118         
119         initgrabz(vc->rv3d, fp[0], fp[1], fp[2]);
120         
121         if(mval[0]!=IS_CLIPPED) {
122                 window_to_3d_delta(vc->ar, dvec, mval[0]-mx, mval[1]-my);
123                 sub_v3_v3v3(fp, fp, dvec);
124         }
125 }
126
127 /*
128  * ob == NULL if you want global matrices
129  * */
130 void view3d_get_transformation(ARegion *ar, RegionView3D *rv3d, Object *ob, bglMats *mats)
131 {
132         float cpy[4][4];
133         int i, j;
134
135         if (ob) {
136                 mul_m4_m4m4(cpy, ob->obmat, rv3d->viewmat);
137         } else {
138                 copy_m4_m4(cpy, rv3d->viewmat);
139         }
140
141         for(i = 0; i < 4; ++i) {
142                 for(j = 0; j < 4; ++j) {
143                         mats->projection[i*4+j] = rv3d->winmat[i][j];
144                         mats->modelview[i*4+j] = cpy[i][j];
145                 }
146         }
147
148         mats->viewport[0] = ar->winrct.xmin;
149         mats->viewport[1] = ar->winrct.ymin;
150         mats->viewport[2] = ar->winx;
151         mats->viewport[3] = ar->winy;   
152 }
153
154 /* ********************** view3d_select: selection manipulations ********************* */
155
156 /* local prototypes */
157
158 void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select)
159 {
160         EditVert *eve;
161         int index= em_wireoffs;
162
163         for(eve= em->verts.first; eve; eve= eve->next, index++) {
164                 if(eve->h==0) {
165                         if(EM_check_backbuf(index)) {
166                                 eve->f = select?(eve->f|1):(eve->f&~1);
167                         }
168                 }
169         }
170 }
171
172 void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select)
173 {
174         EditEdge *eed;
175         int index= em_solidoffs;
176
177         for(eed= em->edges.first; eed; eed= eed->next, index++) {
178                 if(eed->h==0) {
179                         if(EM_check_backbuf(index)) {
180                                 EM_select_edge(eed, select);
181                         }
182                 }
183         }
184 }
185
186 void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select)
187 {
188         EditFace *efa;
189         int index= 1;
190
191         for(efa= em->faces.first; efa; efa= efa->next, index++) {
192                 if(efa->h==0) {
193                         if(EM_check_backbuf(index)) {
194                                 EM_select_face_fgon(em, efa, select);
195                         }
196                 }
197         }
198 }
199
200 void EM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
201 {
202         MFace *mface = me->mface;
203         int a;
204
205         if (mface) {
206                 for(a=1; a<=me->totface; a++, mface++) {
207                         if(EM_check_backbuf(a)) {
208                                 mface->flag = select?(mface->flag|ME_FACE_SEL):(mface->flag&~ME_FACE_SEL);
209                         }
210                 }
211         }
212 }
213
214 void arrows_move_cursor(unsigned short event)
215 {
216 #if 0
217         short mval[2];
218
219         getmouseco_sc(mval);
220
221         if(event==UPARROWKEY) {
222                 warp_pointer(mval[0], mval[1]+1);
223         } else if(event==DOWNARROWKEY) {
224                 warp_pointer(mval[0], mval[1]-1);
225         } else if(event==LEFTARROWKEY) {
226                 warp_pointer(mval[0]-1, mval[1]);
227         } else if(event==RIGHTARROWKEY) {
228                 warp_pointer(mval[0]+1, mval[1]);
229         }
230 #endif
231 }
232
233
234 /* *********************** GESTURE AND LASSO ******************* */
235
236 /* helper also for borderselect */
237 static int edge_fully_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
238 {
239         return BLI_in_rcti(rect, x1, y1) && BLI_in_rcti(rect, x2, y2);
240 }
241
242 static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
243 {
244         int d1, d2, d3, d4;
245         
246         /* check points in rect */
247         if(edge_fully_inside_rect(rect, x1, y1, x2, y2)) return 1;
248         
249         /* check points completely out rect */
250         if(x1<rect->xmin && x2<rect->xmin) return 0;
251         if(x1>rect->xmax && x2>rect->xmax) return 0;
252         if(y1<rect->ymin && y2<rect->ymin) return 0;
253         if(y1>rect->ymax && y2>rect->ymax) return 0;
254         
255         /* simple check lines intersecting. */
256         d1= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymin );
257         d2= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymax );
258         d3= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymax );
259         d4= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymin );
260         
261         if(d1<0 && d2<0 && d3<0 && d4<0) return 0;
262         if(d1>0 && d2>0 && d3>0 && d4>0) return 0;
263         
264         return 1;
265 }
266
267
268 #define MOVES_GESTURE 50
269 #define MOVES_LASSO 500
270
271 int lasso_inside(short mcords[][2], short moves, short sx, short sy)
272 {
273         /* we do the angle rule, define that all added angles should be about zero or 2*PI */
274         float angletot=0.0, len, dot, ang, cross, fp1[2], fp2[2];
275         int a;
276         short *p1, *p2;
277         
278         if(sx==IS_CLIPPED)
279                 return 0;
280         
281         p1= mcords[moves-1];
282         p2= mcords[0];
283         
284         /* first vector */
285         fp1[0]= (float)(p1[0]-sx);
286         fp1[1]= (float)(p1[1]-sy);
287         len= sqrt(fp1[0]*fp1[0] + fp1[1]*fp1[1]);
288         fp1[0]/= len;
289         fp1[1]/= len;
290         
291         for(a=0; a<moves; a++) {
292                 /* second vector */
293                 fp2[0]= (float)(p2[0]-sx);
294                 fp2[1]= (float)(p2[1]-sy);
295                 len= sqrt(fp2[0]*fp2[0] + fp2[1]*fp2[1]);
296                 fp2[0]/= len;
297                 fp2[1]/= len;
298                 
299                 /* dot and angle and cross */
300                 dot= fp1[0]*fp2[0] + fp1[1]*fp2[1];
301                 ang= fabs(saacos(dot));
302
303                 cross= (float)((p1[1]-p2[1])*(p1[0]-sx) + (p2[0]-p1[0])*(p1[1]-sy));
304                 
305                 if(cross<0.0) angletot-= ang;
306                 else angletot+= ang;
307                 
308                 /* circulate */
309                 fp1[0]= fp2[0]; fp1[1]= fp2[1];
310                 p1= p2;
311                 p2= mcords[a+1];
312         }
313         
314         if( fabs(angletot) > 4.0 ) return 1;
315         return 0;
316 }
317
318 /* edge version for lasso select. we assume boundbox check was done */
319 int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1)
320 {
321         short v1[2], v2[2];
322         int a;
323
324         if(x0==IS_CLIPPED || x1==IS_CLIPPED)
325                 return 0;
326         
327         v1[0] = x0, v1[1] = y0;
328         v2[0] = x1, v2[1] = y1;
329
330         /* check points in lasso */
331         if(lasso_inside(mcords, moves, v1[0], v1[1])) return 1;
332         if(lasso_inside(mcords, moves, v2[0], v2[1])) return 1;
333         
334         /* no points in lasso, so we have to intersect with lasso edge */
335         
336         if( isect_line_line_v2_short(mcords[0], mcords[moves-1], v1, v2) > 0) return 1;
337         for(a=0; a<moves-1; a++) {
338                 if( isect_line_line_v2_short(mcords[a], mcords[a+1], v1, v2) > 0) return 1;
339         }
340         
341         return 0;
342 }
343
344
345 /* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN) 
346    and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK
347 */
348 static void do_lasso_select_pose(ViewContext *vc, Object *ob, short mcords[][2], short moves, short select)
349 {
350         bPoseChannel *pchan;
351         float vec[3];
352         short sco1[2], sco2[2];
353         
354         if(ob->type!=OB_ARMATURE || ob->pose==NULL) return;
355         
356         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
357                 VECCOPY(vec, pchan->pose_head);
358                 mul_m4_v3(ob->obmat, vec);
359                 project_short(vc->ar, vec, sco1);
360                 VECCOPY(vec, pchan->pose_tail);
361                 mul_m4_v3(ob->obmat, vec);
362                 project_short(vc->ar, vec, sco2);
363                 
364                 if(lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
365                         if(select) pchan->bone->flag |= BONE_SELECTED;
366                         else pchan->bone->flag &= ~BONE_SELECTED;
367                 }
368         }
369         
370         {
371                 bArmature *arm= ob->data;
372                 if(arm->act_bone && (arm->act_bone->flag & BONE_SELECTED)==0) {
373                         arm->act_bone= NULL;
374                 }
375         }
376 }
377
378
379 static void do_lasso_select_objects(ViewContext *vc, short mcords[][2], short moves, short select)
380 {
381         Base *base;
382         
383         for(base= vc->scene->base.first; base; base= base->next) {
384                 if(BASE_SELECTABLE(vc->v3d, base)) { /* use this to avoid un-needed lasso lookups */
385                         project_short(vc->ar, base->object->obmat[3], &base->sx);
386                         if(lasso_inside(mcords, moves, base->sx, base->sy)) {
387                                 
388                                 if(select) ED_base_object_select(base, BA_SELECT);
389                                 else ED_base_object_select(base, BA_DESELECT);
390                                 base->object->flag= base->flag;
391                         }
392                         if(base->object->mode & OB_MODE_POSE) {
393                                 do_lasso_select_pose(vc, base->object, mcords, moves, select);
394                         }
395                 }
396         }
397 }
398
399 void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
400 {
401         short a;
402         
403         rect->xmin= rect->xmax= mcords[0][0];
404         rect->ymin= rect->ymax= mcords[0][1];
405         
406         for(a=1; a<moves; a++) {
407                 if(mcords[a][0]<rect->xmin) rect->xmin= mcords[a][0];
408                 else if(mcords[a][0]>rect->xmax) rect->xmax= mcords[a][0];
409                 if(mcords[a][1]<rect->ymin) rect->ymin= mcords[a][1];
410                 else if(mcords[a][1]>rect->ymax) rect->ymax= mcords[a][1];
411         }
412 }
413
414 static void do_lasso_select_mesh__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
415 {
416         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
417
418         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
419                 eve->f = data->select?(eve->f|1):(eve->f&~1);
420         }
421 }
422 static void do_lasso_select_mesh__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
423 {
424         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
425
426         if (EM_check_backbuf(em_solidoffs+index)) {
427                 if (data->pass==0) {
428                         if (    edge_fully_inside_rect(data->rect, x0, y0, x1, y1)  &&
429                                         lasso_inside(data->mcords, data->moves, x0, y0) &&
430                                         lasso_inside(data->mcords, data->moves, x1, y1)) {
431                                 EM_select_edge(eed, data->select);
432                                 data->done = 1;
433                         }
434                 } else {
435                         if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) {
436                                 EM_select_edge(eed, data->select);
437                         }
438                 }
439         }
440 }
441 static void do_lasso_select_mesh__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
442 {
443         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
444
445         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
446                 EM_select_face_fgon(data->vc.em, efa, data->select);
447         }
448 }
449
450 static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves, short select)
451 {
452         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } data;
453         ToolSettings *ts= vc->scene->toolsettings;
454         rcti rect;
455         int bbsel;
456         
457         lasso_select_boundbox(&rect, mcords, moves);
458         
459         /* set editmesh */
460         vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
461
462         data.vc= *vc;
463         data.rect = &rect;
464         data.mcords = mcords;
465         data.moves = moves;
466         data.select = select;
467         data.done = 0;
468         data.pass = 0;
469
470         /* workaround: init mats first, EM_mask_init_backbuf_border can change
471            view matrix to pixel space, breaking edge select with backbuf. fixes bug #20936 */
472
473         /* [#21018] breaks zbuf select. run below. only if bbsel fails */
474         /* ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d) */
475
476         glLoadMatrixf(vc->rv3d->viewmat);
477         bbsel= EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
478         
479         if(ts->selectmode & SCE_SELECT_VERTEX) {
480                 if (bbsel) {
481                         EM_backbuf_checkAndSelectVerts(vc->em, select);
482                 } else {
483                         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
484                         mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, 1);
485                 }
486         }
487         if(ts->selectmode & SCE_SELECT_EDGE) {
488                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
489                 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
490
491                 data.pass = 0;
492                 mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0);
493
494                 if (data.done==0) {
495                         data.pass = 1;
496                         mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0);
497                 }
498         }
499         
500         if(ts->selectmode & SCE_SELECT_FACE) {
501                 if (bbsel) {
502                         EM_backbuf_checkAndSelectFaces(vc->em, select);
503                 } else {
504                         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
505                         mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data);
506                 }
507         }
508         
509         EM_free_backbuf();
510         EM_selectmode_flush(vc->em);    
511 }
512
513 #if 0
514 /* this is an exception in that its the only lasso that dosnt use the 3d view (uses space image view) */
515 static void do_lasso_select_mesh_uv(short mcords[][2], short moves, short select)
516 {
517         EditFace *efa;
518         MTFace *tf;
519         int screenUV[2], nverts, i, ok = 1;
520         rcti rect;
521         
522         lasso_select_boundbox(&rect, mcords, moves);
523         
524         if (draw_uvs_face_check()) { /* Face Center Sel */
525                 float cent[2];
526                 ok = 0;
527                 for (efa= em->faces.first; efa; efa= efa->next) {
528                         /* assume not touched */
529                         efa->tmp.l = 0;
530                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
531                         if ((select) != (simaFaceSel_Check(efa, tf))) {
532                                 uv_center(tf->uv, cent, (void *)efa->v4);
533                                 uvco_to_areaco_noclip(cent, screenUV);
534                                 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
535                                         efa->tmp.l = ok = 1;
536                                 }
537                         }
538                 }
539                 /* (de)selects all tagged faces and deals with sticky modes */
540                 if (ok)
541                         uvface_setsel__internal(select);
542                 
543         } else { /* Vert Sel*/
544                 for (efa= em->faces.first; efa; efa= efa->next) {
545                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
546                         if (simaFaceDraw_Check(efa, tf)) {              
547                                 nverts= efa->v4? 4: 3;
548                                 for(i=0; i<nverts; i++) {
549                                         if ((select) != (simaUVSel_Check(efa, tf, i))) {
550                                                 uvco_to_areaco_noclip(tf->uv[i], screenUV);
551                                                 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
552                                                         if (select) {
553                                                                 simaUVSel_Set(efa, tf, i);
554                                                         } else {
555                                                                 simaUVSel_UnSet(efa, tf, i);
556                                                         }
557                                                 }
558                                         }
559                                 }
560                         }
561                 }
562         }
563         if (ok && G.sima->flag & SI_SYNC_UVSEL) {
564                 if (select) EM_select_flush(vc->em);
565                 else            EM_deselect_flush(vc->em);
566         }
567 }
568 #endif
569
570 static void do_lasso_select_curve__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
571 {
572         struct { ViewContext vc; short (*mcords)[2]; short moves; short select; } *data = userData;
573         
574         if (lasso_inside(data->mcords, data->moves, x, y)) {
575                 if (bp) {
576                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
577                 } else {
578                         Curve *cu= data->vc.obedit->data;
579                         
580                         if (cu->drawflag & CU_HIDE_HANDLES) {
581                                 /* can only be beztindex==0 here since handles are hidden */
582                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
583                         } else {
584                                 if (beztindex==0) {
585                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
586                                 } else if (beztindex==1) {
587                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
588                                 } else {
589                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
590                                 }
591                         }
592                 }
593         }
594 }
595
596 static void do_lasso_select_curve(ViewContext *vc, short mcords[][2], short moves, short select)
597 {
598         struct { ViewContext vc; short (*mcords)[2]; short moves; short select; } data;
599
600         /* set vc->editnurb */
601         data.vc = *vc;
602         data.mcords = mcords;
603         data.moves = moves;
604         data.select = select;
605
606         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
607         nurbs_foreachScreenVert(vc, do_lasso_select_curve__doSelect, &data);
608 }
609
610 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, int y)
611 {
612         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
613
614         if (lasso_inside(data->mcords, data->moves, x, y)) {
615                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
616         }
617 }
618 static void do_lasso_select_lattice(ViewContext *vc, short mcords[][2], short moves, short select)
619 {
620         struct { short (*mcords)[2]; short moves; short select; } data;
621
622         /* set editdata in vc */
623         data.mcords = mcords;
624         data.moves = moves;
625         data.select = select;
626
627         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
628         lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data);
629 }
630
631 static void do_lasso_select_armature(ViewContext *vc, short mcords[][2], short moves, short select)
632 {
633         bArmature *arm= vc->obedit->data;
634         EditBone *ebone;
635         float vec[3];
636         short sco1[2], sco2[2], didpoint;
637         
638         /* set editdata in vc */
639         
640         for (ebone= arm->edbo->first; ebone; ebone=ebone->next) {
641
642                 VECCOPY(vec, ebone->head);
643                 mul_m4_v3(vc->obedit->obmat, vec);
644                 project_short(vc->ar, vec, sco1);
645                 VECCOPY(vec, ebone->tail);
646                 mul_m4_v3(vc->obedit->obmat, vec);
647                 project_short(vc->ar, vec, sco2);
648                 
649                 didpoint= 0;
650                 if(lasso_inside(mcords, moves, sco1[0], sco1[1])) {
651                         if(select) ebone->flag |= BONE_ROOTSEL;
652                         else ebone->flag &= ~BONE_ROOTSEL;
653                         didpoint= 1;
654                 }
655                 if(lasso_inside(mcords, moves, sco2[0], sco2[1])) {
656                    if(select) ebone->flag |= BONE_TIPSEL;
657                    else ebone->flag &= ~BONE_TIPSEL;
658                    didpoint= 1;
659                 }
660                 /* if one of points selected, we skip the bone itself */
661                 if(didpoint==0 && lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
662                         if(select) ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
663                         else ebone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
664                 }
665         }
666         ED_armature_sync_selection(arm->edbo);
667         ED_armature_validate_active(arm);
668 }
669
670 static void do_lasso_select_facemode(ViewContext *vc, short mcords[][2], short moves, short select)
671 {
672         Object *ob= vc->obact;
673         Mesh *me= ob?ob->data:NULL;
674         rcti rect;
675         
676         if(me==NULL || me->mtface==NULL) return;
677         if(me->totface==0) return;
678         
679         em_vertoffs= me->totface+1;     /* max index array */
680         
681         lasso_select_boundbox(&rect, mcords, moves);
682         EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
683         
684         EM_backbuf_checkAndSelectTFaces(me, select);
685         
686         EM_free_backbuf();
687         
688 // XXX  object_tface_flags_changed(ob, 0);
689 }
690
691 #if 0
692 static void do_lasso_select_node(short mcords[][2], short moves, short select)
693 {
694         SpaceNode *snode = sa->spacedata.first;
695         
696         bNode *node;
697         rcti rect;
698         short node_cent[2];
699         float node_centf[2];
700         
701         lasso_select_boundbox(&rect, mcords, moves);
702         
703         /* store selection in temp test flag */
704         for(node= snode->edittree->nodes.first; node; node= node->next) {
705                 
706                 node_centf[0] = (node->totr.xmin+node->totr.xmax)/2;
707                 node_centf[1] = (node->totr.ymin+node->totr.ymax)/2;
708                 
709                 ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
710                 if (BLI_in_rcti(&rect, node_cent[0], node_cent[1]) && lasso_inside(mcords, moves, node_cent[0], node_cent[1])) {
711                         if (select) {
712                                 node->flag |= SELECT;
713                         } else {
714                                 node->flag &= ~SELECT;
715                         }
716                 }
717         }
718         BIF_undo_push("Lasso select nodes");
719 }
720 #endif
721
722 void view3d_lasso_select(bContext *C, ViewContext *vc, short mcords[][2], short moves, short select)
723 {
724         Object *ob = CTX_data_active_object(C);
725
726         if(vc->obedit==NULL) { /* Object Mode */
727                 if(paint_facesel_test(ob))
728                         do_lasso_select_facemode(vc, mcords, moves, select);
729                 else if(ob && ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT))
730                         ;
731                 else if(ob && ob->mode & OB_MODE_PARTICLE_EDIT)
732                         PE_lasso_select(C, mcords, moves, select);
733                 else  
734                         do_lasso_select_objects(vc, mcords, moves, select);
735         }
736         else { /* Edit Mode */
737                 if(vc->obedit->type==OB_MESH)
738                         do_lasso_select_mesh(vc, mcords, moves, select);
739                 else if(vc->obedit->type==OB_CURVE || vc->obedit->type==OB_SURF) 
740                         do_lasso_select_curve(vc, mcords, moves, select);
741                 else if(vc->obedit->type==OB_LATTICE) 
742                         do_lasso_select_lattice(vc, mcords, moves, select);
743                 else if(vc->obedit->type==OB_ARMATURE)
744                         do_lasso_select_armature(vc, mcords, moves, select);
745         
746                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc->obedit->data);
747         }
748 }
749
750
751 /* lasso operator gives properties, but since old code works
752    with short array we convert */
753 static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
754 {
755         ViewContext vc;
756         int select, i= 0;
757         short mcords[1024][2];
758
759         RNA_BEGIN(op->ptr, itemptr, "path") {
760                 float loc[2];
761                 
762                 RNA_float_get_array(&itemptr, "loc", loc);
763                 mcords[i][0]= (short)loc[0];
764                 mcords[i][1]= (short)loc[1];
765                 i++;
766                 if(i>=1024) break;
767         }
768         RNA_END;
769         
770         if(i>1) {
771                 view3d_operator_needs_opengl(C);
772                 
773                 /* setup view context for argument to callbacks */
774                 view3d_set_viewcontext(C, &vc);
775                 
776                 select= !RNA_boolean_get(op->ptr, "deselect");
777                 view3d_lasso_select(C, &vc, mcords, i, select);
778                 
779                 return OPERATOR_FINISHED;
780         }
781         return OPERATOR_PASS_THROUGH;
782 }
783
784 void VIEW3D_OT_select_lasso(wmOperatorType *ot)
785 {
786         ot->name= "Lasso Select";
787         ot->description= "Select items using lasso selection";
788         ot->idname= "VIEW3D_OT_select_lasso";
789         
790         ot->invoke= WM_gesture_lasso_invoke;
791         ot->modal= WM_gesture_lasso_modal;
792         ot->exec= view3d_lasso_select_exec;
793         ot->poll= WM_operator_winactive;
794         
795         /* flags */
796         ot->flag= OPTYPE_UNDO;
797         
798         RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
799         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items.");
800 }
801
802
803 /* ************************************************* */
804
805 #if 0
806 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
807 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
808 {
809         Base *base;
810         unsigned int *bufmin,*bufmax;
811         int a,b,rc,tel,aantal,dirvec[4][2],maxob;
812         unsigned int retval=0;
813         
814         base= LASTBASE;
815         if(base==0) return 0;
816         maxob= base->selcol;
817
818         aantal= (size-1)/2;
819         rc= 0;
820
821         dirvec[0][0]= 1;
822         dirvec[0][1]= 0;
823         dirvec[1][0]= 0;
824         dirvec[1][1]= -size;
825         dirvec[2][0]= -1;
826         dirvec[2][1]= 0;
827         dirvec[3][0]= 0;
828         dirvec[3][1]= size;
829
830         bufmin= buf;
831         bufmax= buf+ size*size;
832         buf+= aantal*size+ aantal;
833
834         for(tel=1;tel<=size;tel++) {
835
836                 for(a=0;a<2;a++) {
837                         for(b=0;b<tel;b++) {
838
839                                 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
840                                 if( *buf==dontdo ) retval= dontdo;      /* if only color dontdo is available, still return dontdo */
841                                 
842                                 buf+= (dirvec[rc][0]+dirvec[rc][1]);
843
844                                 if(buf<bufmin || buf>=bufmax) return retval;
845                         }
846                         rc++;
847                         rc &= 3;
848                 }
849         }
850         return retval;
851 }
852 #endif
853
854 /* ************************** mouse select ************************* */
855
856
857 /* The max number of menu items in an object select menu */
858 #define SEL_MENU_SIZE   22
859
860 static void deselectall_except(Scene *scene, Base *b)   /* deselect all except b */
861 {
862         Base *base;
863         
864         for(base= FIRSTBASE; base; base= base->next) {
865                 if (base->flag & SELECT) {
866                         if(b!=base) {
867                                 ED_base_object_select(base, BA_DESELECT);
868                         }
869                 }
870         }
871 }
872
873 static Base *mouse_select_menu(bContext *C, ViewContext *vc, unsigned int *buffer, int hits, short *mval, short extend)
874 {
875         short baseCount = 0;
876         short ok;
877         LinkNode *linklist= NULL;
878         
879         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
880                 ok= FALSE;
881
882                 /* two selection methods, the CTRL select uses max dist of 15 */
883                 if(buffer) {
884                         int a;
885                         for(a=0; a<hits; a++) {
886                                 /* index was converted */
887                                 if(base->selcol==buffer[ (4 * a) + 3 ])
888                                         ok= TRUE;
889                         }
890                 }
891                 else {
892                         int temp, dist=15;
893
894                         project_short(vc->ar, base->object->obmat[3], &base->sx);
895                         
896                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
897                         if(temp < dist)
898                                 ok= TRUE;
899                 }
900
901                 if(ok) {
902                         baseCount++;
903                         BLI_linklist_prepend(&linklist, base);
904
905                         if (baseCount==SEL_MENU_SIZE)
906                                 break;
907                 }
908         }
909         CTX_DATA_END;
910
911         if(baseCount)
912
913
914         if(baseCount==0) {
915                 return NULL;
916         }
917         if(baseCount == 1) {
918                 Base *base= (Base *)linklist->link;
919                 BLI_linklist_free(linklist, NULL);
920                 return base;
921         }
922         else {
923                 /* UI */
924                 uiPopupMenu *pup= uiPupMenuBegin(C, "Select Object", 0);
925                 uiLayout *layout= uiPupMenuLayout(pup);
926                 uiLayout *split= uiLayoutSplit(layout, 0, 0);
927                 uiLayout *column= uiLayoutColumn(split, 0);
928                 LinkNode *node;
929
930                 node= linklist;
931                 while(node) {
932                         Base *base=node->link;
933                         Object *ob= base->object;
934                         char *name= ob->id.name+2;
935                         /* annoying!, since we need to set 2 props cant use this. */
936                         /* uiItemStringO(column, name, 0, "OBJECT_OT_select_name", "name", name); */
937
938                         {
939                                 PointerRNA ptr;
940
941                                 WM_operator_properties_create(&ptr, "OBJECT_OT_select_name");
942                                 RNA_string_set(&ptr, "name", name);
943                                 RNA_boolean_set(&ptr, "extend", extend);
944                                 uiItemFullO(column, name, uiIconFromID((ID *)ob), "OBJECT_OT_select_name", ptr.data, WM_OP_EXEC_DEFAULT, 0);
945                         }
946
947                         node= node->next;
948                 }
949
950                 uiPupMenuEnd(C, pup);
951
952                 BLI_linklist_free(linklist, NULL);
953                 return NULL;
954         }
955 }
956
957 /* we want a select buffer with bones, if there are... */
958 /* so check three selection levels and compare */
959 static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, short *mval)
960 {
961         rcti rect;
962         int offs;
963         short a, hits15, hits9=0, hits5=0;
964         short has_bones15=0, has_bones9=0, has_bones5=0;
965         
966         BLI_init_rcti(&rect, mval[0]-14, mval[0]+14, mval[1]-14, mval[1]+14);
967         hits15= view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
968         if(hits15>0) {
969                 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
970                 
971                 offs= 4*hits15;
972                 BLI_init_rcti(&rect, mval[0]-9, mval[0]+9, mval[1]-9, mval[1]+9);
973                 hits9= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
974                 if(hits9>0) {
975                         for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
976                         
977                         offs+= 4*hits9;
978                         BLI_init_rcti(&rect, mval[0]-5, mval[0]+5, mval[1]-5, mval[1]+5);
979                         hits5= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
980                         if(hits5>0) {
981                                 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
982                         }
983                 }
984                 
985                 if(has_bones5) {
986                         offs= 4*hits15 + 4*hits9;
987                         memcpy(buffer, buffer+offs, 4*offs);
988                         return hits5;
989                 }
990                 if(has_bones9) {
991                         offs= 4*hits15;
992                         memcpy(buffer, buffer+offs, 4*offs);
993                         return hits9;
994                 }
995                 if(has_bones15) {
996                         return hits15;
997                 }
998                 
999                 if(hits5>0) {
1000                         offs= 4*hits15 + 4*hits9;
1001                         memcpy(buffer, buffer+offs, 4*offs);
1002                         return hits5;
1003                 }
1004                 if(hits9>0) {
1005                         offs= 4*hits15;
1006                         memcpy(buffer, buffer+offs, 4*offs);
1007                         return hits9;
1008                 }
1009                 return hits15;
1010         }
1011         
1012         return 0;
1013 }
1014
1015 /* returns basact */
1016 static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits, short *mval, Base *startbase, int has_bones)
1017 {
1018         Scene *scene= vc->scene;
1019         View3D *v3d= vc->v3d;
1020         Base *base, *basact= NULL;
1021         static short lastmval[2]={-100, -100};
1022         int a, donearest= 0;
1023         
1024         /* define if we use solid nearest select or not */
1025         if(v3d->drawtype>OB_WIRE) {
1026                 donearest= 1;
1027                 if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
1028                         if(!has_bones)  /* hrms, if theres bones we always do nearest */
1029                                 donearest= 0;
1030                 }
1031         }
1032         lastmval[0]= mval[0]; lastmval[1]= mval[1];
1033         
1034         if(donearest) {
1035                 unsigned int min= 0xFFFFFFFF;
1036                 int selcol= 0, notcol=0;
1037                 
1038                 
1039                 if(has_bones) {
1040                         /* we skip non-bone hits */
1041                         for(a=0; a<hits; a++) {
1042                                 if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
1043                                         min= buffer[4*a+1];
1044                                         selcol= buffer[4*a+3] & 0xFFFF;
1045                                 }
1046                         }
1047                 }
1048                 else {
1049                         /* only exclude active object when it is selected... */
1050                         if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol; 
1051                         
1052                         for(a=0; a<hits; a++) {
1053                                 if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1054                                         min= buffer[4*a+1];
1055                                         selcol= buffer[4*a+3] & 0xFFFF;
1056                                 }
1057                         }
1058                 }
1059                 
1060                 base= FIRSTBASE;
1061                 while(base) {
1062                         if(base->lay & v3d->lay) {
1063                                 if(base->selcol==selcol) break;
1064                         }
1065                         base= base->next;
1066                 }
1067                 if(base) basact= base;
1068         }
1069         else {
1070                 
1071                 base= startbase;
1072                 while(base) {
1073                         /* skip objects with select restriction, to prevent prematurely ending this loop
1074                         * with an un-selectable choice */
1075                         if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1076                                 base=base->next;
1077                                 if(base==NULL) base= FIRSTBASE;
1078                                 if(base==startbase) break;
1079                         }
1080                         
1081                         if(base->lay & v3d->lay) {
1082                                 for(a=0; a<hits; a++) {
1083                                         if(has_bones) {
1084                                                 /* skip non-bone objects */
1085                                                 if((buffer[4*a+3] & 0xFFFF0000)) {
1086                                                         if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1087                                                                 basact= base;
1088                                                 }
1089                                         }
1090                                         else {
1091                                                 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1092                                                         basact= base;
1093                                         }
1094                                 }
1095                         }
1096                         
1097                         if(basact) break;
1098                         
1099                         base= base->next;
1100                         if(base==NULL) base= FIRSTBASE;
1101                         if(base==startbase) break;
1102                 }
1103         }
1104         
1105         return basact;
1106 }
1107
1108 /* mval comes from event->mval, only use within region handlers */
1109 Base *ED_view3d_give_base_under_cursor(bContext *C, short *mval)
1110 {
1111         ViewContext vc;
1112         Base *basact= NULL;
1113         unsigned int buffer[4*MAXPICKBUF];
1114         int hits;
1115         
1116         /* setup view context for argument to callbacks */
1117         view3d_operator_needs_opengl(C);
1118         view3d_set_viewcontext(C, &vc);
1119         
1120         hits= mixed_bones_object_selectbuffer(&vc, buffer, mval);
1121         
1122         if(hits>0) {
1123                 int a, has_bones= 0;
1124                 
1125                 for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1126                 
1127                 basact= mouse_select_eval_buffer(&vc, buffer, hits, mval, vc.scene->base.first, has_bones);
1128         }
1129         
1130         return basact;
1131 }
1132
1133 /* mval is region coords */
1134 static int mouse_select(bContext *C, short *mval, short extend, short obcenter, short enumerate)
1135 {
1136         ViewContext vc;
1137         ARegion *ar= CTX_wm_region(C);
1138         View3D *v3d= CTX_wm_view3d(C);
1139         Scene *scene= CTX_data_scene(C);
1140         Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
1141         int temp, a, dist=100;
1142         int retval = 0;
1143         short hits;
1144         
1145         /* setup view context for argument to callbacks */
1146         view3d_set_viewcontext(C, &vc);
1147         
1148         /* always start list from basact in wire mode */
1149         startbase=  FIRSTBASE;
1150         if(BASACT && BASACT->next) startbase= BASACT->next;
1151         
1152         /* This block uses the control key to make the object selected by its center point rather then its contents */
1153         /* XXX later on, in editmode do not activate */
1154         if(vc.obedit==NULL && obcenter) {
1155                 
1156                 /* note; shift+alt goes to group-flush-selecting */
1157                 if(enumerate) {
1158                         basact= mouse_select_menu(C, &vc, NULL, 0, mval, extend);
1159                 } else {
1160                         base= startbase;
1161                         while(base) {
1162                                 if (BASE_SELECTABLE(v3d, base)) {
1163                                         project_short(ar, base->object->obmat[3], &base->sx);
1164                                         
1165                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
1166                                         if(base==BASACT) temp+=10;
1167                                         if(temp<dist ) {
1168                                                 
1169                                                 dist= temp;
1170                                                 basact= base;
1171                                         }
1172                                 }
1173                                 base= base->next;
1174                                 
1175                                 if(base==0) base= FIRSTBASE;
1176                                 if(base==startbase) break;
1177                         }
1178                 }
1179         }
1180         else {
1181                 unsigned int buffer[4*MAXPICKBUF];
1182
1183                 /* if objects have posemode set, the bones are in the same selection buffer */
1184                 
1185                 hits= mixed_bones_object_selectbuffer(&vc, buffer, mval);
1186                 
1187                 if(hits>0) {
1188                         int has_bones= 0;
1189                         
1190                         for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1191
1192                         /* note; shift+alt goes to group-flush-selecting */
1193                         if(has_bones==0 && enumerate) {
1194                                 basact= mouse_select_menu(C, &vc, buffer, hits, mval, extend);
1195                         } else {
1196                                 basact= mouse_select_eval_buffer(&vc, buffer, hits, mval, startbase, has_bones);
1197                         }
1198                         
1199                         if(has_bones && basact) {
1200                                 if(ED_do_pose_selectbuffer(scene, basact, buffer, hits, extend) ) {     /* then bone is found */
1201                                 
1202                                         /* we make the armature selected: 
1203                                            not-selected active object in posemode won't work well for tools */
1204                                         basact->flag|= SELECT;
1205                                         basact->object->flag= basact->flag;
1206                                         
1207                                         retval = 1;
1208                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, basact->object);
1209                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, basact->object);
1210                                         
1211                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1212                                         if(BASACT && BASACT->object->mode & OB_MODE_WEIGHT_PAINT) {
1213                                                 /* prevent activating */
1214                                                 basact= NULL;
1215                                         }
1216
1217                                 }
1218                                 /* prevent bone selecting to pass on to object selecting */
1219                                 if(basact==BASACT)
1220                                         basact= NULL;
1221                         }
1222                 }
1223         }
1224         
1225         /* so, do we have something selected? */
1226         if(basact) {
1227                 retval = 1;
1228                 
1229                 if(vc.obedit) {
1230                         /* only do select */
1231                         deselectall_except(scene, basact);
1232                         ED_base_object_select(basact, BA_SELECT);
1233                 }
1234                 /* also prevent making it active on mouse selection */
1235                 else if (BASE_SELECTABLE(v3d, basact)) {
1236
1237                         oldbasact= BASACT;
1238                         
1239                         if(!extend) {
1240                                 deselectall_except(scene, basact);
1241                                 ED_base_object_select(basact, BA_SELECT);
1242                         }
1243                         else if(0) {
1244                                 // XXX select_all_from_groups(basact);
1245                         }
1246                         else {
1247                                 if(basact->flag & SELECT) {
1248                                         if(basact==oldbasact)
1249                                                 ED_base_object_select(basact, BA_DESELECT);
1250                                 }
1251                                 else ED_base_object_select(basact, BA_SELECT);
1252                         }
1253
1254                         if(oldbasact != basact) {
1255                                 ED_base_object_activate(C, basact); /* adds notifier */
1256                         }
1257
1258                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1259                 }
1260         }
1261
1262         return retval;
1263 }
1264
1265 /* ********************  border and circle ************************************** */
1266
1267
1268 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1269 {
1270         int radsq= rad*rad;
1271         float v1[2], v2[2], v3[2];
1272         
1273         /* check points in circle itself */
1274         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1275         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1276         
1277         /* pointdistline */
1278         v3[0]= centx;
1279         v3[1]= centy;
1280         v1[0]= x1;
1281         v1[1]= y1;
1282         v2[0]= x2;
1283         v2[1]= y2;
1284         
1285         if( dist_to_line_segment_v2(v3, v1, v2) < (float)rad ) return 1;
1286         
1287         return 0;
1288 }
1289
1290 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1291 {
1292         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1293
1294         if (BLI_in_rcti(data->rect, x, y)) {
1295                 if (bp) {
1296                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1297                 } else {
1298                         Curve *cu= data->vc.obedit->data;
1299                         
1300                         if (cu->drawflag & CU_HIDE_HANDLES) {
1301                                 /* can only be beztindex==0 here since handles are hidden */
1302                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1303                         } else {
1304                                 if (beztindex==0) {
1305                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1306                                 } else if (beztindex==1) {
1307                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1308                                 } else {
1309                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1310                                 }
1311                         }
1312                 }
1313         }
1314 }
1315 static void do_nurbs_box_select(ViewContext *vc, rcti *rect, int select, int extend)
1316 {
1317         struct { ViewContext vc; rcti *rect; int select; } data;
1318         
1319         data.vc = *vc;
1320         data.rect = rect;
1321         data.select = select;
1322
1323         if (extend == 0 && select) {
1324                 CU_deselect_all(vc->obedit);
1325         }
1326
1327         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1328         nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data);
1329 }
1330
1331 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1332 {
1333         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1334
1335         if (BLI_in_rcti(data->rect, x, y)) {
1336                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1337         }
1338 }
1339 static void do_lattice_box_select(ViewContext *vc, rcti *rect, int select, int extend)
1340 {
1341         struct { ViewContext vc; rcti *rect; int select, pass, done; } data;
1342
1343         data.vc= *vc;
1344         data.rect = rect;
1345         data.select = select;
1346
1347         if (extend == 0 && select) {
1348                 ED_setflagsLatt(vc->obedit, 0);
1349         }
1350
1351         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1352         lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data);
1353 }
1354
1355 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1356 {
1357         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1358
1359         if (BLI_in_rcti(data->rect, x, y)) {
1360                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1361         }
1362 }
1363 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1364 {
1365         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1366
1367         if(EM_check_backbuf(em_solidoffs+index)) {
1368                 if (data->pass==0) {
1369                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1370                                 EM_select_edge(eed, data->select);
1371                                 data->done = 1;
1372                         }
1373                 } else {
1374                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1375                                 EM_select_edge(eed, data->select);
1376                         }
1377                 }
1378         }
1379 }
1380 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1381 {
1382         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1383
1384         if (BLI_in_rcti(data->rect, x, y)) {
1385                 EM_select_face_fgon(data->vc.em, efa, data->select);
1386         }
1387 }
1388 static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select, int extend)
1389 {
1390         struct { ViewContext vc; rcti *rect; short select, pass, done; } data;
1391         ToolSettings *ts= vc->scene->toolsettings;
1392         int bbsel;
1393         
1394         data.vc= *vc;
1395         data.rect = rect;
1396         data.select = select;
1397         data.pass = 0;
1398         data.done = 0;
1399
1400         if (extend == 0 && select)
1401         {
1402                 EM_deselect_all(vc->em);
1403         }
1404
1405         /* workaround: init mats first, EM_mask_init_backbuf_border can change
1406            view matrix to pixel space, breaking edge select with backbuf. fixes bug #20936 */
1407         /*ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);*/ /* for foreach's screen/vert projection */
1408
1409         /* [#21018] breaks zbuf select. run below. only if bbsel fails */
1410         /* ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d) */
1411
1412         glLoadMatrixf(vc->rv3d->viewmat);
1413         bbsel= EM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1414
1415         if(ts->selectmode & SCE_SELECT_VERTEX) {
1416                 if (bbsel) {
1417                         EM_backbuf_checkAndSelectVerts(vc->em, select);
1418                 } else {
1419                         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
1420                         mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1);
1421                 }
1422         }
1423         if(ts->selectmode & SCE_SELECT_EDGE) {
1424                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1425
1426                 data.pass = 0;
1427                 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1428
1429                 if (data.done==0) {
1430                         data.pass = 1;
1431                         mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1432                 }
1433         }
1434         
1435         if(ts->selectmode & SCE_SELECT_FACE) {
1436                 if(bbsel) {
1437                         EM_backbuf_checkAndSelectFaces(vc->em, select);
1438                 } else {
1439                         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
1440                         mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data);
1441                 }
1442         }
1443         
1444         EM_free_backbuf();
1445                 
1446         EM_selectmode_flush(vc->em);
1447 }
1448
1449 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
1450 {
1451         ViewContext vc;
1452         Scene *scene= CTX_data_scene(C);
1453         ScrArea *sa= CTX_wm_area(C);
1454         View3D *v3d= sa->spacedata.first;
1455         Object *obedit= CTX_data_edit_object(C);
1456         Object *obact= CTX_data_active_object(C);
1457         rcti rect;
1458         Base *base;
1459         MetaElem *ml;
1460         unsigned int buffer[4*MAXPICKBUF];
1461         int a, index;
1462         int extend;
1463         short hits, selecting;
1464
1465         view3d_operator_needs_opengl(C);
1466         
1467         /* setup view context for argument to callbacks */
1468         view3d_set_viewcontext(C, &vc);
1469         
1470         selecting= (RNA_int_get(op->ptr, "gesture_mode")==GESTURE_MODAL_SELECT);
1471         rect.xmin= RNA_int_get(op->ptr, "xmin");
1472         rect.ymin= RNA_int_get(op->ptr, "ymin");
1473         rect.xmax= RNA_int_get(op->ptr, "xmax");
1474         rect.ymax= RNA_int_get(op->ptr, "ymax");
1475         extend = RNA_boolean_get(op->ptr, "extend");
1476
1477         if(obedit==NULL && (paint_facesel_test(OBACT))) {
1478                 face_borderselect(C, obact, &rect, selecting, extend);
1479                 return OPERATOR_FINISHED;
1480         }
1481         else if(obedit==NULL && (obact && obact->mode & OB_MODE_PARTICLE_EDIT)) {
1482                 return PE_border_select(C, &rect, selecting, extend);
1483         }
1484         else if(obedit==NULL && (obact && obact->mode & OB_MODE_SCULPT))
1485                 return OPERATOR_CANCELLED;
1486         
1487         if(obedit) {
1488                 if(obedit->type==OB_MESH) {
1489                         Mesh *me= obedit->data;
1490                         vc.em= me->edit_mesh;
1491                         do_mesh_box_select(&vc, &rect, selecting, extend);
1492 //                      if (EM_texFaceCheck())
1493                         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
1494                         
1495                 }
1496                 else if(ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1497                         do_nurbs_box_select(&vc, &rect, selecting, extend);
1498                 }
1499                 else if(obedit->type==OB_MBALL) {
1500                         MetaBall *mb = (MetaBall*)obedit->data;
1501                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1502                         
1503                         if (extend == 0 && selecting) {
1504                                 ml= mb->editelems->first;
1505
1506                                 while(ml) {
1507                                         ml->flag &= ~SELECT;
1508                                         ml= ml->next;
1509                                 }
1510                         }
1511
1512                         ml= mb->editelems->first;
1513                         
1514                         while(ml) {
1515                                 for(a=0; a<hits; a++) {
1516                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1517                                                 ml->flag |= MB_SCALE_RAD;
1518                                                 if(selecting)   ml->flag |= SELECT;
1519                                                 else                    ml->flag &= ~SELECT;
1520                                                 break;
1521                                         }
1522                                         if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1523                                                 ml->flag &= ~MB_SCALE_RAD;
1524                                                 if(selecting)   ml->flag |= SELECT;
1525                                                 else                    ml->flag &= ~SELECT;
1526                                                 break;
1527                                         }
1528                                 }
1529                                 ml= ml->next;
1530                         }
1531                 }
1532                 else if(obedit->type==OB_ARMATURE) {
1533                         bArmature *arm= obedit->data;
1534                         EditBone *ebone;
1535                         
1536                         /* clear flag we use to detect point was affected */
1537                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next)
1538                                 ebone->flag &= ~BONE_DONE;
1539                         
1540                         if (extend==0 && selecting) {
1541                                 /*      Set the flags */
1542                                 CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones) {
1543                                         /* ignore bone if selection can't change */
1544                                         if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
1545                                                 ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
1546                                         }
1547                                 }
1548                                 CTX_DATA_END;
1549                         }
1550
1551                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1552                         
1553                         /* first we only check points inside the border */
1554                         for (a=0; a<hits; a++){
1555                                 index = buffer[(4*a)+3];
1556                                 if (index!=-1) {
1557                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1558                                         if (index & BONESEL_TIP) {
1559                                                 ebone->flag |= BONE_DONE;
1560                                                 if (selecting)  ebone->flag |= BONE_TIPSEL;
1561                                                 else                    ebone->flag &= ~BONE_TIPSEL;
1562                                         }
1563                                         
1564                                         if (index & BONESEL_ROOT) {
1565                                                 ebone->flag |= BONE_DONE;
1566                                                 if (selecting)  ebone->flag |= BONE_ROOTSEL;
1567                                                 else                    ebone->flag &= ~BONE_ROOTSEL;
1568                                         }
1569                                 }
1570                         }
1571                         
1572                         /* now we have to flush tag from parents... */
1573                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next) {
1574                                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1575                                         if(ebone->parent->flag & BONE_DONE)
1576                                                 ebone->flag |= BONE_DONE;
1577                                 }
1578                         }
1579                         
1580                         /* only select/deselect entire bones when no points where in the rect */
1581                         for (a=0; a<hits; a++){
1582                                 index = buffer[(4*a)+3];
1583                                 if (index!=-1) {
1584                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1585                                         if (index & BONESEL_BONE) {
1586                                                 if(!(ebone->flag & BONE_DONE)) {
1587                                                         if (selecting)
1588                                                                 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1589                                                         else
1590                                                                 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1591                                                 }
1592                                         }
1593                                 }
1594                         }
1595                         
1596                         ED_armature_sync_selection(arm->edbo);
1597                 }
1598                 else if(obedit->type==OB_LATTICE) {
1599                         do_lattice_box_select(&vc, &rect, selecting, extend);
1600                 }
1601         }
1602         else {  /* no editmode, unified for bones and objects */
1603                 Bone *bone;
1604                 Object *ob= OBACT;
1605                 unsigned int *vbuffer=NULL; /* selection buffer */
1606                 unsigned int *col;                      /* color in buffer      */
1607                 int bone_only;
1608                 int totobj= MAXPICKBUF; // XXX solve later
1609                 
1610                 if((ob) && (ob->mode & OB_MODE_POSE))
1611                         bone_only= 1;
1612                 else
1613                         bone_only= 0;
1614                 
1615                 if (extend == 0 && selecting) {
1616                         base= FIRSTBASE;
1617
1618                         if (bone_only) {
1619                                 CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) {
1620                                         pchan->bone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
1621                                 }
1622                                 CTX_DATA_END;
1623                         } else {
1624                                 while(base) {
1625                                         Base *next = base->next;
1626                                         if(base->lay & v3d->lay) {
1627                                                 ED_base_object_select(base, BA_DESELECT);
1628                                         }
1629                                         base= next;
1630                                 }
1631                         }
1632                 }
1633
1634                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1635                 vbuffer = MEM_mallocN(4 * (totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1636                 hits= view3d_opengl_select(&vc, vbuffer, 4*(totobj+MAXPICKBUF), &rect);
1637                 /*
1638                 LOGIC NOTES (theeth):
1639                 The buffer and ListBase have the same relative order, which makes the selection
1640                 very simple. Loop through both data sets at the same time, if the color
1641                 is the same as the object, we have a hit and can move to the next color
1642                 and object pair, if not, just move to the next object,
1643                 keeping the same color until we have a hit.
1644
1645                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1646                 does it incorrectly.
1647                 */
1648
1649                 if (hits>0) { /* no need to loop if there's no hit */
1650                         base= FIRSTBASE;
1651                         col = vbuffer + 3;
1652                         
1653                         while(base && hits) {
1654                                 Base *next = base->next;
1655                                 if(base->lay & v3d->lay) {
1656                                         while (base->selcol == (*col & 0xFFFF)) {       /* we got an object */
1657                                                 
1658                                                 if(*col & 0xFFFF0000) {                                 /* we got a bone */
1659                                                         bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1660                                                         if(bone) {
1661                                                                 if(selecting) {
1662                                                                         bone->flag |= BONE_SELECTED;
1663 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 1);
1664                                                                 }
1665                                                                 else {
1666                                                                         bArmature *arm= base->object->data;
1667                                                                         bone->flag &= ~BONE_SELECTED;
1668 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 0);
1669                                                                         if(arm->act_bone==bone)
1670                                                                                 arm->act_bone= NULL;
1671                                                                         
1672                                                                 }
1673                                                         }
1674                                                 }
1675                                                 else if(!bone_only) {
1676                                                         if (selecting)
1677                                                                 ED_base_object_select(base, BA_SELECT);
1678                                                         else
1679                                                                 ED_base_object_select(base, BA_DESELECT);
1680                                                 }
1681
1682                                                 col+=4; /* next color */
1683                                                 hits--;
1684                                                 if(hits==0) break;
1685                                         }
1686                                 }
1687                                 
1688                                 base= next;
1689                         }
1690
1691                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1692
1693                 }
1694                 MEM_freeN(vbuffer);
1695         }
1696         return OPERATOR_FINISHED;
1697
1698
1699
1700 /* *****************Selection Operators******************* */
1701
1702 /* ****** Border Select ****** */
1703 void VIEW3D_OT_select_border(wmOperatorType *ot)
1704 {
1705         /* identifiers */
1706         ot->name= "Border Select";
1707         ot->description= "Select items using border selection";
1708         ot->idname= "VIEW3D_OT_select_border";
1709         
1710         /* api callbacks */
1711         ot->invoke= WM_border_select_invoke;
1712         ot->exec= view3d_borderselect_exec;
1713         ot->modal= WM_border_select_modal;
1714         
1715         ot->poll= ED_operator_view3d_active;
1716         
1717         /* flags */
1718         ot->flag= OPTYPE_UNDO;
1719         
1720         /* rna */
1721         WM_operator_properties_gesture_border(ot, TRUE);
1722 }
1723
1724 /* ****** Mouse Select ****** */
1725
1726
1727 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1728 {
1729         Object *obedit= CTX_data_edit_object(C);
1730         Object *obact= CTX_data_active_object(C);
1731         short extend= RNA_boolean_get(op->ptr, "extend");
1732         short center= RNA_boolean_get(op->ptr, "center");
1733         short enumerate= RNA_boolean_get(op->ptr, "enumerate");
1734         int     retval = 0;
1735
1736         view3d_operator_needs_opengl(C);
1737         
1738         if(obedit) {
1739                 if(obedit->type==OB_MESH)
1740                         retval = mouse_mesh(C, event->mval, extend);
1741                 else if(obedit->type==OB_ARMATURE)
1742                         retval = mouse_armature(C, event->mval, extend);
1743                 else if(obedit->type==OB_LATTICE)
1744                         retval = mouse_lattice(C, event->mval, extend);
1745                 else if(ELEM(obedit->type, OB_CURVE, OB_SURF))
1746                         retval = mouse_nurb(C, event->mval, extend);
1747                 else if(obedit->type==OB_MBALL)
1748                         retval = mouse_mball(C, event->mval, extend);
1749                         
1750         }
1751         else if(obact && obact->mode & OB_MODE_SCULPT)
1752                 return OPERATOR_CANCELLED;
1753         else if(obact && obact->mode & OB_MODE_PARTICLE_EDIT)
1754                 return PE_mouse_particles(C, event->mval, extend);
1755         else if(obact && paint_facesel_test(obact))
1756                 retval = face_select(C, obact, event->mval, extend);
1757         else
1758                 retval = mouse_select(C, event->mval, extend, center, enumerate);
1759
1760         /* passthrough allows tweaks
1761          * FINISHED to signal one operator worked
1762          * */
1763         if (retval)
1764                 return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED;
1765         else
1766                 return OPERATOR_PASS_THROUGH; /* nothing selected, just passthrough */
1767 }
1768
1769 void VIEW3D_OT_select(wmOperatorType *ot)
1770 {
1771         /* identifiers */
1772         ot->name= "Activate/Select";
1773         ot->description= "Activate/select item(s)";
1774         ot->idname= "VIEW3D_OT_select";
1775         
1776         /* api callbacks */
1777         ot->invoke= view3d_select_invoke;
1778         ot->poll= ED_operator_view3d_active;
1779         
1780         /* flags */
1781         ot->flag= OPTYPE_UNDO;
1782         
1783         /* properties */
1784         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first.");
1785         RNA_def_boolean(ot->srna, "center", 0, "Center", "Use the object center when selecting (object mode only).");
1786         RNA_def_boolean(ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only).");
1787 }
1788
1789
1790 /* -------------------- circle select --------------------------------------------- */
1791
1792 static void mesh_circle_doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1793 {
1794         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1795         int mx = x - data->mval[0], my = y - data->mval[1];
1796         float r = sqrt(mx*mx + my*my);
1797
1798         if (r<=data->radius) {
1799                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1800         }
1801 }
1802 static void mesh_circle_doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1803 {
1804         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1805
1806         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1807                 EM_select_edge(eed, data->select);
1808         }
1809 }
1810 static void mesh_circle_doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1811 {
1812         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1813         int mx = x - data->mval[0], my = y - data->mval[1];
1814         float r = sqrt(mx*mx + my*my);
1815         
1816         if (r<=data->radius) {
1817                 EM_select_face_fgon(data->vc->em, efa, data->select);
1818         }
1819 }
1820
1821 static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1822 {
1823         ToolSettings *ts= vc->scene->toolsettings;
1824         int bbsel;
1825         Object *ob= vc->obact;
1826         
1827         if(vc->obedit==NULL && paint_facesel_test(ob)) {
1828                 Mesh *me = ob?ob->data:NULL;
1829
1830                 if (me) {
1831                         em_vertoffs= me->totface+1;     /* max index array */
1832
1833                         bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1834                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1835                         EM_free_backbuf();
1836
1837 // XXX                  object_tface_flags_changed(OBACT, 0);
1838                 }
1839         }
1840         else {
1841                 struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1842                 
1843                 bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1844                 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1845
1846                 vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
1847
1848                 data.vc = vc;
1849                 data.select = selecting;
1850                 data.mval[0] = mval[0];
1851                 data.mval[1] = mval[1];
1852                 data.radius = rad;
1853
1854                 if(ts->selectmode & SCE_SELECT_VERTEX) {
1855                         if(bbsel) {
1856                                 EM_backbuf_checkAndSelectVerts(vc->em, selecting==LEFTMOUSE);
1857                         } else {
1858                                 mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, 1);
1859                         }
1860                 }
1861
1862                 if(ts->selectmode & SCE_SELECT_EDGE) {
1863                         if (bbsel) {
1864                                 EM_backbuf_checkAndSelectEdges(vc->em, selecting==LEFTMOUSE);
1865                         } else {
1866                                 mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, 0);
1867                         }
1868                 }
1869                 
1870                 if(ts->selectmode & SCE_SELECT_FACE) {
1871                         if(bbsel) {
1872                                 EM_backbuf_checkAndSelectFaces(vc->em, selecting==LEFTMOUSE);
1873                         } else {
1874                                 mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data);
1875                         }
1876                 }
1877
1878                 EM_free_backbuf();
1879                 EM_selectmode_flush(vc->em);
1880         }
1881 }
1882
1883
1884 static void nurbscurve_circle_doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1885 {
1886         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1887         int mx = x - data->mval[0], my = y - data->mval[1];
1888         float r = sqrt(mx*mx + my*my);
1889
1890         if (r<=data->radius) {
1891                 if (bp) {
1892                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1893                 } else {
1894                         if (beztindex==0) {
1895                                 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1896                         } else if (beztindex==1) {
1897                                 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1898                         } else {
1899                                 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1900                         }
1901                 }
1902         }
1903 }
1904 static void nurbscurve_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1905 {
1906         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1907
1908         /* set vc-> edit data */
1909         
1910         data.select = selecting;
1911         data.mval[0] = mval[0];
1912         data.mval[1] = mval[1];
1913         data.radius = rad;
1914
1915         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1916         nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data);
1917 }
1918
1919
1920 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, int x, int y)
1921 {
1922         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1923         int mx = x - data->mval[0], my = y - data->mval[1];
1924         float r = sqrt(mx*mx + my*my);
1925
1926         if (r<=data->radius) {
1927                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1928         }
1929 }
1930 static void lattice_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1931 {
1932         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1933
1934         /* set vc-> edit data */
1935         
1936         data.select = selecting;
1937         data.mval[0] = mval[0];
1938         data.mval[1] = mval[1];
1939         data.radius = rad;
1940
1941         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1942         lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data);
1943 }
1944
1945
1946 static short armature_circle_doSelectJoint(void *userData, EditBone *ebone, int x, int y, short head)
1947 {
1948         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1949         int mx = x - data->mval[0], my = y - data->mval[1];
1950         float r = sqrt(mx*mx + my*my);
1951         
1952         if (r <= data->radius) {
1953                 if (head) {
1954                         if (data->select)
1955                                 ebone->flag |= BONE_ROOTSEL;
1956                         else 
1957                                 ebone->flag &= ~BONE_ROOTSEL;
1958                 }
1959                 else {
1960                         if (data->select)
1961                                 ebone->flag |= BONE_TIPSEL;
1962                         else 
1963                                 ebone->flag &= ~BONE_TIPSEL;
1964                 }
1965                 return 1;
1966         }
1967         return 0;
1968 }
1969 static void armature_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1970 {
1971         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1972         bArmature *arm= vc->obedit->data;
1973         EditBone *ebone;
1974         
1975         /* set vc->edit data */
1976         data.select = selecting;
1977         data.mval[0] = mval[0];
1978         data.mval[1] = mval[1];
1979         data.radius = rad;
1980
1981         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1982         
1983         /* check each EditBone... */
1984         // TODO: could be optimised at some point
1985         for (ebone= arm->edbo->first; ebone; ebone=ebone->next) {
1986                 short sco1[2], sco2[2], didpoint=0;
1987                 float vec[3];
1988                 
1989                 /* project head location to screenspace */
1990                 VECCOPY(vec, ebone->head);
1991                 mul_m4_v3(vc->obedit->obmat, vec);
1992                 project_short(vc->ar, vec, sco1);
1993                 
1994                 /* project tail location to screenspace */
1995                 VECCOPY(vec, ebone->tail);
1996                 mul_m4_v3(vc->obedit->obmat, vec);
1997                 project_short(vc->ar, vec, sco2);
1998                 
1999                 /* check if the head and/or tail is in the circle 
2000                  *      - the call to check also does the selection already
2001                  */
2002                 if (armature_circle_doSelectJoint(&data, ebone, sco1[0], sco1[1], 1))
2003                         didpoint= 1;
2004                 if (armature_circle_doSelectJoint(&data, ebone, sco2[0], sco2[1], 0))
2005                         didpoint= 1;
2006                         
2007                 /* only if the endpoints didn't get selected, deal with the middle of the bone too */
2008                 // XXX should we just do this always?
2009                 if ( (didpoint==0) && edge_inside_circle(mval[0], mval[1], rad, sco1[0], sco1[1], sco2[0], sco2[1]) ) {
2010                         if (selecting) 
2011                                 ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
2012                         else 
2013                                 ebone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
2014                 }
2015         }
2016
2017         ED_armature_validate_active(arm);
2018 }
2019
2020 /** Callbacks for circle selection in Editmode */
2021
2022 static void obedit_circle_select(ViewContext *vc, short selecting, short *mval, float rad) 
2023 {
2024         switch(vc->obedit->type) {              
2025         case OB_MESH:
2026                 mesh_circle_select(vc, selecting, mval, rad);
2027                 break;
2028         case OB_CURVE:
2029         case OB_SURF:
2030                 nurbscurve_circle_select(vc, selecting, mval, rad);
2031                 break;
2032         case OB_LATTICE:
2033                 lattice_circle_select(vc, selecting, mval, rad);
2034                 break;
2035         case OB_ARMATURE:
2036                 armature_circle_select(vc, selecting, mval, rad);
2037                 break;
2038         default:
2039                 return;
2040         }
2041 }
2042
2043 /* not a real operator, only for circle test */
2044 static int view3d_circle_select_exec(bContext *C, wmOperator *op)
2045 {
2046         ScrArea *sa= CTX_wm_area(C);
2047         ARegion *ar= CTX_wm_region(C);
2048         Scene *scene= CTX_data_scene(C);
2049         Object *obact= CTX_data_active_object(C);
2050         View3D *v3d= sa->spacedata.first;
2051         int x= RNA_int_get(op->ptr, "x");
2052         int y= RNA_int_get(op->ptr, "y");
2053         int radius= RNA_int_get(op->ptr, "radius");
2054     int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
2055     int selecting;
2056         
2057     selecting= (gesture_mode==GESTURE_MODAL_SELECT);
2058     
2059         if(CTX_data_edit_object(C) || (obact && obact->mode & OB_MODE_PARTICLE_EDIT)) {
2060                 ViewContext vc;
2061                 short mval[2];
2062                 
2063                 view3d_operator_needs_opengl(C);
2064                 
2065                 view3d_set_viewcontext(C, &vc);
2066                 mval[0]= x;
2067                 mval[1]= y;
2068
2069                 if(CTX_data_edit_object(C)) {
2070                         obedit_circle_select(&vc, selecting, mval, (float)radius);
2071                         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obact->data);
2072                 }
2073                 else
2074                         return PE_circle_select(C, selecting, mval, (float)radius);
2075         }
2076         else if(obact && obact->mode & OB_MODE_SCULPT) {
2077                 return OPERATOR_CANCELLED;
2078         }
2079         else {
2080                 Base *base;
2081                 selecting= selecting?BA_SELECT:BA_DESELECT;
2082                 for(base= FIRSTBASE; base; base= base->next) {
2083                         if(base->lay & v3d->lay) {
2084                                 project_short(ar, base->object->obmat[3], &base->sx);
2085                                 if(base->sx!=IS_CLIPPED) {
2086                                         int dx= base->sx-x;
2087                                         int dy= base->sy-y;
2088                                         if( dx*dx + dy*dy < radius*radius)
2089                                                 ED_base_object_select(base, selecting);
2090                                 }
2091                         }
2092                 }
2093                 
2094                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
2095         }
2096         
2097         return OPERATOR_FINISHED;
2098 }
2099
2100 void VIEW3D_OT_select_circle(wmOperatorType *ot)
2101 {
2102         ot->name= "Circle Select";
2103         ot->description= "Select items using circle selection";
2104         ot->idname= "VIEW3D_OT_select_circle";
2105         
2106         ot->invoke= WM_gesture_circle_invoke;
2107         ot->modal= WM_gesture_circle_modal;
2108         ot->exec= view3d_circle_select_exec;
2109         ot->poll= ED_operator_view3d_active;
2110         
2111         /* flags */
2112         ot->flag= OPTYPE_UNDO;
2113         
2114         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
2115         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
2116         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
2117         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2118 }