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