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