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