Fix for [#22741] Material preview doesn't update when "undo" is used to revert a...
[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         }
730         else { /* Edit Mode */
731                 if(vc->obedit->type==OB_MESH)
732                         do_lasso_select_mesh(vc, mcords, moves, select);
733                 else if(vc->obedit->type==OB_CURVE || vc->obedit->type==OB_SURF) 
734                         do_lasso_select_curve(vc, mcords, moves, select);
735                 else if(vc->obedit->type==OB_LATTICE) 
736                         do_lasso_select_lattice(vc, mcords, moves, select);
737                 else if(vc->obedit->type==OB_ARMATURE)
738                         do_lasso_select_armature(vc, mcords, moves, select);
739         
740                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc->obedit->data);
741         }
742 }
743
744
745 /* lasso operator gives properties, but since old code works
746    with short array we convert */
747 static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
748 {
749         ViewContext vc;
750         int select, i= 0;
751         short mcords[1024][2];
752
753         RNA_BEGIN(op->ptr, itemptr, "path") {
754                 float loc[2];
755                 
756                 RNA_float_get_array(&itemptr, "loc", loc);
757                 mcords[i][0]= (short)loc[0];
758                 mcords[i][1]= (short)loc[1];
759                 i++;
760                 if(i>=1024) break;
761         }
762         RNA_END;
763         
764         if(i>1) {
765                 view3d_operator_needs_opengl(C);
766                 
767                 /* setup view context for argument to callbacks */
768                 view3d_set_viewcontext(C, &vc);
769                 
770                 select= !RNA_boolean_get(op->ptr, "deselect");
771                 view3d_lasso_select(C, &vc, mcords, i, select);
772                 
773                 return OPERATOR_FINISHED;
774         }
775         return OPERATOR_PASS_THROUGH;
776 }
777
778 void VIEW3D_OT_select_lasso(wmOperatorType *ot)
779 {
780         ot->name= "Lasso Select";
781         ot->description= "Select items using lasso selection";
782         ot->idname= "VIEW3D_OT_select_lasso";
783         
784         ot->invoke= WM_gesture_lasso_invoke;
785         ot->modal= WM_gesture_lasso_modal;
786         ot->exec= view3d_lasso_select_exec;
787         ot->poll= view3d_selectable_data;
788         
789         /* flags */
790         ot->flag= OPTYPE_UNDO;
791         
792         RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
793         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items.");
794 }
795
796
797 /* ************************************************* */
798
799 #if 0
800 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
801 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
802 {
803         Base *base;
804         unsigned int *bufmin,*bufmax;
805         int a,b,rc,tel,aantal,dirvec[4][2],maxob;
806         unsigned int retval=0;
807         
808         base= LASTBASE;
809         if(base==0) return 0;
810         maxob= base->selcol;
811
812         aantal= (size-1)/2;
813         rc= 0;
814
815         dirvec[0][0]= 1;
816         dirvec[0][1]= 0;
817         dirvec[1][0]= 0;
818         dirvec[1][1]= -size;
819         dirvec[2][0]= -1;
820         dirvec[2][1]= 0;
821         dirvec[3][0]= 0;
822         dirvec[3][1]= size;
823
824         bufmin= buf;
825         bufmax= buf+ size*size;
826         buf+= aantal*size+ aantal;
827
828         for(tel=1;tel<=size;tel++) {
829
830                 for(a=0;a<2;a++) {
831                         for(b=0;b<tel;b++) {
832
833                                 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
834                                 if( *buf==dontdo ) retval= dontdo;      /* if only color dontdo is available, still return dontdo */
835                                 
836                                 buf+= (dirvec[rc][0]+dirvec[rc][1]);
837
838                                 if(buf<bufmin || buf>=bufmax) return retval;
839                         }
840                         rc++;
841                         rc &= 3;
842                 }
843         }
844         return retval;
845 }
846 #endif
847
848 /* ************************** mouse select ************************* */
849
850
851 /* The max number of menu items in an object select menu */
852 #define SEL_MENU_SIZE   22
853
854 static void deselectall_except(Scene *scene, Base *b)   /* deselect all except b */
855 {
856         Base *base;
857         
858         for(base= FIRSTBASE; base; base= base->next) {
859                 if (base->flag & SELECT) {
860                         if(b!=base) {
861                                 ED_base_object_select(base, BA_DESELECT);
862                         }
863                 }
864         }
865 }
866
867 static Base *mouse_select_menu(bContext *C, ViewContext *vc, unsigned int *buffer, int hits, short *mval, short extend)
868 {
869         short baseCount = 0;
870         short ok;
871         LinkNode *linklist= NULL;
872         
873         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
874                 ok= FALSE;
875
876                 /* two selection methods, the CTRL select uses max dist of 15 */
877                 if(buffer) {
878                         int a;
879                         for(a=0; a<hits; a++) {
880                                 /* index was converted */
881                                 if(base->selcol==buffer[ (4 * a) + 3 ])
882                                         ok= TRUE;
883                         }
884                 }
885                 else {
886                         int temp, dist=15;
887
888                         project_short(vc->ar, base->object->obmat[3], &base->sx);
889                         
890                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
891                         if(temp < dist)
892                                 ok= TRUE;
893                 }
894
895                 if(ok) {
896                         baseCount++;
897                         BLI_linklist_prepend(&linklist, base);
898
899                         if (baseCount==SEL_MENU_SIZE)
900                                 break;
901                 }
902         }
903         CTX_DATA_END;
904
905         if(baseCount)
906
907
908         if(baseCount==0) {
909                 return NULL;
910         }
911         if(baseCount == 1) {
912                 Base *base= (Base *)linklist->link;
913                 BLI_linklist_free(linklist, NULL);
914                 return base;
915         }
916         else {
917                 /* UI */
918                 uiPopupMenu *pup= uiPupMenuBegin(C, "Select Object", 0);
919                 uiLayout *layout= uiPupMenuLayout(pup);
920                 uiLayout *split= uiLayoutSplit(layout, 0, 0);
921                 uiLayout *column= uiLayoutColumn(split, 0);
922                 LinkNode *node;
923
924                 node= linklist;
925                 while(node) {
926                         Base *base=node->link;
927                         Object *ob= base->object;
928                         char *name= ob->id.name+2;
929                         /* annoying!, since we need to set 2 props cant use this. */
930                         /* uiItemStringO(column, name, 0, "OBJECT_OT_select_name", "name", name); */
931
932                         {
933                                 PointerRNA ptr;
934
935                                 WM_operator_properties_create(&ptr, "OBJECT_OT_select_name");
936                                 RNA_string_set(&ptr, "name", name);
937                                 RNA_boolean_set(&ptr, "extend", extend);
938                                 uiItemFullO(column, "OBJECT_OT_select_name", name, uiIconFromID((ID *)ob), ptr.data, WM_OP_EXEC_DEFAULT, 0);
939                         }
940
941                         node= node->next;
942                 }
943
944                 uiPupMenuEnd(C, pup);
945
946                 BLI_linklist_free(linklist, NULL);
947                 return NULL;
948         }
949 }
950
951 /* we want a select buffer with bones, if there are... */
952 /* so check three selection levels and compare */
953 static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, short *mval)
954 {
955         rcti rect;
956         int offs;
957         short a, hits15, hits9=0, hits5=0;
958         short has_bones15=0, has_bones9=0, has_bones5=0;
959         
960         BLI_init_rcti(&rect, mval[0]-14, mval[0]+14, mval[1]-14, mval[1]+14);
961         hits15= view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
962         if(hits15>0) {
963                 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
964                 
965                 offs= 4*hits15;
966                 BLI_init_rcti(&rect, mval[0]-9, mval[0]+9, mval[1]-9, mval[1]+9);
967                 hits9= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
968                 if(hits9>0) {
969                         for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
970                         
971                         offs+= 4*hits9;
972                         BLI_init_rcti(&rect, mval[0]-5, mval[0]+5, mval[1]-5, mval[1]+5);
973                         hits5= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
974                         if(hits5>0) {
975                                 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
976                         }
977                 }
978                 
979                 if(has_bones5) {
980                         offs= 4*hits15 + 4*hits9;
981                         memcpy(buffer, buffer+offs, 4*offs);
982                         return hits5;
983                 }
984                 if(has_bones9) {
985                         offs= 4*hits15;
986                         memcpy(buffer, buffer+offs, 4*offs);
987                         return hits9;
988                 }
989                 if(has_bones15) {
990                         return hits15;
991                 }
992                 
993                 if(hits5>0) {
994                         offs= 4*hits15 + 4*hits9;
995                         memcpy(buffer, buffer+offs, 4*offs);
996                         return hits5;
997                 }
998                 if(hits9>0) {
999                         offs= 4*hits15;
1000                         memcpy(buffer, buffer+offs, 4*offs);
1001                         return hits9;
1002                 }
1003                 return hits15;
1004         }
1005         
1006         return 0;
1007 }
1008
1009 /* returns basact */
1010 static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits, short *mval, Base *startbase, int has_bones)
1011 {
1012         Scene *scene= vc->scene;
1013         View3D *v3d= vc->v3d;
1014         Base *base, *basact= NULL;
1015         static short lastmval[2]={-100, -100};
1016         int a, donearest= 0;
1017         
1018         /* define if we use solid nearest select or not */
1019         if(v3d->drawtype>OB_WIRE) {
1020                 donearest= 1;
1021                 if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
1022                         if(!has_bones)  /* hrms, if theres bones we always do nearest */
1023                                 donearest= 0;
1024                 }
1025         }
1026         lastmval[0]= mval[0]; lastmval[1]= mval[1];
1027         
1028         if(donearest) {
1029                 unsigned int min= 0xFFFFFFFF;
1030                 int selcol= 0, notcol=0;
1031                 
1032                 
1033                 if(has_bones) {
1034                         /* we skip non-bone hits */
1035                         for(a=0; a<hits; a++) {
1036                                 if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
1037                                         min= buffer[4*a+1];
1038                                         selcol= buffer[4*a+3] & 0xFFFF;
1039                                 }
1040                         }
1041                 }
1042                 else {
1043                         /* only exclude active object when it is selected... */
1044                         if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol; 
1045                         
1046                         for(a=0; a<hits; a++) {
1047                                 if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1048                                         min= buffer[4*a+1];
1049                                         selcol= buffer[4*a+3] & 0xFFFF;
1050                                 }
1051                         }
1052                 }
1053                 
1054                 base= FIRSTBASE;
1055                 while(base) {
1056                         if(base->lay & v3d->lay) {
1057                                 if(base->selcol==selcol) break;
1058                         }
1059                         base= base->next;
1060                 }
1061                 if(base) basact= base;
1062         }
1063         else {
1064                 
1065                 base= startbase;
1066                 while(base) {
1067                         /* skip objects with select restriction, to prevent prematurely ending this loop
1068                         * with an un-selectable choice */
1069                         if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1070                                 base=base->next;
1071                                 if(base==NULL) base= FIRSTBASE;
1072                                 if(base==startbase) break;
1073                         }
1074                         
1075                         if(base->lay & v3d->lay) {
1076                                 for(a=0; a<hits; a++) {
1077                                         if(has_bones) {
1078                                                 /* skip non-bone objects */
1079                                                 if((buffer[4*a+3] & 0xFFFF0000)) {
1080                                                         if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1081                                                                 basact= base;
1082                                                 }
1083                                         }
1084                                         else {
1085                                                 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1086                                                         basact= base;
1087                                         }
1088                                 }
1089                         }
1090                         
1091                         if(basact) break;
1092                         
1093                         base= base->next;
1094                         if(base==NULL) base= FIRSTBASE;
1095                         if(base==startbase) break;
1096                 }
1097         }
1098         
1099         return basact;
1100 }
1101
1102 /* mval comes from event->mval, only use within region handlers */
1103 Base *ED_view3d_give_base_under_cursor(bContext *C, short *mval)
1104 {
1105         ViewContext vc;
1106         Base *basact= NULL;
1107         unsigned int buffer[4*MAXPICKBUF];
1108         int hits;
1109         
1110         /* setup view context for argument to callbacks */
1111         view3d_operator_needs_opengl(C);
1112         view3d_set_viewcontext(C, &vc);
1113         
1114         hits= mixed_bones_object_selectbuffer(&vc, buffer, mval);
1115         
1116         if(hits>0) {
1117                 int a, has_bones= 0;
1118                 
1119                 for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1120                 
1121                 basact= mouse_select_eval_buffer(&vc, buffer, hits, mval, vc.scene->base.first, has_bones);
1122         }
1123         
1124         return basact;
1125 }
1126
1127 /* mval is region coords */
1128 static int mouse_select(bContext *C, short *mval, short extend, short obcenter, short enumerate)
1129 {
1130         ViewContext vc;
1131         ARegion *ar= CTX_wm_region(C);
1132         View3D *v3d= CTX_wm_view3d(C);
1133         Scene *scene= CTX_data_scene(C);
1134         Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
1135         int temp, a, dist=100;
1136         int retval = 0;
1137         short hits;
1138         
1139         /* setup view context for argument to callbacks */
1140         view3d_set_viewcontext(C, &vc);
1141         
1142         /* always start list from basact in wire mode */
1143         startbase=  FIRSTBASE;
1144         if(BASACT && BASACT->next) startbase= BASACT->next;
1145         
1146         /* This block uses the control key to make the object selected by its center point rather then its contents */
1147         /* XXX later on, in editmode do not activate */
1148         if(vc.obedit==NULL && obcenter) {
1149                 
1150                 /* note; shift+alt goes to group-flush-selecting */
1151                 if(enumerate) {
1152                         basact= mouse_select_menu(C, &vc, NULL, 0, mval, extend);
1153                 } else {
1154                         base= startbase;
1155                         while(base) {
1156                                 if (BASE_SELECTABLE(v3d, base)) {
1157                                         project_short(ar, base->object->obmat[3], &base->sx);
1158                                         
1159                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
1160                                         if(base==BASACT) temp+=10;
1161                                         if(temp<dist ) {
1162                                                 
1163                                                 dist= temp;
1164                                                 basact= base;
1165                                         }
1166                                 }
1167                                 base= base->next;
1168                                 
1169                                 if(base==0) base= FIRSTBASE;
1170                                 if(base==startbase) break;
1171                         }
1172                 }
1173         }
1174         else {
1175                 unsigned int buffer[4*MAXPICKBUF];
1176
1177                 /* if objects have posemode set, the bones are in the same selection buffer */
1178                 
1179                 hits= mixed_bones_object_selectbuffer(&vc, buffer, mval);
1180                 
1181                 if(hits>0) {
1182                         int has_bones= 0;
1183                         
1184                         for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1185
1186                         /* note; shift+alt goes to group-flush-selecting */
1187                         if(has_bones==0 && enumerate) {
1188                                 basact= mouse_select_menu(C, &vc, buffer, hits, mval, extend);
1189                         } else {
1190                                 basact= mouse_select_eval_buffer(&vc, buffer, hits, mval, startbase, has_bones);
1191                         }
1192                         
1193                         if(has_bones && basact) {
1194                                 if(ED_do_pose_selectbuffer(scene, basact, buffer, hits, extend) ) {     /* then bone is found */
1195                                 
1196                                         /* we make the armature selected: 
1197                                            not-selected active object in posemode won't work well for tools */
1198                                         basact->flag|= SELECT;
1199                                         basact->object->flag= basact->flag;
1200                                         
1201                                         retval = 1;
1202                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, basact->object);
1203                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, basact->object);
1204                                         
1205                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1206                                         if(BASACT && BASACT->object->mode & OB_MODE_WEIGHT_PAINT) {
1207                                                 /* prevent activating */
1208                                                 basact= NULL;
1209                                         }
1210
1211                                 }
1212                                 /* prevent bone selecting to pass on to object selecting */
1213                                 if(basact==BASACT)
1214                                         basact= NULL;
1215                         }
1216                 }
1217         }
1218         
1219         /* so, do we have something selected? */
1220         if(basact) {
1221                 retval = 1;
1222                 
1223                 if(vc.obedit) {
1224                         /* only do select */
1225                         deselectall_except(scene, basact);
1226                         ED_base_object_select(basact, BA_SELECT);
1227                 }
1228                 /* also prevent making it active on mouse selection */
1229                 else if (BASE_SELECTABLE(v3d, basact)) {
1230
1231                         oldbasact= BASACT;
1232                         
1233                         if(!extend) {
1234                                 deselectall_except(scene, basact);
1235                                 ED_base_object_select(basact, BA_SELECT);
1236                         }
1237                         else if(0) {
1238                                 // XXX select_all_from_groups(basact);
1239                         }
1240                         else {
1241                                 if(basact->flag & SELECT) {
1242                                         if(basact==oldbasact)
1243                                                 ED_base_object_select(basact, BA_DESELECT);
1244                                 }
1245                                 else ED_base_object_select(basact, BA_SELECT);
1246                         }
1247
1248                         if(oldbasact != basact) {
1249                                 ED_base_object_activate(C, basact); /* adds notifier */
1250                         }
1251
1252                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1253                 }
1254         }
1255
1256         return retval;
1257 }
1258
1259 /* ********************  border and circle ************************************** */
1260
1261
1262 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1263 {
1264         int radsq= rad*rad;
1265         float v1[2], v2[2], v3[2];
1266         
1267         /* check points in circle itself */
1268         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1269         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1270         
1271         /* pointdistline */
1272         v3[0]= centx;
1273         v3[1]= centy;
1274         v1[0]= x1;
1275         v1[1]= y1;
1276         v2[0]= x2;
1277         v2[1]= y2;
1278         
1279         if( dist_to_line_segment_v2(v3, v1, v2) < (float)rad ) return 1;
1280         
1281         return 0;
1282 }
1283
1284 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1285 {
1286         struct { ViewContext *vc; rcti *rect; int select; } *data = userData;
1287         Object *obedit= data->vc->obedit;
1288         Curve *cu= (Curve*)obedit->data;
1289
1290         if (BLI_in_rcti(data->rect, x, y)) {
1291                 if (bp) {
1292                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1293                         if (bp == cu->lastsel && !(bp->f1 & 1)) cu->lastsel = NULL;
1294                 } else {
1295                         if (cu->drawflag & CU_HIDE_HANDLES) {
1296                                 /* can only be beztindex==0 here since handles are hidden */
1297                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1298                         } else {
1299                                 if (beztindex==0) {
1300                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1301                                 } else if (beztindex==1) {
1302                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1303                                 } else {
1304                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1305                                 }
1306                         }
1307
1308                         if (bezt == cu->lastsel && !(bezt->f2 & 1)) cu->lastsel = NULL;
1309                 }
1310         }
1311 }
1312 static void do_nurbs_box_select(ViewContext *vc, rcti *rect, int select, int extend)
1313 {
1314         struct { ViewContext *vc; rcti *rect; int select; } data;
1315         
1316         data.vc = vc;
1317         data.rect = rect;
1318         data.select = select;
1319
1320         if (extend == 0 && select) {
1321                 CU_deselect_all(vc->obedit);
1322         }
1323
1324         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1325         nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data);
1326 }
1327
1328 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1329 {
1330         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1331
1332         if (BLI_in_rcti(data->rect, x, y)) {
1333                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1334         }
1335 }
1336 static void do_lattice_box_select(ViewContext *vc, rcti *rect, int select, int extend)
1337 {
1338         struct { ViewContext vc; rcti *rect; int select, pass, done; } data;
1339
1340         data.vc= *vc;
1341         data.rect = rect;
1342         data.select = select;
1343
1344         if (extend == 0 && select) {
1345                 ED_setflagsLatt(vc->obedit, 0);
1346         }
1347
1348         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1349         lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data);
1350 }
1351
1352 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1353 {
1354         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1355
1356         if (BLI_in_rcti(data->rect, x, y)) {
1357                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1358         }
1359 }
1360 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1361 {
1362         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1363
1364         if(EM_check_backbuf(em_solidoffs+index)) {
1365                 if (data->pass==0) {
1366                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1367                                 EM_select_edge(eed, data->select);
1368                                 data->done = 1;
1369                         }
1370                 } else {
1371                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1372                                 EM_select_edge(eed, data->select);
1373                         }
1374                 }
1375         }
1376 }
1377 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1378 {
1379         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1380
1381         if (BLI_in_rcti(data->rect, x, y)) {
1382                 EM_select_face_fgon(data->vc.em, efa, data->select);
1383         }
1384 }
1385 static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select, int extend)
1386 {
1387         struct { ViewContext vc; rcti *rect; short select, pass, done; } data;
1388         ToolSettings *ts= vc->scene->toolsettings;
1389         int bbsel;
1390         
1391         data.vc= *vc;
1392         data.rect = rect;
1393         data.select = select;
1394         data.pass = 0;
1395         data.done = 0;
1396
1397         if (extend == 0 && select)
1398         {
1399                 EM_deselect_all(vc->em);
1400         }
1401
1402         /* workaround: init mats first, EM_mask_init_backbuf_border can change
1403            view matrix to pixel space, breaking edge select with backbuf. fixes bug #20936 */
1404         /*ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);*/ /* for foreach's screen/vert projection */
1405
1406         /* [#21018] breaks zbuf select. run below. only if bbsel fails */
1407         /* ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d) */
1408
1409         glLoadMatrixf(vc->rv3d->viewmat);
1410         bbsel= EM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1411
1412         if(ts->selectmode & SCE_SELECT_VERTEX) {
1413                 if (bbsel) {
1414                         EM_backbuf_checkAndSelectVerts(vc->em, select);
1415                 } else {
1416                         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
1417                         mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1);
1418                 }
1419         }
1420         if(ts->selectmode & SCE_SELECT_EDGE) {
1421                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1422
1423                 data.pass = 0;
1424                 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1425
1426                 if (data.done==0) {
1427                         data.pass = 1;
1428                         mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1429                 }
1430         }
1431         
1432         if(ts->selectmode & SCE_SELECT_FACE) {
1433                 if(bbsel) {
1434                         EM_backbuf_checkAndSelectFaces(vc->em, select);
1435                 } else {
1436                         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
1437                         mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data);
1438                 }
1439         }
1440         
1441         EM_free_backbuf();
1442                 
1443         EM_selectmode_flush(vc->em);
1444 }
1445
1446 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
1447 {
1448         ViewContext vc;
1449         Scene *scene= CTX_data_scene(C);
1450         ScrArea *sa= CTX_wm_area(C);
1451         View3D *v3d= sa->spacedata.first;
1452         Object *obedit= CTX_data_edit_object(C);
1453         Object *obact= CTX_data_active_object(C);
1454         rcti rect;
1455         Base *base;
1456         MetaElem *ml;
1457         unsigned int buffer[4*MAXPICKBUF];
1458         int a, index;
1459         int extend;
1460         short hits, selecting;
1461
1462         view3d_operator_needs_opengl(C);
1463         
1464         /* setup view context for argument to callbacks */
1465         view3d_set_viewcontext(C, &vc);
1466         
1467         selecting= (RNA_int_get(op->ptr, "gesture_mode")==GESTURE_MODAL_SELECT);
1468         rect.xmin= RNA_int_get(op->ptr, "xmin");
1469         rect.ymin= RNA_int_get(op->ptr, "ymin");
1470         rect.xmax= RNA_int_get(op->ptr, "xmax");
1471         rect.ymax= RNA_int_get(op->ptr, "ymax");
1472         extend = RNA_boolean_get(op->ptr, "extend");
1473
1474         if(obedit==NULL && (paint_facesel_test(OBACT))) {
1475                 face_borderselect(C, obact, &rect, selecting, extend);
1476                 return OPERATOR_FINISHED;
1477         }
1478         else if(obedit==NULL && (obact && obact->mode & OB_MODE_PARTICLE_EDIT)) {
1479                 return PE_border_select(C, &rect, selecting, extend);
1480         }
1481         else if(obedit==NULL && (obact && obact->mode & OB_MODE_SCULPT))
1482                 return OPERATOR_CANCELLED;
1483         
1484         if(obedit) {
1485                 if(obedit->type==OB_MESH) {
1486                         Mesh *me= obedit->data;
1487                         vc.em= me->edit_mesh;
1488                         do_mesh_box_select(&vc, &rect, selecting, extend);
1489 //                      if (EM_texFaceCheck())
1490                         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
1491                         
1492                 }
1493                 else if(ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1494                         do_nurbs_box_select(&vc, &rect, selecting, extend);
1495                 }
1496                 else if(obedit->type==OB_MBALL) {
1497                         MetaBall *mb = (MetaBall*)obedit->data;
1498                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1499                         
1500                         if (extend == 0 && selecting) {
1501                                 ml= mb->editelems->first;
1502
1503                                 while(ml) {
1504                                         ml->flag &= ~SELECT;
1505                                         ml= ml->next;
1506                                 }
1507                         }
1508
1509                         ml= mb->editelems->first;
1510                         
1511                         while(ml) {
1512                                 for(a=0; a<hits; a++) {
1513                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1514                                                 ml->flag |= MB_SCALE_RAD;
1515                                                 if(selecting)   ml->flag |= SELECT;
1516                                                 else                    ml->flag &= ~SELECT;
1517                                                 break;
1518                                         }
1519                                         if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1520                                                 ml->flag &= ~MB_SCALE_RAD;
1521                                                 if(selecting)   ml->flag |= SELECT;
1522                                                 else                    ml->flag &= ~SELECT;
1523                                                 break;
1524                                         }
1525                                 }
1526                                 ml= ml->next;
1527                         }
1528                 }
1529                 else if(obedit->type==OB_ARMATURE) {
1530                         bArmature *arm= obedit->data;
1531                         EditBone *ebone;
1532                         
1533                         /* clear flag we use to detect point was affected */
1534                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next)
1535                                 ebone->flag &= ~BONE_DONE;
1536                         
1537                         if (extend==0 && selecting) {
1538                                 /*      Set the flags */
1539                                 CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones) {
1540                                         /* ignore bone if selection can't change */
1541                                         if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
1542                                                 ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
1543                                         }
1544                                 }
1545                                 CTX_DATA_END;
1546                         }
1547
1548                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1549                         
1550                         /* first we only check points inside the border */
1551                         for (a=0; a<hits; a++){
1552                                 index = buffer[(4*a)+3];
1553                                 if (index!=-1) {
1554                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1555                                         if (index & BONESEL_TIP) {
1556                                                 ebone->flag |= BONE_DONE;
1557                                                 if (selecting)  ebone->flag |= BONE_TIPSEL;
1558                                                 else                    ebone->flag &= ~BONE_TIPSEL;
1559                                         }
1560                                         
1561                                         if (index & BONESEL_ROOT) {
1562                                                 ebone->flag |= BONE_DONE;
1563                                                 if (selecting)  ebone->flag |= BONE_ROOTSEL;
1564                                                 else                    ebone->flag &= ~BONE_ROOTSEL;
1565                                         }
1566                                 }
1567                         }
1568                         
1569                         /* now we have to flush tag from parents... */
1570                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next) {
1571                                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1572                                         if(ebone->parent->flag & BONE_DONE)
1573                                                 ebone->flag |= BONE_DONE;
1574                                 }
1575                         }
1576                         
1577                         /* only select/deselect entire bones when no points where in the rect */
1578                         for (a=0; a<hits; a++){
1579                                 index = buffer[(4*a)+3];
1580                                 if (index!=-1) {
1581                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1582                                         if (index & BONESEL_BONE) {
1583                                                 if(!(ebone->flag & BONE_DONE)) {
1584                                                         if (selecting)
1585                                                                 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1586                                                         else
1587                                                                 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1588                                                 }
1589                                         }
1590                                 }
1591                         }
1592                         
1593                         ED_armature_sync_selection(arm->edbo);
1594                 }
1595                 else if(obedit->type==OB_LATTICE) {
1596                         do_lattice_box_select(&vc, &rect, selecting, extend);
1597                 }
1598         }
1599         else {  /* no editmode, unified for bones and objects */
1600                 Bone *bone;
1601                 Object *ob= OBACT;
1602                 unsigned int *vbuffer=NULL; /* selection buffer */
1603                 unsigned int *col;                      /* color in buffer      */
1604                 int bone_only;
1605                 int bone_selected=0;
1606                 int totobj= MAXPICKBUF; // XXX solve later
1607                 
1608                 if((ob) && (ob->mode & OB_MODE_POSE))
1609                         bone_only= 1;
1610                 else
1611                         bone_only= 0;
1612                 
1613                 if (extend == 0 && selecting) {
1614                         base= FIRSTBASE;
1615
1616                         if (bone_only) {
1617                                 CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) {
1618                                         pchan->bone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
1619                                 }
1620                                 CTX_DATA_END;
1621                         } else {
1622                                 while(base) {
1623                                         Base *next = base->next;
1624                                         if(base->lay & v3d->lay) {
1625                                                 ED_base_object_select(base, BA_DESELECT);
1626                                         }
1627                                         base= next;
1628                                 }
1629                         }
1630                 }
1631
1632                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1633                 vbuffer = MEM_mallocN(4 * (totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1634                 hits= view3d_opengl_select(&vc, vbuffer, 4*(totobj+MAXPICKBUF), &rect);
1635                 /*
1636                 LOGIC NOTES (theeth):
1637                 The buffer and ListBase have the same relative order, which makes the selection
1638                 very simple. Loop through both data sets at the same time, if the color
1639                 is the same as the object, we have a hit and can move to the next color
1640                 and object pair, if not, just move to the next object,
1641                 keeping the same color until we have a hit.
1642
1643                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1644                 does it incorrectly.
1645                 */
1646
1647                 if (hits>0) { /* no need to loop if there's no hit */
1648                         base= FIRSTBASE;
1649                         col = vbuffer + 3;
1650                         
1651                         while(base && hits) {
1652                                 Base *next = base->next;
1653                                 if(base->lay & v3d->lay) {
1654                                         while (base->selcol == (*col & 0xFFFF)) {       /* we got an object */
1655                                                 
1656                                                 if(*col & 0xFFFF0000) {                                 /* we got a bone */
1657                                                         bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1658                                                         if(bone) {
1659                                                                 if(selecting) {
1660                                                                         bone->flag |= BONE_SELECTED;
1661                                                                         bone_selected=1;
1662 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 1);
1663                                                                 }
1664                                                                 else {
1665                                                                         bArmature *arm= base->object->data;
1666                                                                         bone->flag &= ~BONE_SELECTED;
1667 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 0);
1668                                                                         if(arm->act_bone==bone)
1669                                                                                 arm->act_bone= NULL;
1670                                                                         
1671                                                                 }
1672                                                         }
1673                                                 }
1674                                                 else if(!bone_only) {
1675                                                         if (selecting)
1676                                                                 ED_base_object_select(base, BA_SELECT);
1677                                                         else
1678                                                                 ED_base_object_select(base, BA_DESELECT);
1679                                                 }
1680
1681                                                 col+=4; /* next color */
1682                                                 hits--;
1683                                                 if(hits==0) break;
1684                                         }
1685                                 }
1686                                 
1687                                 if (bone_selected)      WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, base->object);
1688                                 
1689                                 base= next;
1690                         }
1691
1692                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1693
1694                 }
1695                 MEM_freeN(vbuffer);
1696         }
1697         return OPERATOR_FINISHED;
1698
1699
1700
1701 /* *****************Selection Operators******************* */
1702
1703 /* ****** Border Select ****** */
1704 void VIEW3D_OT_select_border(wmOperatorType *ot)
1705 {
1706         /* identifiers */
1707         ot->name= "Border Select";
1708         ot->description= "Select items using border selection";
1709         ot->idname= "VIEW3D_OT_select_border";
1710         
1711         /* api callbacks */
1712         ot->invoke= WM_border_select_invoke;
1713         ot->exec= view3d_borderselect_exec;
1714         ot->modal= WM_border_select_modal;
1715         ot->poll= view3d_selectable_data;
1716         
1717         /* flags */
1718         ot->flag= OPTYPE_UNDO;
1719         
1720         /* rna */
1721         WM_operator_properties_gesture_border(ot, TRUE);
1722 }
1723
1724 /* ****** Mouse Select ****** */
1725
1726
1727 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1728 {
1729         Object *obedit= CTX_data_edit_object(C);
1730         Object *obact= CTX_data_active_object(C);
1731         short extend= RNA_boolean_get(op->ptr, "extend");
1732         short center= RNA_boolean_get(op->ptr, "center");
1733         short enumerate= RNA_boolean_get(op->ptr, "enumerate");
1734         int     retval = 0;
1735
1736         view3d_operator_needs_opengl(C);
1737         
1738         if(obedit) {
1739                 if(obedit->type==OB_MESH)
1740                         retval = mouse_mesh(C, event->mval, extend);
1741                 else if(obedit->type==OB_ARMATURE)
1742                         retval = mouse_armature(C, event->mval, extend);
1743                 else if(obedit->type==OB_LATTICE)
1744                         retval = mouse_lattice(C, event->mval, extend);
1745                 else if(ELEM(obedit->type, OB_CURVE, OB_SURF))
1746                         retval = mouse_nurb(C, event->mval, extend);
1747                 else if(obedit->type==OB_MBALL)
1748                         retval = mouse_mball(C, event->mval, extend);
1749                         
1750         }
1751         else if(obact && obact->mode & OB_MODE_SCULPT)
1752                 return OPERATOR_CANCELLED;
1753         else if(obact && obact->mode & OB_MODE_PARTICLE_EDIT)
1754                 return PE_mouse_particles(C, event->mval, extend);
1755         else if(obact && paint_facesel_test(obact))
1756                 retval = face_select(C, obact, event->mval, extend);
1757         else
1758                 retval = mouse_select(C, event->mval, extend, center, enumerate);
1759
1760         /* passthrough allows tweaks
1761          * FINISHED to signal one operator worked
1762          * */
1763         if (retval)
1764                 return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED;
1765         else
1766                 return OPERATOR_PASS_THROUGH; /* nothing selected, just passthrough */
1767 }
1768
1769 void VIEW3D_OT_select(wmOperatorType *ot)
1770 {
1771         /* identifiers */
1772         ot->name= "Activate/Select";
1773         ot->description= "Activate/select item(s)";
1774         ot->idname= "VIEW3D_OT_select";
1775         
1776         /* api callbacks */
1777         ot->invoke= view3d_select_invoke;
1778         ot->poll= ED_operator_view3d_active;
1779         
1780         /* flags */
1781         ot->flag= OPTYPE_UNDO;
1782         
1783         /* properties */
1784         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first.");
1785         RNA_def_boolean(ot->srna, "center", 0, "Center", "Use the object center when selecting (object mode only).");
1786         RNA_def_boolean(ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only).");
1787 }
1788
1789
1790 /* -------------------- circle select --------------------------------------------- */
1791
1792 static void mesh_circle_doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1793 {
1794         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1795         int mx = x - data->mval[0], my = y - data->mval[1];
1796         float r = sqrt(mx*mx + my*my);
1797
1798         if (r<=data->radius) {
1799                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1800         }
1801 }
1802 static void mesh_circle_doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1803 {
1804         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1805
1806         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1807                 EM_select_edge(eed, data->select);
1808         }
1809 }
1810 static void mesh_circle_doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1811 {
1812         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1813         int mx = x - data->mval[0], my = y - data->mval[1];
1814         float r = sqrt(mx*mx + my*my);
1815         
1816         if (r<=data->radius) {
1817                 EM_select_face_fgon(data->vc->em, efa, data->select);
1818         }
1819 }
1820
1821 static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1822 {
1823         ToolSettings *ts= vc->scene->toolsettings;
1824         int bbsel;
1825         Object *ob= vc->obact;
1826         
1827         if(vc->obedit==NULL && paint_facesel_test(ob)) {
1828                 Mesh *me = ob?ob->data:NULL;
1829
1830                 if (me) {
1831                         em_vertoffs= me->totface+1;     /* max index array */
1832
1833                         bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1834                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1835                         EM_free_backbuf();
1836
1837 // XXX                  object_tface_flags_changed(OBACT, 0);
1838                 }
1839         }
1840         else {
1841                 struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1842                 
1843                 bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1844                 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1845
1846                 vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
1847
1848                 data.vc = vc;
1849                 data.select = selecting;
1850                 data.mval[0] = mval[0];
1851                 data.mval[1] = mval[1];
1852                 data.radius = rad;
1853
1854                 if(ts->selectmode & SCE_SELECT_VERTEX) {
1855                         if(bbsel) {
1856                                 EM_backbuf_checkAndSelectVerts(vc->em, selecting==LEFTMOUSE);
1857                         } else {
1858                                 mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, 1);
1859                         }
1860                 }
1861
1862                 if(ts->selectmode & SCE_SELECT_EDGE) {
1863                         if (bbsel) {
1864                                 EM_backbuf_checkAndSelectEdges(vc->em, selecting==LEFTMOUSE);
1865                         } else {
1866                                 mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, 0);
1867                         }
1868                 }
1869                 
1870                 if(ts->selectmode & SCE_SELECT_FACE) {
1871                         if(bbsel) {
1872                                 EM_backbuf_checkAndSelectFaces(vc->em, selecting==LEFTMOUSE);
1873                         } else {
1874                                 mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data);
1875                         }
1876                 }
1877
1878                 EM_free_backbuf();
1879                 EM_selectmode_flush(vc->em);
1880         }
1881 }
1882
1883
1884 static void nurbscurve_circle_doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1885 {
1886         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1887         int mx = x - data->mval[0], my = y - data->mval[1];
1888         float r = sqrt(mx*mx + my*my);
1889         Object *obedit= data->vc->obedit;
1890         Curve *cu= (Curve*)obedit->data;
1891
1892         if (r<=data->radius) {
1893                 if (bp) {
1894                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1895
1896                         if (bp == cu->lastsel && !(bp->f1 & 1)) cu->lastsel = NULL;
1897                 } else {
1898                         if (cu->drawflag & CU_HIDE_HANDLES) {
1899                                 /* can only be beztindex==0 here since handles are hidden */
1900                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1901                         } else {
1902                                 if (beztindex==0) {
1903                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1904                                 } else if (beztindex==1) {
1905                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1906                                 } else {
1907                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1908                                 }
1909                         }
1910
1911                         if (bezt == cu->lastsel && !(bezt->f2 & 1)) cu->lastsel = NULL;
1912                 }
1913         }
1914 }
1915 static void nurbscurve_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1916 {
1917         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1918
1919         /* set vc-> edit data */
1920         
1921         data.select = selecting;
1922         data.mval[0] = mval[0];
1923         data.mval[1] = mval[1];
1924         data.radius = rad;
1925         data.vc = vc;
1926
1927         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1928         nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data);
1929 }
1930
1931
1932 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, int x, int y)
1933 {
1934         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1935         int mx = x - data->mval[0], my = y - data->mval[1];
1936         float r = sqrt(mx*mx + my*my);
1937
1938         if (r<=data->radius) {
1939                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1940         }
1941 }
1942 static void lattice_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1943 {
1944         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1945
1946         /* set vc-> edit data */
1947         
1948         data.select = selecting;
1949         data.mval[0] = mval[0];
1950         data.mval[1] = mval[1];
1951         data.radius = rad;
1952
1953         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1954         lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data);
1955 }
1956
1957
1958 static short armature_circle_doSelectJoint(void *userData, EditBone *ebone, int x, int y, short head)
1959 {
1960         struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
1961         int mx = x - data->mval[0], my = y - data->mval[1];
1962         float r = sqrt(mx*mx + my*my);
1963         
1964         if (r <= data->radius) {
1965                 if (head) {
1966                         if (data->select)
1967                                 ebone->flag |= BONE_ROOTSEL;
1968                         else 
1969                                 ebone->flag &= ~BONE_ROOTSEL;
1970                 }
1971                 else {
1972                         if (data->select)
1973                                 ebone->flag |= BONE_TIPSEL;
1974                         else 
1975                                 ebone->flag &= ~BONE_TIPSEL;
1976                 }
1977                 return 1;
1978         }
1979         return 0;
1980 }
1981 static void armature_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1982 {
1983         struct {ViewContext *vc; short select, mval[2]; float radius; } data;
1984         bArmature *arm= vc->obedit->data;
1985         EditBone *ebone;
1986         
1987         /* set vc->edit data */
1988         data.select = selecting;
1989         data.mval[0] = mval[0];
1990         data.mval[1] = mval[1];
1991         data.radius = rad;
1992
1993         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1994         
1995         /* check each EditBone... */
1996         // TODO: could be optimised at some point
1997         for (ebone= arm->edbo->first; ebone; ebone=ebone->next) {
1998                 short sco1[2], sco2[2], didpoint=0;
1999                 float vec[3];
2000                 
2001                 /* project head location to screenspace */
2002                 mul_v3_m4v3(vec, vc->obedit->obmat, ebone->head);
2003                 project_short(vc->ar, vec, sco1);
2004                 
2005                 /* project tail location to screenspace */
2006                 mul_v3_m4v3(vec, vc->obedit->obmat, ebone->tail);
2007                 project_short(vc->ar, vec, sco2);
2008                 
2009                 /* check if the head and/or tail is in the circle 
2010                  *      - the call to check also does the selection already
2011                  */
2012                 if (armature_circle_doSelectJoint(&data, ebone, sco1[0], sco1[1], 1))
2013                         didpoint= 1;
2014                 if (armature_circle_doSelectJoint(&data, ebone, sco2[0], sco2[1], 0))
2015                         didpoint= 1;
2016                         
2017                 /* only if the endpoints didn't get selected, deal with the middle of the bone too */
2018                 // XXX should we just do this always?
2019                 if ( (didpoint==0) && edge_inside_circle(mval[0], mval[1], rad, sco1[0], sco1[1], sco2[0], sco2[1]) ) {
2020                         if (selecting) 
2021                                 ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
2022                         else 
2023                                 ebone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
2024                 }
2025         }
2026
2027         ED_armature_validate_active(arm);
2028 }
2029
2030 /** Callbacks for circle selection in Editmode */
2031
2032 static void obedit_circle_select(ViewContext *vc, short selecting, short *mval, float rad) 
2033 {
2034         switch(vc->obedit->type) {              
2035         case OB_MESH:
2036                 mesh_circle_select(vc, selecting, mval, rad);
2037                 break;
2038         case OB_CURVE:
2039         case OB_SURF:
2040                 nurbscurve_circle_select(vc, selecting, mval, rad);
2041                 break;
2042         case OB_LATTICE:
2043                 lattice_circle_select(vc, selecting, mval, rad);
2044                 break;
2045         case OB_ARMATURE:
2046                 armature_circle_select(vc, selecting, mval, rad);
2047                 break;
2048         default:
2049                 return;
2050         }
2051 }
2052
2053 /* not a real operator, only for circle test */
2054 static int view3d_circle_select_exec(bContext *C, wmOperator *op)
2055 {
2056         ScrArea *sa= CTX_wm_area(C);
2057         ARegion *ar= CTX_wm_region(C);
2058         Scene *scene= CTX_data_scene(C);
2059         Object *obact= CTX_data_active_object(C);
2060         View3D *v3d= sa->spacedata.first;
2061         int x= RNA_int_get(op->ptr, "x");
2062         int y= RNA_int_get(op->ptr, "y");
2063         int radius= RNA_int_get(op->ptr, "radius");
2064         int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
2065         int selecting;
2066         
2067         selecting= (gesture_mode==GESTURE_MODAL_SELECT);
2068     
2069         if(CTX_data_edit_object(C) || (obact && obact->mode & OB_MODE_PARTICLE_EDIT)) {
2070                 ViewContext vc;
2071                 short mval[2];
2072                 
2073                 view3d_operator_needs_opengl(C);
2074                 
2075                 view3d_set_viewcontext(C, &vc);
2076                 mval[0]= x;
2077                 mval[1]= y;
2078
2079                 if(CTX_data_edit_object(C)) {
2080                         obedit_circle_select(&vc, selecting, mval, (float)radius);
2081                         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obact->data);
2082                 }
2083                 else
2084                         return PE_circle_select(C, selecting, mval, (float)radius);
2085         }
2086         else if(obact && obact->mode & OB_MODE_SCULPT) {
2087                 return OPERATOR_CANCELLED;
2088         }
2089         else {
2090                 Base *base;
2091                 selecting= selecting?BA_SELECT:BA_DESELECT;
2092                 for(base= FIRSTBASE; base; base= base->next) {
2093                         if(base->lay & v3d->lay) {
2094                                 project_short(ar, base->object->obmat[3], &base->sx);
2095                                 if(base->sx!=IS_CLIPPED) {
2096                                         int dx= base->sx-x;
2097                                         int dy= base->sy-y;
2098                                         if( dx*dx + dy*dy < radius*radius)
2099                                                 ED_base_object_select(base, selecting);
2100                                 }
2101                         }
2102                 }
2103                 
2104                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
2105         }
2106         
2107         return OPERATOR_FINISHED;
2108 }
2109
2110 void VIEW3D_OT_select_circle(wmOperatorType *ot)
2111 {
2112         ot->name= "Circle Select";
2113         ot->description= "Select items using circle selection";
2114         ot->idname= "VIEW3D_OT_select_circle";
2115         
2116         ot->invoke= WM_gesture_circle_invoke;
2117         ot->modal= WM_gesture_circle_modal;
2118         ot->exec= view3d_circle_select_exec;
2119         ot->poll= view3d_selectable_data;
2120         
2121         /* flags */
2122         ot->flag= OPTYPE_UNDO;
2123         
2124         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
2125         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
2126         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
2127         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2128 }