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