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