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