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