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