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