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