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