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