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