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