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