2.5
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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_action_types.h"
35 #include "DNA_armature_types.h"
36 #include "DNA_curve_types.h"
37 #include "DNA_camera_types.h"
38 #include "DNA_lamp_types.h"
39 #include "DNA_meta_types.h"
40 #include "DNA_mesh_types.h"
41 #include "DNA_meshdata_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_space_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_userdef_types.h"
47 #include "DNA_view3d_types.h"
48 #include "DNA_world_types.h"
49
50 #include "MEM_guardedalloc.h"
51
52 #include "BLI_arithb.h"
53 #include "BLI_blenlib.h"
54 #include "BLI_editVert.h"
55 #include "BLI_rand.h"
56
57 #include "BKE_action.h"
58 #include "BKE_context.h"
59 #include "BKE_depsgraph.h"
60 #include "BKE_object.h"
61 #include "BKE_global.h"
62 #include "BKE_scene.h"
63 #include "BKE_screen.h"
64 #include "BKE_utildefines.h"
65
66 #include "RE_pipeline.h"        // make_stars
67
68 #include "BIF_gl.h"
69 #include "BIF_retopo.h"
70 #include "BIF_editarmature.h"
71
72 #include "WM_api.h"
73 #include "WM_types.h"
74
75 #include "RNA_access.h"
76 #include "RNA_define.h"
77
78 #include "ED_mesh.h"
79 #include "ED_object.h"
80 #include "ED_screen.h"
81 #include "ED_types.h"
82
83 #include "UI_interface.h"
84 #include "UI_resources.h"
85 #include "UI_view2d.h"
86
87 #include "PIL_time.h" /* smoothview */
88
89 #include "view3d_intern.h"      // own include
90
91
92 static void view3d_set_viewcontext(bContext *C, ViewContext *vc)
93 {
94         memset(vc, 0, sizeof(ViewContext));
95         vc->ar= CTX_wm_region(C);
96         vc->scene= CTX_data_scene(C);
97         vc->v3d= (View3D *)CTX_wm_space_data(C);
98         vc->obact= CTX_data_active_object(C);
99         vc->obedit= CTX_data_edit_object(C); 
100 }
101
102 /* ********************** view3d_select: selection manipulations ********************* */
103
104 /* XXX to solve *************** */
105 static void BIF_undo_push() {}
106 /* XXX end ********************* */
107
108 /* local prototypes */
109
110 void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select)
111 {
112         EditVert *eve;
113         int index= em_wireoffs;
114
115         for(eve= em->verts.first; eve; eve= eve->next, index++) {
116                 if(eve->h==0) {
117                         if(EM_check_backbuf(index)) {
118                                 eve->f = select?(eve->f|1):(eve->f&~1);
119                         }
120                 }
121         }
122 }
123
124 void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select)
125 {
126         EditEdge *eed;
127         int index= em_solidoffs;
128
129         for(eed= em->edges.first; eed; eed= eed->next, index++) {
130                 if(eed->h==0) {
131                         if(EM_check_backbuf(index)) {
132                                 EM_select_edge(eed, select);
133                         }
134                 }
135         }
136 }
137
138 void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select)
139 {
140         EditFace *efa;
141         int index= 1;
142
143         for(efa= em->faces.first; efa; efa= efa->next, index++) {
144                 if(efa->h==0) {
145                         if(EM_check_backbuf(index)) {
146                                 EM_select_face_fgon(em, efa, select);
147                         }
148                 }
149         }
150 }
151
152 void EM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
153 {
154         MFace *mface = me->mface;
155         int a;
156
157         if (mface) {
158                 for(a=1; a<=me->totface; a++, mface++) {
159                         if(EM_check_backbuf(a)) {
160                                 mface->flag = select?(mface->flag|ME_FACE_SEL):(mface->flag&~ME_FACE_SEL);
161                         }
162                 }
163         }
164 }
165
166 void arrows_move_cursor(unsigned short event)
167 {
168 #if 0
169         short mval[2];
170
171         getmouseco_sc(mval);
172
173         if(event==UPARROWKEY) {
174                 warp_pointer(mval[0], mval[1]+1);
175         } else if(event==DOWNARROWKEY) {
176                 warp_pointer(mval[0], mval[1]-1);
177         } else if(event==LEFTARROWKEY) {
178                 warp_pointer(mval[0]-1, mval[1]);
179         } else if(event==RIGHTARROWKEY) {
180                 warp_pointer(mval[0]+1, mval[1]);
181         }
182 #endif
183 }
184
185
186 /* *********************** GESTURE AND LASSO ******************* */
187
188 /* helper also for borderselect */
189 static int edge_fully_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
190 {
191         return BLI_in_rcti(rect, x1, y1) && BLI_in_rcti(rect, x2, y2);
192 }
193
194 static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
195 {
196         int d1, d2, d3, d4;
197         
198         /* check points in rect */
199         if(edge_fully_inside_rect(rect, x1, y1, x2, y2)) return 1;
200         
201         /* check points completely out rect */
202         if(x1<rect->xmin && x2<rect->xmin) return 0;
203         if(x1>rect->xmax && x2>rect->xmax) return 0;
204         if(y1<rect->ymin && y2<rect->ymin) return 0;
205         if(y1>rect->ymax && y2>rect->ymax) return 0;
206         
207         /* simple check lines intersecting. */
208         d1= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymin );
209         d2= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymax );
210         d3= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymax );
211         d4= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymin );
212         
213         if(d1<0 && d2<0 && d3<0 && d4<0) return 0;
214         if(d1>0 && d2>0 && d3>0 && d4>0) return 0;
215         
216         return 1;
217 }
218
219
220 #define MOVES_GESTURE 50
221 #define MOVES_LASSO 500
222
223 int lasso_inside(short mcords[][2], short moves, short sx, short sy)
224 {
225         /* we do the angle rule, define that all added angles should be about zero or 2*PI */
226         float angletot=0.0, len, dot, ang, cross, fp1[2], fp2[2];
227         int a;
228         short *p1, *p2;
229         
230         if(sx==IS_CLIPPED)
231                 return 0;
232         
233         p1= mcords[moves-1];
234         p2= mcords[0];
235         
236         /* first vector */
237         fp1[0]= (float)(p1[0]-sx);
238         fp1[1]= (float)(p1[1]-sy);
239         len= sqrt(fp1[0]*fp1[0] + fp1[1]*fp1[1]);
240         fp1[0]/= len;
241         fp1[1]/= len;
242         
243         for(a=0; a<moves; a++) {
244                 /* second vector */
245                 fp2[0]= (float)(p2[0]-sx);
246                 fp2[1]= (float)(p2[1]-sy);
247                 len= sqrt(fp2[0]*fp2[0] + fp2[1]*fp2[1]);
248                 fp2[0]/= len;
249                 fp2[1]/= len;
250                 
251                 /* dot and angle and cross */
252                 dot= fp1[0]*fp2[0] + fp1[1]*fp2[1];
253                 ang= fabs(saacos(dot));
254
255                 cross= (float)((p1[1]-p2[1])*(p1[0]-sx) + (p2[0]-p1[0])*(p1[1]-sy));
256                 
257                 if(cross<0.0) angletot-= ang;
258                 else angletot+= ang;
259                 
260                 /* circulate */
261                 fp1[0]= fp2[0]; fp1[1]= fp2[1];
262                 p1= p2;
263                 p2= mcords[a+1];
264         }
265         
266         if( fabs(angletot) > 4.0 ) return 1;
267         return 0;
268 }
269
270 /* edge version for lasso select. we assume boundbox check was done */
271 int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1)
272 {
273         short v1[2], v2[2];
274         int a;
275
276         if(x0==IS_CLIPPED || x1==IS_CLIPPED)
277                 return 0;
278         
279         v1[0] = x0, v1[1] = y0;
280         v2[0] = x1, v2[1] = y1;
281
282         /* check points in lasso */
283         if(lasso_inside(mcords, moves, v1[0], v1[1])) return 1;
284         if(lasso_inside(mcords, moves, v2[0], v2[1])) return 1;
285         
286         /* no points in lasso, so we have to intersect with lasso edge */
287         
288         if( IsectLL2Ds(mcords[0], mcords[moves-1], v1, v2) > 0) return 1;
289         for(a=0; a<moves-1; a++) {
290                 if( IsectLL2Ds(mcords[a], mcords[a+1], v1, v2) > 0) return 1;
291         }
292         
293         return 0;
294 }
295
296
297 /* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN) 
298    and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK
299 */
300 static void do_lasso_select_pose(ViewContext *vc, short mcords[][2], short moves, short select)
301 {
302         Object *ob= vc->obact;
303         bPoseChannel *pchan;
304         float vec[3];
305         short sco1[2], sco2[2];
306         
307         if(ob->type!=OB_ARMATURE || ob->pose==NULL) return;
308         
309         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
310                 VECCOPY(vec, pchan->pose_head);
311                 Mat4MulVecfl(ob->obmat, vec);
312                 project_short(vc->ar, vc->v3d, vec, sco1);
313                 VECCOPY(vec, pchan->pose_tail);
314                 Mat4MulVecfl(ob->obmat, vec);
315                 project_short(vc->ar, vc->v3d, vec, sco2);
316                 
317                 if(lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
318                         if(select) pchan->bone->flag |= BONE_SELECTED;
319                         else pchan->bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
320                 }
321         }
322 }
323
324
325 static void do_lasso_select_objects(ViewContext *vc, short mcords[][2], short moves, short select)
326 {
327         Base *base;
328         
329         for(base= vc->scene->base.first; base; base= base->next) {
330                 if(base->lay & vc->v3d->lay) {
331                         project_short(vc->ar, vc->v3d, base->object->obmat[3], &base->sx);
332                         if(lasso_inside(mcords, moves, base->sx, base->sy)) {
333                                 
334                                 if(select) ED_base_object_select(base, BA_SELECT);
335                                 else ED_base_object_select(base, BA_DESELECT);
336                                 base->object->flag= base->flag;
337                         }
338                         if(base->object->flag & OB_POSEMODE) {
339                                 do_lasso_select_pose(vc, mcords, moves, select);
340                         }
341                 }
342         }
343 }
344
345 void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
346 {
347         short a;
348         
349         rect->xmin= rect->xmax= mcords[0][0];
350         rect->ymin= rect->ymax= mcords[0][1];
351         
352         for(a=1; a<moves; a++) {
353                 if(mcords[a][0]<rect->xmin) rect->xmin= mcords[a][0];
354                 else if(mcords[a][0]>rect->xmax) rect->xmax= mcords[a][0];
355                 if(mcords[a][1]<rect->ymin) rect->ymin= mcords[a][1];
356                 else if(mcords[a][1]>rect->ymax) rect->ymax= mcords[a][1];
357         }
358 }
359
360 static void do_lasso_select_mesh__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
361 {
362         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
363
364         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
365                 eve->f = data->select?(eve->f|1):(eve->f&~1);
366         }
367 }
368 static void do_lasso_select_mesh__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
369 {
370         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
371
372         if (EM_check_backbuf(em_solidoffs+index)) {
373                 if (data->pass==0) {
374                         if (    edge_fully_inside_rect(data->rect, x0, y0, x1, y1)  &&
375                                         lasso_inside(data->mcords, data->moves, x0, y0) &&
376                                         lasso_inside(data->mcords, data->moves, x1, y1)) {
377                                 EM_select_edge(eed, data->select);
378                                 data->done = 1;
379                         }
380                 } else {
381                         if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) {
382                                 EM_select_edge(eed, data->select);
383                         }
384                 }
385         }
386 }
387 static void do_lasso_select_mesh__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
388 {
389         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
390
391         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
392                 EM_select_face_fgon(data->vc.em, efa, data->select);
393         }
394 }
395
396 static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves, short select)
397 {
398         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } data;
399         rcti rect;
400         int bbsel;
401         
402         lasso_select_boundbox(&rect, mcords, moves);
403         
404         /* set editmesh */
405         vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
406
407         data.vc= *vc;
408         data.rect = &rect;
409         data.mcords = mcords;
410         data.moves = moves;
411         data.select = select;
412         data.done = 0;
413         data.pass = 0;
414
415         bbsel= EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
416         
417         if(vc->scene->selectmode & SCE_SELECT_VERTEX) {
418                 if (bbsel) {
419                         EM_backbuf_checkAndSelectVerts(vc->em, select);
420                 } else {
421                         mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, 1);
422                 }
423         }
424         if(vc->scene->selectmode & SCE_SELECT_EDGE) {
425                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
426
427                 data.pass = 0;
428                 mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0);
429
430                 if (data.done==0) {
431                         data.pass = 1;
432                         mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0);
433                 }
434         }
435         
436         if(vc->scene->selectmode & SCE_SELECT_FACE) {
437                 if (bbsel) {
438                         EM_backbuf_checkAndSelectFaces(vc->em, select);
439                 } else {
440                         mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data);
441                 }
442         }
443         
444         EM_free_backbuf();
445         EM_selectmode_flush(vc->em);    
446 }
447
448 #if 0
449 /* this is an exception in that its the only lasso that dosnt use the 3d view (uses space image view) */
450 static void do_lasso_select_mesh_uv(short mcords[][2], short moves, short select)
451 {
452         EditFace *efa;
453         MTFace *tf;
454         int screenUV[2], nverts, i, ok = 1;
455         rcti rect;
456         
457         lasso_select_boundbox(&rect, mcords, moves);
458         
459         if (draw_uvs_face_check()) { /* Face Center Sel */
460                 float cent[2];
461                 ok = 0;
462                 for (efa= em->faces.first; efa; efa= efa->next) {
463                         /* assume not touched */
464                         efa->tmp.l = 0;
465                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
466                         if ((select) != (simaFaceSel_Check(efa, tf))) {
467                                 uv_center(tf->uv, cent, (void *)efa->v4);
468                                 uvco_to_areaco_noclip(cent, screenUV);
469                                 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
470                                         efa->tmp.l = ok = 1;
471                                 }
472                         }
473                 }
474                 /* (de)selects all tagged faces and deals with sticky modes */
475                 if (ok)
476                         uvface_setsel__internal(select);
477                 
478         } else { /* Vert Sel*/
479                 for (efa= em->faces.first; efa; efa= efa->next) {
480                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
481                         if (simaFaceDraw_Check(efa, tf)) {              
482                                 nverts= efa->v4? 4: 3;
483                                 for(i=0; i<nverts; i++) {
484                                         if ((select) != (simaUVSel_Check(efa, tf, i))) {
485                                                 uvco_to_areaco_noclip(tf->uv[i], screenUV);
486                                                 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
487                                                         if (select) {
488                                                                 simaUVSel_Set(efa, tf, i);
489                                                         } else {
490                                                                 simaUVSel_UnSet(efa, tf, i);
491                                                         }
492                                                 }
493                                         }
494                                 }
495                         }
496                 }
497         }
498         if (ok && G.sima->flag & SI_SYNC_UVSEL) {
499                 if (select) EM_select_flush(vc->em);
500                 else            EM_deselect_flush(vc->em);
501         }
502 }
503 #endif
504
505 static void do_lasso_select_curve__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
506 {
507         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
508
509         if (lasso_inside(data->mcords, data->moves, x, y)) {
510                 if (bp) {
511                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
512                 } else {
513                         if (G.f & G_HIDDENHANDLES) {
514                                 /* can only be beztindex==0 here since handles are hidden */
515                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
516                         } else {
517                                 if (beztindex==0) {
518                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
519                                 } else if (beztindex==1) {
520                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
521                                 } else {
522                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
523                                 }
524                         }
525                 }
526         }
527 }
528
529 static void do_lasso_select_curve(ViewContext *vc, short mcords[][2], short moves, short select)
530 {
531         struct { short (*mcords)[2]; short moves; short select; } data;
532
533         /* set vc->editnurb */
534         data.mcords = mcords;
535         data.moves = moves;
536         data.select = select;
537
538         nurbs_foreachScreenVert(vc, do_lasso_select_curve__doSelect, &data);
539 }
540
541 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, int y)
542 {
543         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
544
545         if (lasso_inside(data->mcords, data->moves, x, y)) {
546                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
547         }
548 }
549 static void do_lasso_select_lattice(ViewContext *vc, short mcords[][2], short moves, short select)
550 {
551         struct { short (*mcords)[2]; short moves; short select; } data;
552
553         /* set editdata in vc */
554         data.mcords = mcords;
555         data.moves = moves;
556         data.select = select;
557
558         lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data);
559 }
560
561 static void do_lasso_select_armature(ViewContext *vc, short mcords[][2], short moves, short select)
562 {
563         EditBone *ebone;
564         float vec[3];
565         short sco1[2], sco2[2], didpoint;
566         
567         /* set editdata in vc */
568         
569         for (ebone=G.edbo.first; ebone; ebone=ebone->next) {
570
571                 VECCOPY(vec, ebone->head);
572                 Mat4MulVecfl(G.obedit->obmat, vec);
573                 project_short(vc->ar, vc->v3d, vec, sco1);
574                 VECCOPY(vec, ebone->tail);
575                 Mat4MulVecfl(G.obedit->obmat, vec);
576                 project_short(vc->ar, vc->v3d, vec, sco2);
577                 
578                 didpoint= 0;
579                 if(lasso_inside(mcords, moves, sco1[0], sco1[1])) {
580                         if(select) ebone->flag |= BONE_ROOTSEL;
581                         else ebone->flag &= ~BONE_ROOTSEL;
582                         didpoint= 1;
583                 }
584                 if(lasso_inside(mcords, moves, sco2[0], sco2[1])) {
585                    if(select) ebone->flag |= BONE_TIPSEL;
586                    else ebone->flag &= ~BONE_TIPSEL;
587                    didpoint= 1;
588                 }
589                 /* if one of points selected, we skip the bone itself */
590                 if(didpoint==0 && lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
591                         if(select) ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
592                         else ebone->flag &= ~(BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
593                 }
594         }
595         // XXX countall();      /* abused for flushing selection!!!! */
596 }
597
598 static void do_lasso_select_facemode(ViewContext *vc, short mcords[][2], short moves, short select)
599 {
600         Object *ob= vc->obact;
601         Mesh *me= ob?ob->data:NULL;
602         rcti rect;
603         
604         if(me==NULL || me->mtface==NULL) return;
605         if(me->totface==0) return;
606         
607         em_vertoffs= me->totface+1;     /* max index array */
608         
609         lasso_select_boundbox(&rect, mcords, moves);
610         EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
611         
612         EM_backbuf_checkAndSelectTFaces(me, select);
613         
614         EM_free_backbuf();
615         
616 // XXX  object_tface_flags_changed(ob, 0);
617 }
618
619 #if 0
620 static void do_lasso_select_node(short mcords[][2], short moves, short select)
621 {
622         SpaceNode *snode = sa->spacedata.first;
623         
624         bNode *node;
625         rcti rect;
626         short node_cent[2];
627         float node_centf[2];
628         
629         lasso_select_boundbox(&rect, mcords, moves);
630         
631         /* store selection in temp test flag */
632         for(node= snode->edittree->nodes.first; node; node= node->next) {
633                 
634                 node_centf[0] = (node->totr.xmin+node->totr.xmax)/2;
635                 node_centf[1] = (node->totr.ymin+node->totr.ymax)/2;
636                 
637                 ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
638                 if (BLI_in_rcti(&rect, node_cent[0], node_cent[1]) && lasso_inside(mcords, moves, node_cent[0], node_cent[1])) {
639                         if (select) {
640                                 node->flag |= SELECT;
641                         } else {
642                                 node->flag &= ~SELECT;
643                         }
644                 }
645         }
646         BIF_undo_push("Lasso select nodes");
647 }
648 #endif
649
650 void view3d_lasso_select(ViewContext *vc, short mcords[][2], short moves, short select)
651 {
652         if(G.obedit==NULL) {
653                 if(FACESEL_PAINT_TEST)
654                         do_lasso_select_facemode(vc, mcords, moves, select);
655                 else if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))
656                         ;
657 // XX           else if(G.f & G_PARTICLEEDIT)
658 //                      PE_do_lasso_select(mcords, moves, select);
659                 else  
660                         do_lasso_select_objects(vc, mcords, moves, select);
661         }
662         else if(G.obedit->type==OB_MESH) {
663                 do_lasso_select_mesh(vc, mcords, moves, select);
664         } else if(G.obedit->type==OB_CURVE || G.obedit->type==OB_SURF) 
665                 do_lasso_select_curve(vc, mcords, moves, select);
666         else if(G.obedit->type==OB_LATTICE) 
667                 do_lasso_select_lattice(vc, mcords, moves, select);
668         else if(G.obedit->type==OB_ARMATURE)
669                 do_lasso_select_armature(vc, mcords, moves, select);
670
671         BIF_undo_push("Lasso select");
672         
673 }
674
675 static EnumPropertyItem lasso_select_types[] = {
676         {0, "SELECT", "Select", ""},
677         {1, "DESELECT", "Deselect", ""},
678         {0, NULL, NULL, NULL}
679 };
680
681
682 /* lasso operator gives properties, but since old code works
683    with short array we convert */
684 static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
685 {
686         ViewContext vc;
687         int select, i= 0;
688         short mcords[1024][2];
689
690         RNA_BEGIN(op->ptr, itemptr, "path") {
691                 float loc[2];
692                 
693                 RNA_float_get_array(&itemptr, "loc", loc);
694                 mcords[i][0]= (short)loc[0];
695                 mcords[i][1]= (short)loc[1];
696                 i++;
697                 if(i>=1024) break;
698         }
699         RNA_END;
700         
701         /* setup view context for argument to callbacks */
702         view3d_set_viewcontext(C, &vc);
703         
704         select= RNA_enum_is_equal(op->ptr, "type", "SELECT");
705         view3d_lasso_select(&vc, mcords, i, select);
706         
707         return OPERATOR_FINISHED;
708 }
709
710 void VIEW3D_OT_lasso_select(wmOperatorType *ot)
711 {
712         PropertyRNA *prop;
713         
714         ot->name= "Lasso Select";
715         ot->idname= "VIEW3D_OT_lasso_select";
716         
717         ot->invoke= WM_gesture_lasso_invoke;
718         ot->modal= WM_gesture_lasso_modal;
719         ot->exec= view3d_lasso_select_exec;
720         
721         ot->poll= WM_operator_winactive;
722         
723         prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
724         RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
725         
726         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
727         RNA_def_property_enum_items(prop, lasso_select_types);
728
729 }
730
731
732 /* ************************************************* */
733
734 #if 0
735 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
736 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
737 {
738         Base *base;
739         unsigned int *bufmin,*bufmax;
740         int a,b,rc,tel,aantal,dirvec[4][2],maxob;
741         unsigned int retval=0;
742         
743         base= LASTBASE;
744         if(base==0) return 0;
745         maxob= base->selcol;
746
747         aantal= (size-1)/2;
748         rc= 0;
749
750         dirvec[0][0]= 1;
751         dirvec[0][1]= 0;
752         dirvec[1][0]= 0;
753         dirvec[1][1]= -size;
754         dirvec[2][0]= -1;
755         dirvec[2][1]= 0;
756         dirvec[3][0]= 0;
757         dirvec[3][1]= size;
758
759         bufmin= buf;
760         bufmax= buf+ size*size;
761         buf+= aantal*size+ aantal;
762
763         for(tel=1;tel<=size;tel++) {
764
765                 for(a=0;a<2;a++) {
766                         for(b=0;b<tel;b++) {
767
768                                 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
769                                 if( *buf==dontdo ) retval= dontdo;      /* if only color dontdo is available, still return dontdo */
770                                 
771                                 buf+= (dirvec[rc][0]+dirvec[rc][1]);
772
773                                 if(buf<bufmin || buf>=bufmax) return retval;
774                         }
775                         rc++;
776                         rc &= 3;
777                 }
778         }
779         return retval;
780 }
781 #endif
782
783 /* ************************** mouse select ************************* */
784
785
786 #define MAXPICKBUF      10000
787 /* The max number of menu items in an object select menu */
788 #define SEL_MENU_SIZE   22
789
790
791 static void deselectall_except(Scene *scene, Base *b)   /* deselect all except b */
792 {
793         Base *base;
794         
795         for(base= FIRSTBASE; base; base= base->next) {
796                 if (base->flag & SELECT) {
797                         if(b!=base) {
798                                 ED_base_object_select(base, BA_DESELECT);
799                         }
800                 }
801         }
802 }
803
804 static Base *mouse_select_menu(ViewContext *vc, unsigned int *buffer, int hits, short *mval)
805 {
806         Scene *scene= vc->scene;
807         View3D *v3d= vc->v3d;
808         Base *baseList[SEL_MENU_SIZE]={NULL}; /*baseList is used to store all possible bases to bring up a menu */
809         Base *base;
810         short baseCount = 0;
811         char menuText[20 + SEL_MENU_SIZE*32] = "Select Object%t";       /* max ob name = 22 */
812         char str[32];
813         
814         for(base=FIRSTBASE; base; base= base->next) {
815                 if (BASE_SELECTABLE(v3d, base)) {
816                         baseList[baseCount] = NULL;
817                         
818                         /* two selection methods, the CTRL select uses max dist of 15 */
819                         if(buffer) {
820                                 int a;
821                                 for(a=0; a<hits; a++) {
822                                         /* index was converted */
823                                         if(base->selcol==buffer[ (4 * a) + 3 ]) baseList[baseCount] = base;
824                                 }
825                         }
826                         else {
827                                 int temp, dist=15;
828                                 
829                                 project_short(vc->ar, vc->v3d, base->object->obmat[3], &base->sx);
830                                 
831                                 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
832                                 if(temp<dist ) baseList[baseCount] = base;
833                         }
834                         
835                         if(baseList[baseCount]) {
836                                 if (baseCount < SEL_MENU_SIZE) {
837                                         baseList[baseCount] = base;
838                                         sprintf(str, "|%s %%x%d", base->object->id.name+2, baseCount+1);        /* max ob name == 22 */
839                                                         strcat(menuText, str);
840                                                         baseCount++;
841                                 }
842                         }
843                 }
844         }
845
846         if(baseCount<=1) return baseList[0];
847         else {
848                 baseCount = -1; // XXX = pupmenu(menuText);
849                 
850                 if (baseCount != -1) { /* If nothing is selected then dont do anything */
851                         return baseList[baseCount-1];
852                 }
853                 else return NULL;
854         }
855 }
856
857 /* we want a select buffer with bones, if there are... */
858 /* so check three selection levels and compare */
859 static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, short *mval)
860 {
861         rcti rect;
862         int offs;
863         short a, hits15, hits9=0, hits5=0;
864         short has_bones15=0, has_bones9=0, has_bones5=0;
865         
866         BLI_init_rcti(&rect, mval[0]-14, mval[0]+14, mval[1]-14, mval[1]+14);
867         hits15= view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
868         if(hits15>0) {
869                 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
870                 
871                 offs= 4*hits15;
872                 BLI_init_rcti(&rect, mval[0]-9, mval[0]+9, mval[1]-9, mval[1]+9);
873                 hits9= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
874                 if(hits9>0) {
875                         for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
876                         
877                         offs+= 4*hits9;
878                         BLI_init_rcti(&rect, mval[0]-5, mval[0]+5, mval[1]-5, mval[1]+5);
879                         hits5= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
880                         if(hits5>0) {
881                                 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
882                         }
883                 }
884                 
885                 if(has_bones5) {
886                         offs= 4*hits15 + 4*hits9;
887                         memcpy(buffer, buffer+offs, 4*offs);
888                         return hits5;
889                 }
890                 if(has_bones9) {
891                         offs= 4*hits15;
892                         memcpy(buffer, buffer+offs, 4*offs);
893                         return hits9;
894                 }
895                 if(has_bones15) {
896                         return hits15;
897                 }
898                 
899                 if(hits5>0) {
900                         offs= 4*hits15 + 4*hits9;
901                         memcpy(buffer, buffer+offs, 4*offs);
902                         return hits5;
903                 }
904                 if(hits9>0) {
905                         offs= 4*hits15;
906                         memcpy(buffer, buffer+offs, 4*offs);
907                         return hits9;
908                 }
909                 return hits15;
910         }
911         
912         return 0;
913 }
914
915
916 /* mval is region coords */
917 static void mouse_select(bContext *C, short *mval, short extend, short obcenter)
918 {
919         ViewContext vc;
920         ARegion *ar= CTX_wm_region(C);
921         View3D *v3d= (View3D *)CTX_wm_space_data(C);
922         Scene *scene= CTX_data_scene(C);
923         Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
924         unsigned int buffer[4*MAXPICKBUF];
925         int temp, a, dist=100;
926         short hits;
927         
928         /* setup view context for argument to callbacks */
929         view3d_set_viewcontext(C, &vc);
930         
931         /* always start list from basact in wire mode */
932         startbase=  FIRSTBASE;
933         if(BASACT && BASACT->next) startbase= BASACT->next;
934         
935         /* This block uses the control key to make the object selected by its center point rather then its contents */
936         /* XXX later on, in editmode do not activate */
937         if(G.obedit==NULL && obcenter) {
938                 
939                 /* note; shift+alt goes to group-flush-selecting */
940                 /* XXX solve */
941                 if(0) 
942                         basact= mouse_select_menu(&vc, NULL, 0, mval);
943                 else {
944                         base= startbase;
945                         while(base) {
946                                 if (BASE_SELECTABLE(v3d, base)) {
947                                         project_short(ar, v3d, base->object->obmat[3], &base->sx);
948                                         
949                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
950                                         if(base==BASACT) temp+=10;
951                                         if(temp<dist ) {
952                                                 
953                                                 dist= temp;
954                                                 basact= base;
955                                         }
956                                 }
957                                 base= base->next;
958                                 
959                                 if(base==0) base= FIRSTBASE;
960                                 if(base==startbase) break;
961                         }
962                 }
963         }
964         else {
965                 /* if objects have posemode set, the bones are in the same selection buffer */
966                 
967                 hits= mixed_bones_object_selectbuffer(&vc, buffer, mval);
968                 
969                 if(hits>0) {
970                         int has_bones= 0;
971                         
972                         for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
973
974                         /* note; shift+alt goes to group-flush-selecting */
975                         if(has_bones==0 && 0) 
976                                 basact= mouse_select_menu(&vc, buffer, hits, mval);
977                         else {
978                                 static short lastmval[2]={-100, -100};
979                                 int donearest= 0;
980                                 
981                                 /* define if we use solid nearest select or not */
982                                 if(v3d->drawtype>OB_WIRE) {
983                                         donearest= 1;
984                                         if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
985                                                 if(!has_bones)  /* hrms, if theres bones we always do nearest */
986                                                         donearest= 0;
987                                         }
988                                 }
989                                 lastmval[0]= mval[0]; lastmval[1]= mval[1];
990                                 
991                                 if(donearest) {
992                                         unsigned int min= 0xFFFFFFFF;
993                                         int selcol= 0, notcol=0;
994                                         
995
996                                         if(has_bones) {
997                                                 /* we skip non-bone hits */
998                                                 for(a=0; a<hits; a++) {
999                                                         if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
1000                                                                 min= buffer[4*a+1];
1001                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1002                                                         }
1003                                                 }
1004                                         }
1005                                         else {
1006                                                 /* only exclude active object when it is selected... */
1007                                                 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol; 
1008                                         
1009                                                 for(a=0; a<hits; a++) {
1010                                                         if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1011                                                                 min= buffer[4*a+1];
1012                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1013                                                         }
1014                                                 }
1015                                         }
1016
1017                                         base= FIRSTBASE;
1018                                         while(base) {
1019                                                 if(base->lay & v3d->lay) {
1020                                                         if(base->selcol==selcol) break;
1021                                                 }
1022                                                 base= base->next;
1023                                         }
1024                                         if(base) basact= base;
1025                                 }
1026                                 else {
1027                                         
1028                                         base= startbase;
1029                                         while(base) {
1030                                                 /* skip objects with select restriction, to prevent prematurely ending this loop
1031                                                  * with an un-selectable choice */
1032                                                 if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1033                                                         base=base->next;
1034                                                         if(base==NULL) base= FIRSTBASE;
1035                                                         if(base==startbase) break;
1036                                                 }
1037                                         
1038                                                 if(base->lay & v3d->lay) {
1039                                                         for(a=0; a<hits; a++) {
1040                                                                 if(has_bones) {
1041                                                                         /* skip non-bone objects */
1042                                                                         if((buffer[4*a+3] & 0xFFFF0000)) {
1043                                                                                 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1044                                                                                         basact= base;
1045                                                                         }
1046                                                                 }
1047                                                                 else {
1048                                                                         if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1049                                                                                 basact= base;
1050                                                                 }
1051                                                         }
1052                                                 }
1053                                                 
1054                                                 if(basact) break;
1055                                                 
1056                                                 base= base->next;
1057                                                 if(base==NULL) base= FIRSTBASE;
1058                                                 if(base==startbase) break;
1059                                         }
1060                                 }
1061                         }
1062                         
1063                         if(has_bones && basact) {
1064                                 if(0) {// XXX do_pose_selectbuffer(basact, buffer, hits) ) {    /* then bone is found */
1065                                 
1066                                         /* we make the armature selected: 
1067                                            not-selected active object in posemode won't work well for tools */
1068                                         basact->flag|= SELECT;
1069                                         basact->object->flag= basact->flag;
1070                                         
1071                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1072                                         if(G.f & G_WEIGHTPAINT) {
1073                                                 /* prevent activating */
1074                                                 basact= NULL;
1075                                         }
1076                                         
1077                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, basact->object);
1078                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, basact->object);
1079
1080                                 }
1081                                 /* prevent bone selecting to pass on to object selecting */
1082                                 if(basact==BASACT)
1083                                         basact= NULL;
1084                         }
1085                 }
1086         }
1087         
1088         /* so, do we have something selected? */
1089         if(basact) {
1090                 
1091                 if(G.obedit) {
1092                         /* only do select */
1093                         deselectall_except(scene, basact);
1094                         ED_base_object_select(basact, BA_SELECT);
1095                 }
1096                 /* also prevent making it active on mouse selection */
1097                 else if (BASE_SELECTABLE(v3d, basact)) {
1098
1099                         oldbasact= BASACT;
1100                         BASACT= basact;
1101                         
1102                         if(!extend) {
1103                                 deselectall_except(scene, basact);
1104                                 ED_base_object_select(basact, BA_SELECT);
1105                         }
1106                         else if(0) {
1107                                 // XXX select_all_from_groups(basact);
1108                         }
1109                         else {
1110                                 if(basact->flag & SELECT) {
1111                                         if(basact==oldbasact)
1112                                                 ED_base_object_select(basact, BA_DESELECT);
1113                                 }
1114                                 else ED_base_object_select(basact, BA_SELECT);
1115                         }
1116
1117                         if(oldbasact != basact) {
1118                                 ED_base_object_activate(C, basact); /* adds notifier */
1119                         }
1120
1121                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1122                         
1123                 }
1124         }
1125
1126 }
1127
1128 /* ********************  border and circle ************************************** */
1129
1130
1131 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1132 {
1133         int radsq= rad*rad;
1134         float v1[2], v2[2], v3[2];
1135         
1136         /* check points in circle itself */
1137         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1138         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1139         
1140         /* pointdistline */
1141         v3[0]= centx;
1142         v3[1]= centy;
1143         v1[0]= x1;
1144         v1[1]= y1;
1145         v2[0]= x2;
1146         v2[1]= y2;
1147         
1148         if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1149         
1150         return 0;
1151 }
1152
1153 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1154 {
1155         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1156
1157         if (BLI_in_rcti(data->rect, x, y)) {
1158                 if (bp) {
1159                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1160                 } else {
1161                         if (G.f & G_HIDDENHANDLES) {
1162                                 /* can only be beztindex==0 here since handles are hidden */
1163                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1164                         } else {
1165                                 if (beztindex==0) {
1166                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1167                                 } else if (beztindex==1) {
1168                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1169                                 } else {
1170                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1171                                 }
1172                         }
1173                 }
1174         }
1175 }
1176 static void do_nurbs_box_select(ViewContext *vc, rcti *rect, int select)
1177 {
1178         struct { ViewContext vc; rcti *rect; int select; } data;
1179         
1180         data.vc= *vc;
1181         data.rect = rect;
1182         data.select = select;
1183
1184         nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data);
1185 }
1186
1187 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1188 {
1189         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1190
1191         if (BLI_in_rcti(data->rect, x, y)) {
1192                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1193         }
1194 }
1195 static void do_lattice_box_select(ViewContext *vc, rcti *rect, int select)
1196 {
1197         struct { ViewContext vc; rcti *rect; int select, pass, done; } data;
1198
1199         data.vc= *vc;
1200         data.rect = rect;
1201         data.select = select;
1202
1203         lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data);
1204 }
1205
1206 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1207 {
1208         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1209
1210         if (BLI_in_rcti(data->rect, x, y)) {
1211                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1212         }
1213 }
1214 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1215 {
1216         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1217
1218         if(EM_check_backbuf(em_solidoffs+index)) {
1219                 if (data->pass==0) {
1220                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1221                                 EM_select_edge(eed, data->select);
1222                                 data->done = 1;
1223                         }
1224                 } else {
1225                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1226                                 EM_select_edge(eed, data->select);
1227                         }
1228                 }
1229         }
1230 }
1231 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1232 {
1233         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1234
1235         if (BLI_in_rcti(data->rect, x, y)) {
1236                 EM_select_face_fgon(data->vc.em, efa, data->select);
1237         }
1238 }
1239 static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select)
1240 {
1241         struct { ViewContext vc; rcti *rect; short select, pass, done; } data;
1242         int bbsel;
1243         
1244         data.vc= *vc;
1245         data.rect = rect;
1246         data.select = select;
1247         data.pass = 0;
1248         data.done = 0;
1249
1250         bbsel= EM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1251
1252         if(vc->scene->selectmode & SCE_SELECT_VERTEX) {
1253                 if (bbsel) {
1254                         EM_backbuf_checkAndSelectVerts(vc->em, select);
1255                 } else {
1256                         mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1);
1257                 }
1258         }
1259         if(vc->scene->selectmode & SCE_SELECT_EDGE) {
1260                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1261
1262                 data.pass = 0;
1263                 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1264
1265                 if (data.done==0) {
1266                         data.pass = 1;
1267                         mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1268                 }
1269         }
1270         
1271         if(vc->scene->selectmode & SCE_SELECT_FACE) {
1272                 if(bbsel) {
1273                         EM_backbuf_checkAndSelectFaces(vc->em, select);
1274                 } else {
1275                         mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data);
1276                 }
1277         }
1278         
1279         EM_free_backbuf();
1280                 
1281         EM_selectmode_flush(vc->em);
1282 }
1283
1284 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
1285 {
1286         ViewContext vc;
1287         Scene *scene= CTX_data_scene(C);
1288         ScrArea *sa= CTX_wm_area(C);
1289         View3D *v3d= sa->spacedata.first;
1290         rcti rect;
1291         Base *base;
1292         MetaElem *ml;
1293         unsigned int buffer[4*MAXPICKBUF];
1294         int a, index;
1295         short hits, val;
1296
1297         view3d_operator_needs_opengl(C);
1298         
1299         /* setup view context for argument to callbacks */
1300         view3d_set_viewcontext(C, &vc);
1301         
1302         val= RNA_int_get(op->ptr, "event_type");
1303         rect.xmin= RNA_int_get(op->ptr, "xmin");
1304         rect.ymin= RNA_int_get(op->ptr, "ymin");
1305         rect.xmax= RNA_int_get(op->ptr, "xmax");
1306         rect.ymax= RNA_int_get(op->ptr, "ymax");
1307         
1308         if(G.obedit==NULL && (FACESEL_PAINT_TEST)) {
1309 // XXX          face_borderselect();
1310                 return OPERATOR_FINISHED;
1311         }
1312         else if(G.obedit==NULL && (G.f & G_PARTICLEEDIT)) {
1313 // XXX          PE_borderselect();
1314                 return OPERATOR_FINISHED;
1315         }
1316         
1317         if(G.obedit) {
1318                 if(G.obedit->type==OB_MESH) {
1319                         Mesh *me= G.obedit->data;
1320                         vc.em= me->edit_mesh;
1321                         do_mesh_box_select(&vc, &rect, (val==LEFTMOUSE));
1322 //                      if (EM_texFaceCheck())
1323                         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, G.obedit);
1324                         
1325                 }
1326                 else if(ELEM(G.obedit->type, OB_CURVE, OB_SURF)) {
1327                         do_nurbs_box_select(&vc, &rect, val==LEFTMOUSE);
1328 //                      allqueue(REDRAWVIEW3D, 0);
1329                 }
1330                 else if(G.obedit->type==OB_MBALL) {
1331                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1332                         
1333                         ml= NULL; // XXX editelems.first;
1334                         
1335                         while(ml) {
1336                                 for(a=0; a<hits; a++) {
1337                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1338                                                 ml->flag |= MB_SCALE_RAD;
1339                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1340                                                 else ml->flag &= ~SELECT;
1341                                                 break;
1342                                         }
1343                                         if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1344                                                 ml->flag &= ~MB_SCALE_RAD;
1345                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1346                                                 else ml->flag &= ~SELECT;
1347                                                 break;
1348                                         }
1349                                 }
1350                                 ml= ml->next;
1351                         }
1352                 }
1353                 else if(G.obedit->type==OB_ARMATURE) {
1354                         EditBone *ebone;
1355                         
1356                         /* clear flag we use to detect point was affected */
1357                         for(ebone= G.edbo.first; ebone; ebone= ebone->next)
1358                                 ebone->flag &= ~BONE_DONE;
1359                         
1360                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1361                         
1362                         /* first we only check points inside the border */
1363                         for (a=0; a<hits; a++){
1364                                 index = buffer[(4*a)+3];
1365                                 if (index!=-1) {
1366                                         ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1367                                         if (index & BONESEL_TIP) {
1368                                                 ebone->flag |= BONE_DONE;
1369                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
1370                                                 else ebone->flag &= ~BONE_TIPSEL;
1371                                         }
1372                                         
1373                                         if (index & BONESEL_ROOT) {
1374                                                 ebone->flag |= BONE_DONE;
1375                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
1376                                                 else ebone->flag &= ~BONE_ROOTSEL;
1377                                         }
1378                                 }
1379                         }
1380                         
1381                         /* now we have to flush tag from parents... */
1382                         for(ebone= G.edbo.first; ebone; ebone= ebone->next) {
1383                                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1384                                         if(ebone->parent->flag & BONE_DONE)
1385                                                 ebone->flag |= BONE_DONE;
1386                                 }
1387                         }
1388                         
1389                         /* only select/deselect entire bones when no points where in the rect */
1390                         for (a=0; a<hits; a++){
1391                                 index = buffer[(4*a)+3];
1392                                 if (index!=-1) {
1393                                         ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1394                                         if (index & BONESEL_BONE) {
1395                                                 if(!(ebone->flag & BONE_DONE)) {
1396                                                         if (val==LEFTMOUSE)
1397                                                                 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1398                                                         else
1399                                                                 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1400                                                 }
1401                                         }
1402                                 }
1403                         }
1404                         
1405                 }
1406                 else if(G.obedit->type==OB_LATTICE) {
1407                         do_lattice_box_select(&vc, &rect, val==LEFTMOUSE);
1408                 }
1409         }
1410         else {  /* no editmode, unified for bones and objects */
1411                 Bone *bone;
1412                 unsigned int *vbuffer=NULL; /* selection buffer */
1413                 unsigned int *col;                      /* color in buffer      */
1414                 short selecting = 0;
1415                 Object *ob= OBACT;
1416                 int bone_only;
1417                 
1418                 if((ob) && (ob->flag & OB_POSEMODE))
1419                         bone_only= 1;
1420                 else
1421                         bone_only= 0;
1422                 
1423                 if (val==LEFTMOUSE)
1424                         selecting = 1;
1425                 
1426                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1427                 vbuffer = MEM_mallocN(4 * (G.totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1428                 hits= view3d_opengl_select(&vc, vbuffer, 4*(G.totobj+MAXPICKBUF), &rect);
1429                 /*
1430                 LOGIC NOTES (theeth):
1431                 The buffer and ListBase have the same relative order, which makes the selection
1432                 very simple. Loop through both data sets at the same time, if the color
1433                 is the same as the object, we have a hit and can move to the next color
1434                 and object pair, if not, just move to the next object,
1435                 keeping the same color until we have a hit.
1436
1437                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1438                 does it incorrectly.
1439                 */
1440
1441                 if (hits>0) { /* no need to loop if there's no hit */
1442                         base= FIRSTBASE;
1443                         col = vbuffer + 3;
1444                         
1445                         while(base && hits) {
1446                                 Base *next = base->next;
1447                                 if(base->lay & v3d->lay) {
1448                                         while (base->selcol == (*col & 0xFFFF)) {       /* we got an object */
1449                                                 
1450                                                 if(*col & 0xFFFF0000) {                                 /* we got a bone */
1451                                                         bone = NULL; // XXX get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1452                                                         if(bone) {
1453                                                                 if(selecting) {
1454                                                                         bone->flag |= BONE_SELECTED;
1455 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 1);
1456                                                                 }
1457                                                                 else {
1458                                                                         bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1459 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 0);
1460                                                                 }
1461                                                         }
1462                                                 }
1463                                                 else if(!bone_only) {
1464                                                         if (selecting)
1465                                                                 ED_base_object_select(base, BA_SELECT);
1466                                                         else
1467                                                                 ED_base_object_select(base, BA_DESELECT);
1468                                                 }
1469
1470                                                 col+=4; /* next color */
1471                                                 hits--;
1472                                                 if(hits==0) break;
1473                                         }
1474                                 }
1475                                 
1476                                 base= next;
1477                         }
1478
1479                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1480
1481                 }
1482                 MEM_freeN(vbuffer);
1483         }
1484         
1485         return OPERATOR_FINISHED;
1486
1487
1488
1489 /* *****************Selection Operators******************* */
1490 static EnumPropertyItem prop_select_types[] = {
1491         {0, "EXCLUSIVE", "Exclusive", ""},
1492         {1, "EXTEND", "Extend", ""},
1493         {0, NULL, NULL, NULL}
1494 };
1495
1496 /* ****** Border Select ****** */
1497 void VIEW3D_OT_borderselect(wmOperatorType *ot)
1498 {
1499         PropertyRNA *prop;
1500         
1501         /* identifiers */
1502         ot->name= "Border Select";
1503         ot->idname= "VIEW3D_OT_borderselect";
1504         
1505         /* api callbacks */
1506         ot->invoke= WM_border_select_invoke;
1507         ot->exec= view3d_borderselect_exec;
1508         ot->modal= WM_border_select_modal;
1509         
1510         ot->poll= ED_operator_view3d_active;
1511         
1512         /* rna */
1513         RNA_def_property(ot->srna, "event_type", PROP_INT, PROP_NONE);
1514         RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
1515         RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
1516         RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
1517         RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
1518
1519         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
1520         RNA_def_property_enum_items(prop, prop_select_types);
1521 }
1522
1523 /* ****** Mouse Select ****** */
1524
1525
1526 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1527 {
1528         ARegion *ar= CTX_wm_region(C);
1529         Object *obedit= CTX_data_edit_object(C);
1530         short extend= RNA_enum_is_equal(op->ptr, "type", "EXTEND");
1531         short mval[2];  
1532         
1533         mval[0]= event->x - ar->winrct.xmin;
1534         mval[1]= event->y - ar->winrct.ymin;
1535
1536         view3d_operator_needs_opengl(C);
1537         
1538         if(obedit) {
1539                 if(obedit->type==OB_MESH)
1540                         mouse_mesh(C, mval, extend);
1541         }
1542         else 
1543                 mouse_select(C, mval, extend, 0);
1544         
1545         /* allowing tweaks */
1546         return OPERATOR_PASS_THROUGH;
1547 }
1548
1549 void VIEW3D_OT_select(wmOperatorType *ot)
1550 {
1551         PropertyRNA *prop;
1552
1553         /* identifiers */
1554         ot->name= "Activate/Select";
1555         ot->idname= "VIEW3D_OT_select";
1556         
1557         /* api callbacks */
1558         ot->invoke= view3d_select_invoke;
1559         ot->poll= ED_operator_view3d_active;
1560
1561         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
1562         RNA_def_property_enum_items(prop, prop_select_types);
1563 }
1564
1565
1566 /* -------------------- circle select --------------------------------------------- */
1567
1568 static void mesh_circle_doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1569 {
1570         struct { short select, mval[2]; float radius; } *data = userData;
1571         int mx = x - data->mval[0], my = y - data->mval[1];
1572         float r = sqrt(mx*mx + my*my);
1573
1574         if (r<=data->radius) {
1575                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1576         }
1577 }
1578 static void mesh_circle_doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1579 {
1580         struct { short select, mval[2]; float radius; } *data = userData;
1581
1582         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1583                 EM_select_edge(eed, data->select);
1584         }
1585 }
1586 static void mesh_circle_doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1587 {
1588         struct { short select, mval[2]; float radius; } *data = userData;
1589         int mx = x - data->mval[0], my = y - data->mval[1];
1590         float r = sqrt(mx*mx + my*my);
1591         EditMesh *em= NULL; // XXX
1592         
1593         if (r<=data->radius) {
1594                 EM_select_face_fgon(em, efa, data->select);
1595         }
1596 }
1597
1598 static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1599 {
1600         int bbsel;
1601         
1602         if(vc->obedit==NULL && (FACESEL_PAINT_TEST)) {
1603                 Object *ob= vc->obact;
1604                 Mesh *me = ob?ob->data:NULL;
1605
1606                 if (me) {
1607                         em_vertoffs= me->totface+1;     /* max index array */
1608
1609                         bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1610                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1611                         EM_free_backbuf();
1612
1613 // XXX                  object_tface_flags_changed(OBACT, 0);
1614                 }
1615         }
1616         else {
1617                 struct { short select, mval[2]; float radius; } data;
1618                 
1619                 bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1620                 vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
1621
1622                 data.select = selecting;
1623                 data.mval[0] = mval[0];
1624                 data.mval[1] = mval[1];
1625                 data.radius = rad;
1626
1627                 if(vc->scene->selectmode & SCE_SELECT_VERTEX) {
1628                         if(bbsel) {
1629                                 EM_backbuf_checkAndSelectVerts(vc->em, selecting==LEFTMOUSE);
1630                         } else {
1631                                 mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, 1);
1632                         }
1633                 }
1634
1635                 if(vc->scene->selectmode & SCE_SELECT_EDGE) {
1636                         if (bbsel) {
1637                                 EM_backbuf_checkAndSelectEdges(vc->em, selecting==LEFTMOUSE);
1638                         } else {
1639                                 mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, 0);
1640                         }
1641                 }
1642                 
1643                 if(vc->scene->selectmode & SCE_SELECT_FACE) {
1644                         if(bbsel) {
1645                                 EM_backbuf_checkAndSelectFaces(vc->em, selecting==LEFTMOUSE);
1646                         } else {
1647                                 mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data);
1648                         }
1649                 }
1650
1651                 EM_free_backbuf();
1652                 EM_selectmode_flush(vc->em);
1653         }
1654 }
1655
1656
1657 static void nurbscurve_circle_doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1658 {
1659         struct { short select, mval[2]; float radius; } *data = userData;
1660         int mx = x - data->mval[0], my = y - data->mval[1];
1661         float r = sqrt(mx*mx + my*my);
1662
1663         if (r<=data->radius) {
1664                 if (bp) {
1665                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1666                 } else {
1667                         if (beztindex==0) {
1668                                 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1669                         } else if (beztindex==1) {
1670                                 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1671                         } else {
1672                                 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1673                         }
1674                 }
1675         }
1676 }
1677 static void nurbscurve_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1678 {
1679         struct { short select, mval[2]; float radius; } data;
1680
1681         /* set vc-> edit data */
1682         
1683         data.select = selecting;
1684         data.mval[0] = mval[0];
1685         data.mval[1] = mval[1];
1686         data.radius = rad;
1687
1688         nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data);
1689 }
1690
1691
1692 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, int x, int y)
1693 {
1694         struct { short select, mval[2]; float radius; } *data = userData;
1695         int mx = x - data->mval[0], my = y - data->mval[1];
1696         float r = sqrt(mx*mx + my*my);
1697
1698         if (r<=data->radius) {
1699                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1700         }
1701 }
1702 static void lattice_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1703 {
1704         struct { short select, mval[2]; float radius; } data;
1705
1706         /* set vc-> edit data */
1707         
1708         data.select = selecting;
1709         data.mval[0] = mval[0];
1710         data.mval[1] = mval[1];
1711         data.radius = rad;
1712
1713         lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data);
1714 }
1715
1716 /** Callbacks for circle selection in Editmode */
1717
1718 static void obedit_circle_select(ViewContext *vc, short selecting, short *mval, float rad) 
1719 {
1720         switch(vc->obedit->type) {              
1721         case OB_MESH:
1722                 mesh_circle_select(vc, selecting, mval, rad);
1723                 break;
1724         case OB_CURVE:
1725         case OB_SURF:
1726                 nurbscurve_circle_select(vc, selecting, mval, rad);
1727                 break;
1728         case OB_LATTICE:
1729                 lattice_circle_select(vc, selecting, mval, rad);
1730                 break;
1731         default:
1732                 return;
1733         }
1734 }
1735
1736 /* not a real operator, only for circle test */
1737 static int view3d_circle_select_exec(bContext *C, wmOperator *op)
1738 {
1739         ScrArea *sa= CTX_wm_area(C);
1740         ARegion *ar= CTX_wm_region(C);
1741         Scene *scene= CTX_data_scene(C);
1742         View3D *v3d= sa->spacedata.first;
1743         int x= RNA_int_get(op->ptr, "x");
1744         int y= RNA_int_get(op->ptr, "y");
1745         int radius= RNA_int_get(op->ptr, "radius");
1746         
1747         if(CTX_data_edit_object(C)) {
1748                 ViewContext vc;
1749                 short mval[2], selecting;
1750                 
1751                 view3d_set_viewcontext(C, &vc);
1752                 mval[0]= x;
1753                 mval[1]= y;
1754                 selecting= LEFTMOUSE==RNA_int_get(op->ptr, "event_type"); // XXX solve
1755                 obedit_circle_select(&vc, selecting, mval, (float)radius);
1756         }
1757         else {
1758                 Base *base;
1759                 
1760                 for(base= FIRSTBASE; base; base= base->next) {
1761                         if(base->lay & v3d->lay) {
1762                                 project_short(ar, v3d, base->object->obmat[3], &base->sx);
1763                                 if(base->sx!=IS_CLIPPED) {
1764                                         int dx= base->sx-x;
1765                                         int dy= base->sy-y;
1766                                         if( dx*dx + dy*dy < radius*radius)
1767                                                 ED_base_object_select(base, BA_SELECT);
1768                                 }
1769                         }
1770                 }
1771                 
1772                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1773         }
1774         
1775         return OPERATOR_FINISHED;
1776 }
1777
1778 void VIEW3D_OT_circle_select(wmOperatorType *ot)
1779 {
1780         ot->name= "Circle Select";
1781         ot->idname= "VIEW3D_OT_circle_select";
1782         
1783         ot->invoke= WM_gesture_circle_invoke;
1784         ot->modal= WM_gesture_circle_modal;
1785         ot->exec= view3d_circle_select_exec;
1786         ot->poll= ED_operator_view3d_active;
1787         
1788         RNA_def_property(ot->srna, "x", PROP_INT, PROP_NONE);
1789         RNA_def_property(ot->srna, "y", PROP_INT, PROP_NONE);
1790         RNA_def_property(ot->srna, "radius", PROP_INT, PROP_NONE);
1791         RNA_def_property(ot->srna, "event_type", PROP_INT, PROP_NONE);
1792         
1793 }