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