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