2.5
[blender-staging.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_mesh.h"
80 #include "ED_object.h"
81 #include "ED_screen.h"
82 #include "ED_types.h"
83 #include "ED_util.h"
84
85 #include "UI_interface.h"
86 #include "UI_resources.h"
87 #include "UI_view2d.h"
88
89 #include "PIL_time.h" /* smoothview */
90
91 #include "view3d_intern.h"      // own include
92
93
94 void view3d_set_viewcontext(bContext *C, ViewContext *vc)
95 {
96         memset(vc, 0, sizeof(ViewContext));
97         vc->ar= CTX_wm_region(C);
98         vc->scene= CTX_data_scene(C);
99         vc->v3d= CTX_wm_view3d(C);
100         vc->rv3d= vc->ar->regiondata;
101         vc->obact= CTX_data_active_object(C);
102         vc->obedit= CTX_data_edit_object(C); 
103 }
104
105 /* ********************** view3d_select: selection manipulations ********************* */
106
107 /* XXX to solve *************** */
108 static void BIF_undo_push() {}
109 /* XXX end ********************* */
110
111 /* local prototypes */
112
113 void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select)
114 {
115         EditVert *eve;
116         int index= em_wireoffs;
117
118         for(eve= em->verts.first; eve; eve= eve->next, index++) {
119                 if(eve->h==0) {
120                         if(EM_check_backbuf(index)) {
121                                 eve->f = select?(eve->f|1):(eve->f&~1);
122                         }
123                 }
124         }
125 }
126
127 void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select)
128 {
129         EditEdge *eed;
130         int index= em_solidoffs;
131
132         for(eed= em->edges.first; eed; eed= eed->next, index++) {
133                 if(eed->h==0) {
134                         if(EM_check_backbuf(index)) {
135                                 EM_select_edge(eed, select);
136                         }
137                 }
138         }
139 }
140
141 void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select)
142 {
143         EditFace *efa;
144         int index= 1;
145
146         for(efa= em->faces.first; efa; efa= efa->next, index++) {
147                 if(efa->h==0) {
148                         if(EM_check_backbuf(index)) {
149                                 EM_select_face_fgon(em, efa, select);
150                         }
151                 }
152         }
153 }
154
155 void EM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
156 {
157         MFace *mface = me->mface;
158         int a;
159
160         if (mface) {
161                 for(a=1; a<=me->totface; a++, mface++) {
162                         if(EM_check_backbuf(a)) {
163                                 mface->flag = select?(mface->flag|ME_FACE_SEL):(mface->flag&~ME_FACE_SEL);
164                         }
165                 }
166         }
167 }
168
169 void arrows_move_cursor(unsigned short event)
170 {
171 #if 0
172         short mval[2];
173
174         getmouseco_sc(mval);
175
176         if(event==UPARROWKEY) {
177                 warp_pointer(mval[0], mval[1]+1);
178         } else if(event==DOWNARROWKEY) {
179                 warp_pointer(mval[0], mval[1]-1);
180         } else if(event==LEFTARROWKEY) {
181                 warp_pointer(mval[0]-1, mval[1]);
182         } else if(event==RIGHTARROWKEY) {
183                 warp_pointer(mval[0]+1, mval[1]);
184         }
185 #endif
186 }
187
188
189 /* *********************** GESTURE AND LASSO ******************* */
190
191 /* helper also for borderselect */
192 static int edge_fully_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
193 {
194         return BLI_in_rcti(rect, x1, y1) && BLI_in_rcti(rect, x2, y2);
195 }
196
197 static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
198 {
199         int d1, d2, d3, d4;
200         
201         /* check points in rect */
202         if(edge_fully_inside_rect(rect, x1, y1, x2, y2)) return 1;
203         
204         /* check points completely out rect */
205         if(x1<rect->xmin && x2<rect->xmin) return 0;
206         if(x1>rect->xmax && x2>rect->xmax) return 0;
207         if(y1<rect->ymin && y2<rect->ymin) return 0;
208         if(y1>rect->ymax && y2>rect->ymax) return 0;
209         
210         /* simple check lines intersecting. */
211         d1= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymin );
212         d2= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymax );
213         d3= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymax );
214         d4= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymin );
215         
216         if(d1<0 && d2<0 && d3<0 && d4<0) return 0;
217         if(d1>0 && d2>0 && d3>0 && d4>0) return 0;
218         
219         return 1;
220 }
221
222
223 #define MOVES_GESTURE 50
224 #define MOVES_LASSO 500
225
226 int lasso_inside(short mcords[][2], short moves, short sx, short sy)
227 {
228         /* we do the angle rule, define that all added angles should be about zero or 2*PI */
229         float angletot=0.0, len, dot, ang, cross, fp1[2], fp2[2];
230         int a;
231         short *p1, *p2;
232         
233         if(sx==IS_CLIPPED)
234                 return 0;
235         
236         p1= mcords[moves-1];
237         p2= mcords[0];
238         
239         /* first vector */
240         fp1[0]= (float)(p1[0]-sx);
241         fp1[1]= (float)(p1[1]-sy);
242         len= sqrt(fp1[0]*fp1[0] + fp1[1]*fp1[1]);
243         fp1[0]/= len;
244         fp1[1]/= len;
245         
246         for(a=0; a<moves; a++) {
247                 /* second vector */
248                 fp2[0]= (float)(p2[0]-sx);
249                 fp2[1]= (float)(p2[1]-sy);
250                 len= sqrt(fp2[0]*fp2[0] + fp2[1]*fp2[1]);
251                 fp2[0]/= len;
252                 fp2[1]/= len;
253                 
254                 /* dot and angle and cross */
255                 dot= fp1[0]*fp2[0] + fp1[1]*fp2[1];
256                 ang= fabs(saacos(dot));
257
258                 cross= (float)((p1[1]-p2[1])*(p1[0]-sx) + (p2[0]-p1[0])*(p1[1]-sy));
259                 
260                 if(cross<0.0) angletot-= ang;
261                 else angletot+= ang;
262                 
263                 /* circulate */
264                 fp1[0]= fp2[0]; fp1[1]= fp2[1];
265                 p1= p2;
266                 p2= mcords[a+1];
267         }
268         
269         if( fabs(angletot) > 4.0 ) return 1;
270         return 0;
271 }
272
273 /* edge version for lasso select. we assume boundbox check was done */
274 int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1)
275 {
276         short v1[2], v2[2];
277         int a;
278
279         if(x0==IS_CLIPPED || x1==IS_CLIPPED)
280                 return 0;
281         
282         v1[0] = x0, v1[1] = y0;
283         v2[0] = x1, v2[1] = y1;
284
285         /* check points in lasso */
286         if(lasso_inside(mcords, moves, v1[0], v1[1])) return 1;
287         if(lasso_inside(mcords, moves, v2[0], v2[1])) return 1;
288         
289         /* no points in lasso, so we have to intersect with lasso edge */
290         
291         if( IsectLL2Ds(mcords[0], mcords[moves-1], v1, v2) > 0) return 1;
292         for(a=0; a<moves-1; a++) {
293                 if( IsectLL2Ds(mcords[a], mcords[a+1], v1, v2) > 0) return 1;
294         }
295         
296         return 0;
297 }
298
299
300 /* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN) 
301    and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK
302 */
303 static void do_lasso_select_pose(ViewContext *vc, short mcords[][2], short moves, short select)
304 {
305         Object *ob= vc->obact;
306         bPoseChannel *pchan;
307         float vec[3];
308         short sco1[2], sco2[2];
309         
310         if(ob->type!=OB_ARMATURE || ob->pose==NULL) return;
311         
312         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
313                 VECCOPY(vec, pchan->pose_head);
314                 Mat4MulVecfl(ob->obmat, vec);
315                 project_short(vc->ar, vec, sco1);
316                 VECCOPY(vec, pchan->pose_tail);
317                 Mat4MulVecfl(ob->obmat, vec);
318                 project_short(vc->ar, vec, sco2);
319                 
320                 if(lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
321                         if(select) pchan->bone->flag |= BONE_SELECTED;
322                         else pchan->bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
323                 }
324         }
325 }
326
327
328 static void do_lasso_select_objects(ViewContext *vc, short mcords[][2], short moves, short select)
329 {
330         Base *base;
331         
332         for(base= vc->scene->base.first; base; base= base->next) {
333                 if(base->lay & vc->v3d->lay) {
334                         project_short(vc->ar, base->object->obmat[3], &base->sx);
335                         if(lasso_inside(mcords, moves, base->sx, base->sy)) {
336                                 
337                                 if(select) ED_base_object_select(base, BA_SELECT);
338                                 else ED_base_object_select(base, BA_DESELECT);
339                                 base->object->flag= base->flag;
340                         }
341                         if(base->object->flag & OB_POSEMODE) {
342                                 do_lasso_select_pose(vc, mcords, moves, select);
343                         }
344                 }
345         }
346 }
347
348 void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
349 {
350         short a;
351         
352         rect->xmin= rect->xmax= mcords[0][0];
353         rect->ymin= rect->ymax= mcords[0][1];
354         
355         for(a=1; a<moves; a++) {
356                 if(mcords[a][0]<rect->xmin) rect->xmin= mcords[a][0];
357                 else if(mcords[a][0]>rect->xmax) rect->xmax= mcords[a][0];
358                 if(mcords[a][1]<rect->ymin) rect->ymin= mcords[a][1];
359                 else if(mcords[a][1]>rect->ymax) rect->ymax= mcords[a][1];
360         }
361 }
362
363 static void do_lasso_select_mesh__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
364 {
365         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
366
367         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
368                 eve->f = data->select?(eve->f|1):(eve->f&~1);
369         }
370 }
371 static void do_lasso_select_mesh__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
372 {
373         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
374
375         if (EM_check_backbuf(em_solidoffs+index)) {
376                 if (data->pass==0) {
377                         if (    edge_fully_inside_rect(data->rect, x0, y0, x1, y1)  &&
378                                         lasso_inside(data->mcords, data->moves, x0, y0) &&
379                                         lasso_inside(data->mcords, data->moves, x1, y1)) {
380                                 EM_select_edge(eed, data->select);
381                                 data->done = 1;
382                         }
383                 } else {
384                         if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) {
385                                 EM_select_edge(eed, data->select);
386                         }
387                 }
388         }
389 }
390 static void do_lasso_select_mesh__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
391 {
392         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
393
394         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
395                 EM_select_face_fgon(data->vc.em, efa, data->select);
396         }
397 }
398
399 static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves, short select)
400 {
401         struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } data;
402         rcti rect;
403         int bbsel;
404         
405         lasso_select_boundbox(&rect, mcords, moves);
406         
407         /* set editmesh */
408         vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
409
410         data.vc= *vc;
411         data.rect = &rect;
412         data.mcords = mcords;
413         data.moves = moves;
414         data.select = select;
415         data.done = 0;
416         data.pass = 0;
417
418         bbsel= EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
419         
420         if(vc->scene->selectmode & SCE_SELECT_VERTEX) {
421                 if (bbsel) {
422                         EM_backbuf_checkAndSelectVerts(vc->em, select);
423                 } else {
424                         mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, 1);
425                 }
426         }
427         if(vc->scene->selectmode & SCE_SELECT_EDGE) {
428                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
429
430                 data.pass = 0;
431                 mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0);
432
433                 if (data.done==0) {
434                         data.pass = 1;
435                         mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0);
436                 }
437         }
438         
439         if(vc->scene->selectmode & SCE_SELECT_FACE) {
440                 if (bbsel) {
441                         EM_backbuf_checkAndSelectFaces(vc->em, select);
442                 } else {
443                         mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data);
444                 }
445         }
446         
447         EM_free_backbuf();
448         EM_selectmode_flush(vc->em);    
449 }
450
451 #if 0
452 /* this is an exception in that its the only lasso that dosnt use the 3d view (uses space image view) */
453 static void do_lasso_select_mesh_uv(short mcords[][2], short moves, short select)
454 {
455         EditFace *efa;
456         MTFace *tf;
457         int screenUV[2], nverts, i, ok = 1;
458         rcti rect;
459         
460         lasso_select_boundbox(&rect, mcords, moves);
461         
462         if (draw_uvs_face_check()) { /* Face Center Sel */
463                 float cent[2];
464                 ok = 0;
465                 for (efa= em->faces.first; efa; efa= efa->next) {
466                         /* assume not touched */
467                         efa->tmp.l = 0;
468                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
469                         if ((select) != (simaFaceSel_Check(efa, tf))) {
470                                 uv_center(tf->uv, cent, (void *)efa->v4);
471                                 uvco_to_areaco_noclip(cent, screenUV);
472                                 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
473                                         efa->tmp.l = ok = 1;
474                                 }
475                         }
476                 }
477                 /* (de)selects all tagged faces and deals with sticky modes */
478                 if (ok)
479                         uvface_setsel__internal(select);
480                 
481         } else { /* Vert Sel*/
482                 for (efa= em->faces.first; efa; efa= efa->next) {
483                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
484                         if (simaFaceDraw_Check(efa, tf)) {              
485                                 nverts= efa->v4? 4: 3;
486                                 for(i=0; i<nverts; i++) {
487                                         if ((select) != (simaUVSel_Check(efa, tf, i))) {
488                                                 uvco_to_areaco_noclip(tf->uv[i], screenUV);
489                                                 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
490                                                         if (select) {
491                                                                 simaUVSel_Set(efa, tf, i);
492                                                         } else {
493                                                                 simaUVSel_UnSet(efa, tf, i);
494                                                         }
495                                                 }
496                                         }
497                                 }
498                         }
499                 }
500         }
501         if (ok && G.sima->flag & SI_SYNC_UVSEL) {
502                 if (select) EM_select_flush(vc->em);
503                 else            EM_deselect_flush(vc->em);
504         }
505 }
506 #endif
507
508 static void do_lasso_select_curve__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
509 {
510         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
511
512         if (lasso_inside(data->mcords, data->moves, x, y)) {
513                 if (bp) {
514                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
515                 } else {
516                         if (G.f & G_HIDDENHANDLES) {
517                                 /* can only be beztindex==0 here since handles are hidden */
518                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
519                         } else {
520                                 if (beztindex==0) {
521                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
522                                 } else if (beztindex==1) {
523                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
524                                 } else {
525                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
526                                 }
527                         }
528                 }
529         }
530 }
531
532 static void do_lasso_select_curve(ViewContext *vc, short mcords[][2], short moves, short select)
533 {
534         struct { short (*mcords)[2]; short moves; short select; } data;
535
536         /* set vc->editnurb */
537         data.mcords = mcords;
538         data.moves = moves;
539         data.select = select;
540
541         nurbs_foreachScreenVert(vc, do_lasso_select_curve__doSelect, &data);
542 }
543
544 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, int y)
545 {
546         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
547
548         if (lasso_inside(data->mcords, data->moves, x, y)) {
549                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
550         }
551 }
552 static void do_lasso_select_lattice(ViewContext *vc, short mcords[][2], short moves, short select)
553 {
554         struct { short (*mcords)[2]; short moves; short select; } data;
555
556         /* set editdata in vc */
557         data.mcords = mcords;
558         data.moves = moves;
559         data.select = select;
560
561         lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data);
562 }
563
564 static void do_lasso_select_armature(ViewContext *vc, short mcords[][2], short moves, short select)
565 {
566         bArmature *arm= vc->obedit->data;
567         EditBone *ebone;
568         float vec[3];
569         short sco1[2], sco2[2], didpoint;
570         
571         /* set editdata in vc */
572         
573         for (ebone= arm->edbo->first; ebone; ebone=ebone->next) {
574
575                 VECCOPY(vec, ebone->head);
576                 Mat4MulVecfl(vc->obedit->obmat, vec);
577                 project_short(vc->ar, vec, sco1);
578                 VECCOPY(vec, ebone->tail);
579                 Mat4MulVecfl(vc->obedit->obmat, vec);
580                 project_short(vc->ar, vec, sco2);
581                 
582                 didpoint= 0;
583                 if(lasso_inside(mcords, moves, sco1[0], sco1[1])) {
584                         if(select) ebone->flag |= BONE_ROOTSEL;
585                         else ebone->flag &= ~BONE_ROOTSEL;
586                         didpoint= 1;
587                 }
588                 if(lasso_inside(mcords, moves, sco2[0], sco2[1])) {
589                    if(select) ebone->flag |= BONE_TIPSEL;
590                    else ebone->flag &= ~BONE_TIPSEL;
591                    didpoint= 1;
592                 }
593                 /* if one of points selected, we skip the bone itself */
594                 if(didpoint==0 && lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
595                         if(select) ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
596                         else ebone->flag &= ~(BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
597                 }
598         }
599         // XXX countall();      /* abused for flushing selection!!!! */
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 // XX           else if(G.f & G_PARTICLEEDIT)
662 //                      PE_do_lasso_select(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 // XXX          PE_borderselect();
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 //                      allqueue(REDRAWVIEW3D, 0);
1325                 }
1326                 else if(obedit->type==OB_MBALL) {
1327                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1328                         
1329                         ml= NULL; // XXX editelems.first;
1330                         
1331                         while(ml) {
1332                                 for(a=0; a<hits; a++) {
1333                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1334                                                 ml->flag |= MB_SCALE_RAD;
1335                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1336                                                 else ml->flag &= ~SELECT;
1337                                                 break;
1338                                         }
1339                                         if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1340                                                 ml->flag &= ~MB_SCALE_RAD;
1341                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1342                                                 else ml->flag &= ~SELECT;
1343                                                 break;
1344                                         }
1345                                 }
1346                                 ml= ml->next;
1347                         }
1348                 }
1349                 else if(obedit->type==OB_ARMATURE) {
1350                         bArmature *arm= obedit->data;
1351                         EditBone *ebone;
1352                         
1353                         /* clear flag we use to detect point was affected */
1354                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next)
1355                                 ebone->flag &= ~BONE_DONE;
1356                         
1357                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1358                         
1359                         /* first we only check points inside the border */
1360                         for (a=0; a<hits; a++){
1361                                 index = buffer[(4*a)+3];
1362                                 if (index!=-1) {
1363                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1364                                         if (index & BONESEL_TIP) {
1365                                                 ebone->flag |= BONE_DONE;
1366                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
1367                                                 else ebone->flag &= ~BONE_TIPSEL;
1368                                         }
1369                                         
1370                                         if (index & BONESEL_ROOT) {
1371                                                 ebone->flag |= BONE_DONE;
1372                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
1373                                                 else ebone->flag &= ~BONE_ROOTSEL;
1374                                         }
1375                                 }
1376                         }
1377                         
1378                         /* now we have to flush tag from parents... */
1379                         for(ebone= arm->edbo->first; ebone; ebone= ebone->next) {
1380                                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1381                                         if(ebone->parent->flag & BONE_DONE)
1382                                                 ebone->flag |= BONE_DONE;
1383                                 }
1384                         }
1385                         
1386                         /* only select/deselect entire bones when no points where in the rect */
1387                         for (a=0; a<hits; a++){
1388                                 index = buffer[(4*a)+3];
1389                                 if (index!=-1) {
1390                                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1391                                         if (index & BONESEL_BONE) {
1392                                                 if(!(ebone->flag & BONE_DONE)) {
1393                                                         if (val==LEFTMOUSE)
1394                                                                 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1395                                                         else
1396                                                                 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1397                                                 }
1398                                         }
1399                                 }
1400                         }
1401                         
1402                 }
1403                 else if(obedit->type==OB_LATTICE) {
1404                         do_lattice_box_select(&vc, &rect, val==LEFTMOUSE);
1405                 }
1406         }
1407         else {  /* no editmode, unified for bones and objects */
1408                 Bone *bone;
1409                 Object *ob= OBACT;
1410                 unsigned int *vbuffer=NULL; /* selection buffer */
1411                 unsigned int *col;                      /* color in buffer      */
1412                 short selecting = 0;
1413                 int bone_only;
1414                 int totobj= MAXPICKBUF; // XXX solve later
1415                 
1416                 if((ob) && (ob->flag & OB_POSEMODE))
1417                         bone_only= 1;
1418                 else
1419                         bone_only= 0;
1420                 
1421                 if (val==LEFTMOUSE)
1422                         selecting = 1;
1423                 
1424                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1425                 vbuffer = MEM_mallocN(4 * (totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1426                 hits= view3d_opengl_select(&vc, vbuffer, 4*(totobj+MAXPICKBUF), &rect);
1427                 /*
1428                 LOGIC NOTES (theeth):
1429                 The buffer and ListBase have the same relative order, which makes the selection
1430                 very simple. Loop through both data sets at the same time, if the color
1431                 is the same as the object, we have a hit and can move to the next color
1432                 and object pair, if not, just move to the next object,
1433                 keeping the same color until we have a hit.
1434
1435                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1436                 does it incorrectly.
1437                 */
1438
1439                 if (hits>0) { /* no need to loop if there's no hit */
1440                         base= FIRSTBASE;
1441                         col = vbuffer + 3;
1442                         
1443                         while(base && hits) {
1444                                 Base *next = base->next;
1445                                 if(base->lay & v3d->lay) {
1446                                         while (base->selcol == (*col & 0xFFFF)) {       /* we got an object */
1447                                                 
1448                                                 if(*col & 0xFFFF0000) {                                 /* we got a bone */
1449                                                         bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1450                                                         if(bone) {
1451                                                                 if(selecting) {
1452                                                                         bone->flag |= BONE_SELECTED;
1453 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 1);
1454                                                                 }
1455                                                                 else {
1456                                                                         bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1457 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 0);
1458                                                                 }
1459                                                         }
1460                                                 }
1461                                                 else if(!bone_only) {
1462                                                         if (selecting)
1463                                                                 ED_base_object_select(base, BA_SELECT);
1464                                                         else
1465                                                                 ED_base_object_select(base, BA_DESELECT);
1466                                                 }
1467
1468                                                 col+=4; /* next color */
1469                                                 hits--;
1470                                                 if(hits==0) break;
1471                                         }
1472                                 }
1473                                 
1474                                 base= next;
1475                         }
1476
1477                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1478
1479                 }
1480                 MEM_freeN(vbuffer);
1481         }
1482         ED_undo_push(C,"Border Select");
1483         return OPERATOR_FINISHED;
1484
1485
1486
1487 /* *****************Selection Operators******************* */
1488 static EnumPropertyItem prop_select_types[] = {
1489         {0, "EXCLUSIVE", "Exclusive", ""},
1490         {1, "EXTEND", "Extend", ""},
1491         {0, NULL, NULL, NULL}
1492 };
1493
1494 /* ****** Border Select ****** */
1495 void VIEW3D_OT_borderselect(wmOperatorType *ot)
1496 {
1497         /* identifiers */
1498         ot->name= "Border Select";
1499         ot->idname= "VIEW3D_OT_borderselect";
1500         
1501         /* api callbacks */
1502         ot->invoke= WM_border_select_invoke;
1503         ot->exec= view3d_borderselect_exec;
1504         ot->modal= WM_border_select_modal;
1505         
1506         ot->poll= ED_operator_view3d_active;
1507         
1508         /* rna */
1509         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1510         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1511         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1512         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1513         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1514
1515         RNA_def_enum(ot->srna, "type", prop_select_types, 0, "Type", "");
1516 }
1517
1518 /* ****** Mouse Select ****** */
1519
1520
1521 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1522 {
1523         ARegion *ar= CTX_wm_region(C);
1524         Object *obedit= CTX_data_edit_object(C);
1525         short extend= RNA_enum_is_equal(op->ptr, "type", "EXTEND");
1526         short mval[2];  
1527         
1528         mval[0]= event->x - ar->winrct.xmin;
1529         mval[1]= event->y - ar->winrct.ymin;
1530
1531         view3d_operator_needs_opengl(C);
1532         
1533         if(obedit) {
1534                 if(obedit->type==OB_MESH)
1535                         mouse_mesh(C, mval, extend);
1536                 else if(obedit->type==OB_ARMATURE)
1537                         mouse_armature(C, mval, extend);
1538                 else if(obedit->type==OB_LATTICE)
1539                         mouse_lattice(C, mval, extend);
1540                 else if(ELEM(obedit->type, OB_CURVE, OB_SURF))
1541                         mouse_nurb(C, mval, extend);
1542                         
1543         }
1544         else 
1545                 mouse_select(C, mval, extend, 0);
1546         
1547         ED_undo_push(C,"Mouse Select");
1548         /* allowing tweaks */
1549         return OPERATOR_PASS_THROUGH;
1550 }
1551
1552 void VIEW3D_OT_select(wmOperatorType *ot)
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         /* properties */
1563         RNA_def_enum(ot->srna, "type", prop_select_types, 0, "Type", "");
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, 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         ED_undo_push(C,"Circle Select");
1777         return OPERATOR_FINISHED;
1778 }
1779
1780 void VIEW3D_OT_circle_select(wmOperatorType *ot)
1781 {
1782         ot->name= "Circle Select";
1783         ot->idname= "VIEW3D_OT_circle_select";
1784         
1785         ot->invoke= WM_gesture_circle_invoke;
1786         ot->modal= WM_gesture_circle_modal;
1787         ot->exec= view3d_circle_select_exec;
1788         ot->poll= ED_operator_view3d_active;
1789         
1790         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
1791         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
1792         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
1793         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1794 }