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