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