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