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
71 #include "WM_api.h"
72 #include "WM_types.h"
73
74 #include "RNA_access.h"
75 #include "RNA_define.h"
76
77 #include "ED_armature.h"
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         bArmature *arm= vc->obedit->data;
564         EditBone *ebone;
565         float vec[3];
566         short sco1[2], sco2[2], didpoint;
567         
568         /* set editdata in vc */
569         
570         for (ebone= arm->edbo->first; ebone; ebone=ebone->next) {
571
572                 VECCOPY(vec, ebone->head);
573                 Mat4MulVecfl(vc->obedit->obmat, vec);
574                 project_short(vc->ar, vc->v3d, vec, sco1);
575                 VECCOPY(vec, ebone->tail);
576                 Mat4MulVecfl(vc->obedit->obmat, vec);
577                 project_short(vc->ar, vc->v3d, vec, sco2);
578                 
579                 didpoint= 0;
580                 if(lasso_inside(mcords, moves, sco1[0], sco1[1])) {
581                         if(select) ebone->flag |= BONE_ROOTSEL;
582                         else ebone->flag &= ~BONE_ROOTSEL;
583                         didpoint= 1;
584                 }
585                 if(lasso_inside(mcords, moves, sco2[0], sco2[1])) {
586                    if(select) ebone->flag |= BONE_TIPSEL;
587                    else ebone->flag &= ~BONE_TIPSEL;
588                    didpoint= 1;
589                 }
590                 /* if one of points selected, we skip the bone itself */
591                 if(didpoint==0 && lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
592                         if(select) ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
593                         else ebone->flag &= ~(BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
594                 }
595         }
596         // XXX countall();      /* abused for flushing selection!!!! */
597 }
598
599 static void do_lasso_select_facemode(ViewContext *vc, short mcords[][2], short moves, short select)
600 {
601         Object *ob= vc->obact;
602         Mesh *me= ob?ob->data:NULL;
603         rcti rect;
604         
605         if(me==NULL || me->mtface==NULL) return;
606         if(me->totface==0) return;
607         
608         em_vertoffs= me->totface+1;     /* max index array */
609         
610         lasso_select_boundbox(&rect, mcords, moves);
611         EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
612         
613         EM_backbuf_checkAndSelectTFaces(me, select);
614         
615         EM_free_backbuf();
616         
617 // XXX  object_tface_flags_changed(ob, 0);
618 }
619
620 #if 0
621 static void do_lasso_select_node(short mcords[][2], short moves, short select)
622 {
623         SpaceNode *snode = sa->spacedata.first;
624         
625         bNode *node;
626         rcti rect;
627         short node_cent[2];
628         float node_centf[2];
629         
630         lasso_select_boundbox(&rect, mcords, moves);
631         
632         /* store selection in temp test flag */
633         for(node= snode->edittree->nodes.first; node; node= node->next) {
634                 
635                 node_centf[0] = (node->totr.xmin+node->totr.xmax)/2;
636                 node_centf[1] = (node->totr.ymin+node->totr.ymax)/2;
637                 
638                 ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
639                 if (BLI_in_rcti(&rect, node_cent[0], node_cent[1]) && lasso_inside(mcords, moves, node_cent[0], node_cent[1])) {
640                         if (select) {
641                                 node->flag |= SELECT;
642                         } else {
643                                 node->flag &= ~SELECT;
644                         }
645                 }
646         }
647         BIF_undo_push("Lasso select nodes");
648 }
649 #endif
650
651 void view3d_lasso_select(ViewContext *vc, short mcords[][2], short moves, short select)
652 {
653         if(vc->obedit==NULL) {
654                 if(FACESEL_PAINT_TEST)
655                         do_lasso_select_facemode(vc, mcords, moves, select);
656                 else if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))
657                         ;
658 // XX           else if(G.f & G_PARTICLEEDIT)
659 //                      PE_do_lasso_select(mcords, moves, select);
660                 else  
661                         do_lasso_select_objects(vc, mcords, moves, select);
662         }
663         else if(vc->obedit->type==OB_MESH) {
664                 do_lasso_select_mesh(vc, mcords, moves, select);
665         } else if(vc->obedit->type==OB_CURVE || vc->obedit->type==OB_SURF) 
666                 do_lasso_select_curve(vc, mcords, moves, select);
667         else if(vc->obedit->type==OB_LATTICE) 
668                 do_lasso_select_lattice(vc, mcords, moves, select);
669         else if(vc->obedit->type==OB_ARMATURE)
670                 do_lasso_select_armature(vc, mcords, moves, select);
671
672         BIF_undo_push("Lasso select");
673         
674 }
675
676 static EnumPropertyItem lasso_select_types[] = {
677         {0, "SELECT", "Select", ""},
678         {1, "DESELECT", "Deselect", ""},
679         {0, NULL, NULL, NULL}
680 };
681
682
683 /* lasso operator gives properties, but since old code works
684    with short array we convert */
685 static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
686 {
687         ViewContext vc;
688         int select, i= 0;
689         short mcords[1024][2];
690
691         RNA_BEGIN(op->ptr, itemptr, "path") {
692                 float loc[2];
693                 
694                 RNA_float_get_array(&itemptr, "loc", loc);
695                 mcords[i][0]= (short)loc[0];
696                 mcords[i][1]= (short)loc[1];
697                 i++;
698                 if(i>=1024) break;
699         }
700         RNA_END;
701         
702         /* setup view context for argument to callbacks */
703         view3d_set_viewcontext(C, &vc);
704         
705         select= RNA_enum_is_equal(op->ptr, "type", "SELECT");
706         view3d_lasso_select(&vc, mcords, i, select);
707         
708         return OPERATOR_FINISHED;
709 }
710
711 void VIEW3D_OT_lasso_select(wmOperatorType *ot)
712 {
713         PropertyRNA *prop;
714         
715         ot->name= "Lasso Select";
716         ot->idname= "VIEW3D_OT_lasso_select";
717         
718         ot->invoke= WM_gesture_lasso_invoke;
719         ot->modal= WM_gesture_lasso_modal;
720         ot->exec= view3d_lasso_select_exec;
721         
722         ot->poll= WM_operator_winactive;
723         
724         prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
725         RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
726         
727         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
728         RNA_def_property_enum_items(prop, lasso_select_types);
729
730 }
731
732
733 /* ************************************************* */
734
735 #if 0
736 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
737 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
738 {
739         Base *base;
740         unsigned int *bufmin,*bufmax;
741         int a,b,rc,tel,aantal,dirvec[4][2],maxob;
742         unsigned int retval=0;
743         
744         base= LASTBASE;
745         if(base==0) return 0;
746         maxob= base->selcol;
747
748         aantal= (size-1)/2;
749         rc= 0;
750
751         dirvec[0][0]= 1;
752         dirvec[0][1]= 0;
753         dirvec[1][0]= 0;
754         dirvec[1][1]= -size;
755         dirvec[2][0]= -1;
756         dirvec[2][1]= 0;
757         dirvec[3][0]= 0;
758         dirvec[3][1]= size;
759
760         bufmin= buf;
761         bufmax= buf+ size*size;
762         buf+= aantal*size+ aantal;
763
764         for(tel=1;tel<=size;tel++) {
765
766                 for(a=0;a<2;a++) {
767                         for(b=0;b<tel;b++) {
768
769                                 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
770                                 if( *buf==dontdo ) retval= dontdo;      /* if only color dontdo is available, still return dontdo */
771                                 
772                                 buf+= (dirvec[rc][0]+dirvec[rc][1]);
773
774                                 if(buf<bufmin || buf>=bufmax) return retval;
775                         }
776                         rc++;
777                         rc &= 3;
778                 }
779         }
780         return retval;
781 }
782 #endif
783
784 /* ************************** mouse select ************************* */
785
786
787 /* The max number of menu items in an object select menu */
788 #define SEL_MENU_SIZE   22
789
790 static void deselectall_except(Scene *scene, Base *b)   /* deselect all except b */
791 {
792         Base *base;
793         
794         for(base= FIRSTBASE; base; base= base->next) {
795                 if (base->flag & SELECT) {
796                         if(b!=base) {
797                                 ED_base_object_select(base, BA_DESELECT);
798                         }
799                 }
800         }
801 }
802
803 static Base *mouse_select_menu(ViewContext *vc, unsigned int *buffer, int hits, short *mval)
804 {
805         Scene *scene= vc->scene;
806         View3D *v3d= vc->v3d;
807         Base *baseList[SEL_MENU_SIZE]={NULL}; /*baseList is used to store all possible bases to bring up a menu */
808         Base *base;
809         short baseCount = 0;
810         char menuText[20 + SEL_MENU_SIZE*32] = "Select Object%t";       /* max ob name = 22 */
811         char str[32];
812         
813         for(base=FIRSTBASE; base; base= base->next) {
814                 if (BASE_SELECTABLE(v3d, base)) {
815                         baseList[baseCount] = NULL;
816                         
817                         /* two selection methods, the CTRL select uses max dist of 15 */
818                         if(buffer) {
819                                 int a;
820                                 for(a=0; a<hits; a++) {
821                                         /* index was converted */
822                                         if(base->selcol==buffer[ (4 * a) + 3 ]) baseList[baseCount] = base;
823                                 }
824                         }
825                         else {
826                                 int temp, dist=15;
827                                 
828                                 project_short(vc->ar, vc->v3d, base->object->obmat[3], &base->sx);
829                                 
830                                 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
831                                 if(temp<dist ) baseList[baseCount] = base;
832                         }
833                         
834                         if(baseList[baseCount]) {
835                                 if (baseCount < SEL_MENU_SIZE) {
836                                         baseList[baseCount] = base;
837                                         sprintf(str, "|%s %%x%d", base->object->id.name+2, baseCount+1);        /* max ob name == 22 */
838                                                         strcat(menuText, str);
839                                                         baseCount++;
840                                 }
841                         }
842                 }
843         }
844
845         if(baseCount<=1) return baseList[0];
846         else {
847                 baseCount = -1; // XXX = pupmenu(menuText);
848                 
849                 if (baseCount != -1) { /* If nothing is selected then dont do anything */
850                         return baseList[baseCount-1];
851                 }
852                 else return NULL;
853         }
854 }
855
856 /* we want a select buffer with bones, if there are... */
857 /* so check three selection levels and compare */
858 static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, short *mval)
859 {
860         rcti rect;
861         int offs;
862         short a, hits15, hits9=0, hits5=0;
863         short has_bones15=0, has_bones9=0, has_bones5=0;
864         
865         BLI_init_rcti(&rect, mval[0]-14, mval[0]+14, mval[1]-14, mval[1]+14);
866         hits15= view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
867         if(hits15>0) {
868                 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
869                 
870                 offs= 4*hits15;
871                 BLI_init_rcti(&rect, mval[0]-9, mval[0]+9, mval[1]-9, mval[1]+9);
872                 hits9= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
873                 if(hits9>0) {
874                         for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
875                         
876                         offs+= 4*hits9;
877                         BLI_init_rcti(&rect, mval[0]-5, mval[0]+5, mval[1]-5, mval[1]+5);
878                         hits5= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
879                         if(hits5>0) {
880                                 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
881                         }
882                 }
883                 
884                 if(has_bones5) {
885                         offs= 4*hits15 + 4*hits9;
886                         memcpy(buffer, buffer+offs, 4*offs);
887                         return hits5;
888                 }
889                 if(has_bones9) {
890                         offs= 4*hits15;
891                         memcpy(buffer, buffer+offs, 4*offs);
892                         return hits9;
893                 }
894                 if(has_bones15) {
895                         return hits15;
896                 }
897                 
898                 if(hits5>0) {
899                         offs= 4*hits15 + 4*hits9;
900                         memcpy(buffer, buffer+offs, 4*offs);
901                         return hits5;
902                 }
903                 if(hits9>0) {
904                         offs= 4*hits15;
905                         memcpy(buffer, buffer+offs, 4*offs);
906                         return hits9;
907                 }
908                 return hits15;
909         }
910         
911         return 0;
912 }
913
914
915 /* mval is region coords */
916 static void mouse_select(bContext *C, short *mval, short extend, short obcenter)
917 {
918         ViewContext vc;
919         ARegion *ar= CTX_wm_region(C);
920         View3D *v3d= (View3D *)CTX_wm_space_data(C);
921         Scene *scene= CTX_data_scene(C);
922         Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
923         unsigned int buffer[4*MAXPICKBUF];
924         int temp, a, dist=100;
925         short hits;
926         
927         /* setup view context for argument to callbacks */
928         view3d_set_viewcontext(C, &vc);
929         
930         /* always start list from basact in wire mode */
931         startbase=  FIRSTBASE;
932         if(BASACT && BASACT->next) startbase= BASACT->next;
933         
934         /* This block uses the control key to make the object selected by its center point rather then its contents */
935         /* XXX later on, in editmode do not activate */
936         if(vc.obedit==NULL && obcenter) {
937                 
938                 /* note; shift+alt goes to group-flush-selecting */
939                 /* XXX solve */
940                 if(0) 
941                         basact= mouse_select_menu(&vc, NULL, 0, mval);
942                 else {
943                         base= startbase;
944                         while(base) {
945                                 if (BASE_SELECTABLE(v3d, base)) {
946                                         project_short(ar, v3d, base->object->obmat[3], &base->sx);
947                                         
948                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
949                                         if(base==BASACT) temp+=10;
950                                         if(temp<dist ) {
951                                                 
952                                                 dist= temp;
953                                                 basact= base;
954                                         }
955                                 }
956                                 base= base->next;
957                                 
958                                 if(base==0) base= FIRSTBASE;
959                                 if(base==startbase) break;
960                         }
961                 }
962         }
963         else {
964                 /* if objects have posemode set, the bones are in the same selection buffer */
965                 
966                 hits= mixed_bones_object_selectbuffer(&vc, buffer, mval);
967                 
968                 if(hits>0) {
969                         int has_bones= 0;
970                         
971                         for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
972
973                         /* note; shift+alt goes to group-flush-selecting */
974                         if(has_bones==0 && 0) 
975                                 basact= mouse_select_menu(&vc, buffer, hits, mval);
976                         else {
977                                 static short lastmval[2]={-100, -100};
978                                 int donearest= 0;
979                                 
980                                 /* define if we use solid nearest select or not */
981                                 if(v3d->drawtype>OB_WIRE) {
982                                         donearest= 1;
983                                         if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
984                                                 if(!has_bones)  /* hrms, if theres bones we always do nearest */
985                                                         donearest= 0;
986                                         }
987                                 }
988                                 lastmval[0]= mval[0]; lastmval[1]= mval[1];
989                                 
990                                 if(donearest) {
991                                         unsigned int min= 0xFFFFFFFF;
992                                         int selcol= 0, notcol=0;
993                                         
994
995                                         if(has_bones) {
996                                                 /* we skip non-bone hits */
997                                                 for(a=0; a<hits; a++) {
998                                                         if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
999                                                                 min= buffer[4*a+1];
1000                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1001                                                         }
1002                                                 }
1003                                         }
1004                                         else {
1005                                                 /* only exclude active object when it is selected... */
1006                                                 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol; 
1007                                         
1008                                                 for(a=0; a<hits; a++) {
1009                                                         if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1010                                                                 min= buffer[4*a+1];
1011                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1012                                                         }
1013                                                 }
1014                                         }
1015
1016                                         base= FIRSTBASE;
1017                                         while(base) {
1018                                                 if(base->lay & v3d->lay) {
1019                                                         if(base->selcol==selcol) break;
1020                                                 }
1021                                                 base= base->next;
1022                                         }
1023                                         if(base) basact= base;
1024                                 }
1025                                 else {
1026                                         
1027                                         base= startbase;
1028                                         while(base) {
1029                                                 /* skip objects with select restriction, to prevent prematurely ending this loop
1030                                                  * with an un-selectable choice */
1031                                                 if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1032                                                         base=base->next;
1033                                                         if(base==NULL) base= FIRSTBASE;
1034                                                         if(base==startbase) break;
1035                                                 }
1036                                         
1037                                                 if(base->lay & v3d->lay) {
1038                                                         for(a=0; a<hits; a++) {
1039                                                                 if(has_bones) {
1040                                                                         /* skip non-bone objects */
1041                                                                         if((buffer[4*a+3] & 0xFFFF0000)) {
1042                                                                                 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1043                                                                                         basact= base;
1044                                                                         }
1045                                                                 }
1046                                                                 else {
1047                                                                         if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1048                                                                                 basact= base;
1049                                                                 }
1050                                                         }
1051                                                 }
1052                                                 
1053                                                 if(basact) break;
1054                                                 
1055                                                 base= base->next;
1056                                                 if(base==NULL) base= FIRSTBASE;
1057                                                 if(base==startbase) break;
1058                                         }
1059                                 }
1060                         }
1061                         
1062                         if(has_bones && basact) {
1063                                 if(0) {// XXX do_pose_selectbuffer(basact, buffer, hits) ) {    /* then bone is found */
1064                                 
1065                                         /* we make the armature selected: 
1066                                            not-selected active object in posemode won't work well for tools */
1067                                         basact->flag|= SELECT;
1068                                         basact->object->flag= basact->flag;
1069                                         
1070                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1071                                         if(G.f & G_WEIGHTPAINT) {
1072                                                 /* prevent activating */
1073                                                 basact= NULL;
1074                                         }
1075                                         
1076                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, basact->object);
1077                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, basact->object);
1078
1079                                 }
1080                                 /* prevent bone selecting to pass on to object selecting */
1081                                 if(basact==BASACT)
1082                                         basact= NULL;
1083                         }
1084                 }
1085         }
1086         
1087         /* so, do we have something selected? */
1088         if(basact) {
1089                 
1090                 if(vc.obedit) {
1091                         /* only do select */
1092                         deselectall_except(scene, basact);
1093                         ED_base_object_select(basact, BA_SELECT);
1094                 }
1095                 /* also prevent making it active on mouse selection */
1096                 else if (BASE_SELECTABLE(v3d, basact)) {
1097
1098                         oldbasact= BASACT;
1099                         BASACT= basact;
1100                         
1101                         if(!extend) {
1102                                 deselectall_except(scene, basact);
1103                                 ED_base_object_select(basact, BA_SELECT);
1104                         }
1105                         else if(0) {
1106                                 // XXX select_all_from_groups(basact);
1107                         }
1108                         else {
1109                                 if(basact->flag & SELECT) {
1110                                         if(basact==oldbasact)
1111                                                 ED_base_object_select(basact, BA_DESELECT);
1112                                 }
1113                                 else ED_base_object_select(basact, BA_SELECT);
1114                         }
1115
1116                         if(oldbasact != basact) {
1117                                 ED_base_object_activate(C, basact); /* adds notifier */
1118                         }
1119
1120                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1121                         
1122                 }
1123         }
1124
1125 }
1126
1127 /* ********************  border and circle ************************************** */
1128
1129
1130 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1131 {
1132         int radsq= rad*rad;
1133         float v1[2], v2[2], v3[2];
1134         
1135         /* check points in circle itself */
1136         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1137         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1138         
1139         /* pointdistline */
1140         v3[0]= centx;
1141         v3[1]= centy;
1142         v1[0]= x1;
1143         v1[1]= y1;
1144         v2[0]= x2;
1145         v2[1]= y2;
1146         
1147         if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1148         
1149         return 0;
1150 }
1151
1152 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1153 {
1154         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1155
1156         if (BLI_in_rcti(data->rect, x, y)) {
1157                 if (bp) {
1158                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1159                 } else {
1160                         if (G.f & G_HIDDENHANDLES) {
1161                                 /* can only be beztindex==0 here since handles are hidden */
1162                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1163                         } else {
1164                                 if (beztindex==0) {
1165                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1166                                 } else if (beztindex==1) {
1167                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1168                                 } else {
1169                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1170                                 }
1171                         }
1172                 }
1173         }
1174 }
1175 static void do_nurbs_box_select(ViewContext *vc, rcti *rect, int select)
1176 {
1177         struct { ViewContext vc; rcti *rect; int select; } data;
1178         
1179         data.vc= *vc;
1180         data.rect = rect;
1181         data.select = select;
1182
1183         nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data);
1184 }
1185
1186 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1187 {
1188         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1189
1190         if (BLI_in_rcti(data->rect, x, y)) {
1191                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1192         }
1193 }
1194 static void do_lattice_box_select(ViewContext *vc, rcti *rect, int select)
1195 {
1196         struct { ViewContext vc; rcti *rect; int select, pass, done; } data;
1197
1198         data.vc= *vc;
1199         data.rect = rect;
1200         data.select = select;
1201
1202         lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data);
1203 }
1204
1205 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1206 {
1207         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1208
1209         if (BLI_in_rcti(data->rect, x, y)) {
1210                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1211         }
1212 }
1213 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1214 {
1215         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1216
1217         if(EM_check_backbuf(em_solidoffs+index)) {
1218                 if (data->pass==0) {
1219                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1220                                 EM_select_edge(eed, data->select);
1221                                 data->done = 1;
1222                         }
1223                 } else {
1224                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1225                                 EM_select_edge(eed, data->select);
1226                         }
1227                 }
1228         }
1229 }
1230 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1231 {
1232         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1233
1234         if (BLI_in_rcti(data->rect, x, y)) {
1235                 EM_select_face_fgon(data->vc.em, efa, data->select);
1236         }
1237 }
1238 static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select)
1239 {
1240         struct { ViewContext vc; rcti *rect; short select, pass, done; } data;
1241         int bbsel;
1242         
1243         data.vc= *vc;
1244         data.rect = rect;
1245         data.select = select;
1246         data.pass = 0;
1247         data.done = 0;
1248
1249         bbsel= EM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1250
1251         if(vc->scene->selectmode & SCE_SELECT_VERTEX) {
1252                 if (bbsel) {
1253                         EM_backbuf_checkAndSelectVerts(vc->em, select);
1254                 } else {
1255                         mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1);
1256                 }
1257         }
1258         if(vc->scene->selectmode & SCE_SELECT_EDGE) {
1259                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1260
1261                 data.pass = 0;
1262                 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1263
1264                 if (data.done==0) {
1265                         data.pass = 1;
1266                         mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1267                 }
1268         }
1269         
1270         if(vc->scene->selectmode & SCE_SELECT_FACE) {
1271                 if(bbsel) {
1272                         EM_backbuf_checkAndSelectFaces(vc->em, select);
1273                 } else {
1274                         mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data);
1275                 }
1276         }
1277         
1278         EM_free_backbuf();
1279                 
1280         EM_selectmode_flush(vc->em);
1281 }
1282
1283 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
1284 {
1285         ViewContext vc;
1286         Scene *scene= CTX_data_scene(C);
1287         ScrArea *sa= CTX_wm_area(C);
1288         View3D *v3d= sa->spacedata.first;
1289         Object *obedit= CTX_data_edit_object(C);
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(obedit==NULL && (FACESEL_PAINT_TEST)) {
1309 // XXX          face_borderselect();
1310                 return OPERATOR_FINISHED;
1311         }
1312         else if(obedit==NULL && (G.f & G_PARTICLEEDIT)) {
1313 // XXX          PE_borderselect();
1314                 return OPERATOR_FINISHED;
1315         }
1316         
1317         if(obedit) {
1318                 if(obedit->type==OB_MESH) {
1319                         Mesh *me= 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, obedit);
1324                         
1325                 }
1326                 else if(ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1327                         do_nurbs_box_select(&vc, &rect, val==LEFTMOUSE);
1328 //                      allqueue(REDRAWVIEW3D, 0);
1329                 }
1330                 else if(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(obedit->type==OB_ARMATURE) {
1354                         bArmature *arm= obedit->data;
1355                         EditBone *ebone;
1356                         
1357                         /* clear flag we use to detect point was affected */
1358                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next)
1359                                 ebone->flag &= ~BONE_DONE;
1360                         
1361                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1362                         
1363                         /* first we only check points inside the border */
1364                         for (a=0; a<hits; a++){
1365                                 index = buffer[(4*a)+3];
1366                                 if (index!=-1) {
1367                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1368                                         if (index & BONESEL_TIP) {
1369                                                 ebone->flag |= BONE_DONE;
1370                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
1371                                                 else ebone->flag &= ~BONE_TIPSEL;
1372                                         }
1373                                         
1374                                         if (index & BONESEL_ROOT) {
1375                                                 ebone->flag |= BONE_DONE;
1376                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
1377                                                 else ebone->flag &= ~BONE_ROOTSEL;
1378                                         }
1379                                 }
1380                         }
1381                         
1382                         /* now we have to flush tag from parents... */
1383                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next) {
1384                                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1385                                         if(ebone->parent->flag & BONE_DONE)
1386                                                 ebone->flag |= BONE_DONE;
1387                                 }
1388                         }
1389                         
1390                         /* only select/deselect entire bones when no points where in the rect */
1391                         for (a=0; a<hits; a++){
1392                                 index = buffer[(4*a)+3];
1393                                 if (index!=-1) {
1394                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1395                                         if (index & BONESEL_BONE) {
1396                                                 if(!(ebone->flag & BONE_DONE)) {
1397                                                         if (val==LEFTMOUSE)
1398                                                                 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1399                                                         else
1400                                                                 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1401                                                 }
1402                                         }
1403                                 }
1404                         }
1405                         
1406                 }
1407                 else if(obedit->type==OB_LATTICE) {
1408                         do_lattice_box_select(&vc, &rect, val==LEFTMOUSE);
1409                 }
1410         }
1411         else {  /* no editmode, unified for bones and objects */
1412                 Bone *bone;
1413                 unsigned int *vbuffer=NULL; /* selection buffer */
1414                 unsigned int *col;                      /* color in buffer      */
1415                 short selecting = 0;
1416                 Object *ob= OBACT;
1417                 int bone_only;
1418                 
1419                 if((ob) && (ob->flag & OB_POSEMODE))
1420                         bone_only= 1;
1421                 else
1422                         bone_only= 0;
1423                 
1424                 if (val==LEFTMOUSE)
1425                         selecting = 1;
1426                 
1427                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1428                 vbuffer = MEM_mallocN(4 * (G.totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1429                 hits= view3d_opengl_select(&vc, vbuffer, 4*(G.totobj+MAXPICKBUF), &rect);
1430                 /*
1431                 LOGIC NOTES (theeth):
1432                 The buffer and ListBase have the same relative order, which makes the selection
1433                 very simple. Loop through both data sets at the same time, if the color
1434                 is the same as the object, we have a hit and can move to the next color
1435                 and object pair, if not, just move to the next object,
1436                 keeping the same color until we have a hit.
1437
1438                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1439                 does it incorrectly.
1440                 */
1441
1442                 if (hits>0) { /* no need to loop if there's no hit */
1443                         base= FIRSTBASE;
1444                         col = vbuffer + 3;
1445                         
1446                         while(base && hits) {
1447                                 Base *next = base->next;
1448                                 if(base->lay & v3d->lay) {
1449                                         while (base->selcol == (*col & 0xFFFF)) {       /* we got an object */
1450                                                 
1451                                                 if(*col & 0xFFFF0000) {                                 /* we got a bone */
1452                                                         bone = NULL; // XXX get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1453                                                         if(bone) {
1454                                                                 if(selecting) {
1455                                                                         bone->flag |= BONE_SELECTED;
1456 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 1);
1457                                                                 }
1458                                                                 else {
1459                                                                         bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1460 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 0);
1461                                                                 }
1462                                                         }
1463                                                 }
1464                                                 else if(!bone_only) {
1465                                                         if (selecting)
1466                                                                 ED_base_object_select(base, BA_SELECT);
1467                                                         else
1468                                                                 ED_base_object_select(base, BA_DESELECT);
1469                                                 }
1470
1471                                                 col+=4; /* next color */
1472                                                 hits--;
1473                                                 if(hits==0) break;
1474                                         }
1475                                 }
1476                                 
1477                                 base= next;
1478                         }
1479
1480                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1481
1482                 }
1483                 MEM_freeN(vbuffer);
1484         }
1485         
1486         return OPERATOR_FINISHED;
1487
1488
1489
1490 /* *****************Selection Operators******************* */
1491 static EnumPropertyItem prop_select_types[] = {
1492         {0, "EXCLUSIVE", "Exclusive", ""},
1493         {1, "EXTEND", "Extend", ""},
1494         {0, NULL, NULL, NULL}
1495 };
1496
1497 /* ****** Border Select ****** */
1498 void VIEW3D_OT_borderselect(wmOperatorType *ot)
1499 {
1500         PropertyRNA *prop;
1501         
1502         /* identifiers */
1503         ot->name= "Border Select";
1504         ot->idname= "VIEW3D_OT_borderselect";
1505         
1506         /* api callbacks */
1507         ot->invoke= WM_border_select_invoke;
1508         ot->exec= view3d_borderselect_exec;
1509         ot->modal= WM_border_select_modal;
1510         
1511         ot->poll= ED_operator_view3d_active;
1512         
1513         /* rna */
1514         RNA_def_property(ot->srna, "event_type", PROP_INT, PROP_NONE);
1515         RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
1516         RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
1517         RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
1518         RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
1519
1520         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
1521         RNA_def_property_enum_items(prop, prop_select_types);
1522 }
1523
1524 /* ****** Mouse Select ****** */
1525
1526
1527 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1528 {
1529         ARegion *ar= CTX_wm_region(C);
1530         Object *obedit= CTX_data_edit_object(C);
1531         short extend= RNA_enum_is_equal(op->ptr, "type", "EXTEND");
1532         short mval[2];  
1533         
1534         mval[0]= event->x - ar->winrct.xmin;
1535         mval[1]= event->y - ar->winrct.ymin;
1536
1537         view3d_operator_needs_opengl(C);
1538         
1539         if(obedit) {
1540                 if(obedit->type==OB_MESH)
1541                         mouse_mesh(C, mval, extend);
1542         }
1543         else 
1544                 mouse_select(C, mval, extend, 0);
1545         
1546         /* allowing tweaks */
1547         return OPERATOR_PASS_THROUGH;
1548 }
1549
1550 void VIEW3D_OT_select(wmOperatorType *ot)
1551 {
1552         PropertyRNA *prop;
1553
1554         /* identifiers */
1555         ot->name= "Activate/Select";
1556         ot->idname= "VIEW3D_OT_select";
1557         
1558         /* api callbacks */
1559         ot->invoke= view3d_select_invoke;
1560         ot->poll= ED_operator_view3d_active;
1561
1562         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
1563         RNA_def_property_enum_items(prop, prop_select_types);
1564 }
1565
1566
1567 /* -------------------- circle select --------------------------------------------- */
1568
1569 static void mesh_circle_doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1570 {
1571         struct { short select, mval[2]; float radius; } *data = userData;
1572         int mx = x - data->mval[0], my = y - data->mval[1];
1573         float r = sqrt(mx*mx + my*my);
1574
1575         if (r<=data->radius) {
1576                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1577         }
1578 }
1579 static void mesh_circle_doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1580 {
1581         struct { short select, mval[2]; float radius; } *data = userData;
1582
1583         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1584                 EM_select_edge(eed, data->select);
1585         }
1586 }
1587 static void mesh_circle_doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1588 {
1589         struct { short select, mval[2]; float radius; } *data = userData;
1590         int mx = x - data->mval[0], my = y - data->mval[1];
1591         float r = sqrt(mx*mx + my*my);
1592         EditMesh *em= NULL; // XXX
1593         
1594         if (r<=data->radius) {
1595                 EM_select_face_fgon(em, efa, data->select);
1596         }
1597 }
1598
1599 static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1600 {
1601         int bbsel;
1602         
1603         if(vc->obedit==NULL && (FACESEL_PAINT_TEST)) {
1604                 Object *ob= vc->obact;
1605                 Mesh *me = ob?ob->data:NULL;
1606
1607                 if (me) {
1608                         em_vertoffs= me->totface+1;     /* max index array */
1609
1610                         bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1611                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1612                         EM_free_backbuf();
1613
1614 // XXX                  object_tface_flags_changed(OBACT, 0);
1615                 }
1616         }
1617         else {
1618                 struct { short select, mval[2]; float radius; } data;
1619                 
1620                 bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
1621                 vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
1622
1623                 data.select = selecting;
1624                 data.mval[0] = mval[0];
1625                 data.mval[1] = mval[1];
1626                 data.radius = rad;
1627
1628                 if(vc->scene->selectmode & SCE_SELECT_VERTEX) {
1629                         if(bbsel) {
1630                                 EM_backbuf_checkAndSelectVerts(vc->em, selecting==LEFTMOUSE);
1631                         } else {
1632                                 mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, 1);
1633                         }
1634                 }
1635
1636                 if(vc->scene->selectmode & SCE_SELECT_EDGE) {
1637                         if (bbsel) {
1638                                 EM_backbuf_checkAndSelectEdges(vc->em, selecting==LEFTMOUSE);
1639                         } else {
1640                                 mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, 0);
1641                         }
1642                 }
1643                 
1644                 if(vc->scene->selectmode & SCE_SELECT_FACE) {
1645                         if(bbsel) {
1646                                 EM_backbuf_checkAndSelectFaces(vc->em, selecting==LEFTMOUSE);
1647                         } else {
1648                                 mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data);
1649                         }
1650                 }
1651
1652                 EM_free_backbuf();
1653                 EM_selectmode_flush(vc->em);
1654         }
1655 }
1656
1657
1658 static void nurbscurve_circle_doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1659 {
1660         struct { short select, mval[2]; float radius; } *data = userData;
1661         int mx = x - data->mval[0], my = y - data->mval[1];
1662         float r = sqrt(mx*mx + my*my);
1663
1664         if (r<=data->radius) {
1665                 if (bp) {
1666                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1667                 } else {
1668                         if (beztindex==0) {
1669                                 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1670                         } else if (beztindex==1) {
1671                                 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1672                         } else {
1673                                 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1674                         }
1675                 }
1676         }
1677 }
1678 static void nurbscurve_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1679 {
1680         struct { short select, mval[2]; float radius; } data;
1681
1682         /* set vc-> edit data */
1683         
1684         data.select = selecting;
1685         data.mval[0] = mval[0];
1686         data.mval[1] = mval[1];
1687         data.radius = rad;
1688
1689         nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data);
1690 }
1691
1692
1693 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, int x, int y)
1694 {
1695         struct { short select, mval[2]; float radius; } *data = userData;
1696         int mx = x - data->mval[0], my = y - data->mval[1];
1697         float r = sqrt(mx*mx + my*my);
1698
1699         if (r<=data->radius) {
1700                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1701         }
1702 }
1703 static void lattice_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1704 {
1705         struct { short select, mval[2]; float radius; } data;
1706
1707         /* set vc-> edit data */
1708         
1709         data.select = selecting;
1710         data.mval[0] = mval[0];
1711         data.mval[1] = mval[1];
1712         data.radius = rad;
1713
1714         lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data);
1715 }
1716
1717 /** Callbacks for circle selection in Editmode */
1718
1719 static void obedit_circle_select(ViewContext *vc, short selecting, short *mval, float rad) 
1720 {
1721         switch(vc->obedit->type) {              
1722         case OB_MESH:
1723                 mesh_circle_select(vc, selecting, mval, rad);
1724                 break;
1725         case OB_CURVE:
1726         case OB_SURF:
1727                 nurbscurve_circle_select(vc, selecting, mval, rad);
1728                 break;
1729         case OB_LATTICE:
1730                 lattice_circle_select(vc, selecting, mval, rad);
1731                 break;
1732         default:
1733                 return;
1734         }
1735 }
1736
1737 /* not a real operator, only for circle test */
1738 static int view3d_circle_select_exec(bContext *C, wmOperator *op)
1739 {
1740         ScrArea *sa= CTX_wm_area(C);
1741         ARegion *ar= CTX_wm_region(C);
1742         Scene *scene= CTX_data_scene(C);
1743         View3D *v3d= sa->spacedata.first;
1744         int x= RNA_int_get(op->ptr, "x");
1745         int y= RNA_int_get(op->ptr, "y");
1746         int radius= RNA_int_get(op->ptr, "radius");
1747         
1748         if(CTX_data_edit_object(C)) {
1749                 ViewContext vc;
1750                 short mval[2], selecting;
1751                 
1752                 view3d_set_viewcontext(C, &vc);
1753                 mval[0]= x;
1754                 mval[1]= y;
1755                 selecting= LEFTMOUSE==RNA_int_get(op->ptr, "event_type"); // XXX solve
1756                 obedit_circle_select(&vc, selecting, mval, (float)radius);
1757         }
1758         else {
1759                 Base *base;
1760                 
1761                 for(base= FIRSTBASE; base; base= base->next) {
1762                         if(base->lay & v3d->lay) {
1763                                 project_short(ar, v3d, base->object->obmat[3], &base->sx);
1764                                 if(base->sx!=IS_CLIPPED) {
1765                                         int dx= base->sx-x;
1766                                         int dy= base->sy-y;
1767                                         if( dx*dx + dy*dy < radius*radius)
1768                                                 ED_base_object_select(base, BA_SELECT);
1769                                 }
1770                         }
1771                 }
1772                 
1773                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1774         }
1775         
1776         return OPERATOR_FINISHED;
1777 }
1778
1779 void VIEW3D_OT_circle_select(wmOperatorType *ot)
1780 {
1781         ot->name= "Circle Select";
1782         ot->idname= "VIEW3D_OT_circle_select";
1783         
1784         ot->invoke= WM_gesture_circle_invoke;
1785         ot->modal= WM_gesture_circle_modal;
1786         ot->exec= view3d_circle_select_exec;
1787         ot->poll= ED_operator_view3d_active;
1788         
1789         RNA_def_property(ot->srna, "x", PROP_INT, PROP_NONE);
1790         RNA_def_property(ot->srna, "y", PROP_INT, PROP_NONE);
1791         RNA_def_property(ot->srna, "radius", PROP_INT, PROP_NONE);
1792         RNA_def_property(ot->srna, "event_type", PROP_INT, PROP_NONE);
1793         
1794 }