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
684 void deselectall(Scene *scene, View3D *v3d)     /* is toggle */
685 {
686         Base *base;
687         int a=0, ok=0; 
688
689         base= FIRSTBASE;
690         while(base) {
691                 /* is there a visible selected object */
692                 if(base->lay & v3d->lay &&
693                   (base->object->restrictflag & OB_RESTRICT_VIEW)==0 &&
694                   (base->object->restrictflag & OB_RESTRICT_SELECT)==0
695                 ) {
696                         if (base->flag & SELECT) {
697                                 ok= a= 1;
698                                 break;
699                         } else {
700                                 ok=1;
701                         }
702                 }
703                 base= base->next;
704         }
705         
706         if (!ok) return;
707         
708         base= FIRSTBASE;
709         while(base) {
710                 if(base->lay & v3d->lay &&
711                   (base->object->restrictflag & OB_RESTRICT_VIEW)==0 &&
712                   (base->object->restrictflag & OB_RESTRICT_SELECT)==0
713                 ) {
714                         if(a) 
715                                 select_base_v3d(base, BA_DESELECT);
716                         else 
717                                 select_base_v3d(base, BA_SELECT);
718                         base->object->flag= base->flag;
719                 }
720                 base= base->next;
721         }
722
723         BIF_undo_push("(De)select all");
724 }
725
726 /* inverts object selection */
727 void selectswap(Scene *scene, View3D *v3d)
728 {
729         Base *base;
730
731         for(base= FIRSTBASE; base; base= base->next) {
732                 if(base->lay & v3d->lay && (base->object->restrictflag & OB_RESTRICT_VIEW)==0) {
733                         
734                         if (TESTBASE(v3d, base))
735                                 select_base_v3d(base, BA_DESELECT);
736                         else
737                                 select_base_v3d(base, BA_SELECT);
738                         base->object->flag= base->flag;
739                 }
740         }
741
742         BIF_undo_push("Select Inverse");
743 }
744
745 /* inverts object selection */
746 void selectrandom(Scene *scene, View3D *v3d, short randfac)
747 {
748         Base *base;
749         /*static short randfac = 50;*/
750 // XXX  if(button(&randfac,0, 100,"Percentage:")==0) return;
751         
752         for(base= FIRSTBASE; base; base= base->next) {
753                 if(base->lay & v3d->lay &&
754                   (base->object->restrictflag & OB_RESTRICT_VIEW)==0
755                 ) {
756                         if (!TESTBASE(v3d, base) && ( (BLI_frand() * 100) < randfac)) {
757                                 select_base_v3d(base, BA_SELECT);
758                                 base->object->flag= base->flag;
759                         }
760                 }
761         }
762
763         BIF_undo_push("Select Random");
764 }
765
766 /* selects all objects on a particular layer */
767 void selectall_layer(Scene *scene, unsigned int layernum) 
768 {
769         Base *base;
770         
771         base= FIRSTBASE;
772         while(base) {
773                 if(base->lay == (1<< (layernum -1)) &&
774                   (base->object->restrictflag & OB_RESTRICT_VIEW)==0
775                 ) {
776                         select_base_v3d(base, BA_SELECT);
777                 }
778                 base= base->next;
779         }
780
781         BIF_undo_push("Select all per layer");
782 }
783
784
785 #if 0
786 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
787 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
788 {
789         Base *base;
790         unsigned int *bufmin,*bufmax;
791         int a,b,rc,tel,aantal,dirvec[4][2],maxob;
792         unsigned int retval=0;
793         
794         base= LASTBASE;
795         if(base==0) return 0;
796         maxob= base->selcol;
797
798         aantal= (size-1)/2;
799         rc= 0;
800
801         dirvec[0][0]= 1;
802         dirvec[0][1]= 0;
803         dirvec[1][0]= 0;
804         dirvec[1][1]= -size;
805         dirvec[2][0]= -1;
806         dirvec[2][1]= 0;
807         dirvec[3][0]= 0;
808         dirvec[3][1]= size;
809
810         bufmin= buf;
811         bufmax= buf+ size*size;
812         buf+= aantal*size+ aantal;
813
814         for(tel=1;tel<=size;tel++) {
815
816                 for(a=0;a<2;a++) {
817                         for(b=0;b<tel;b++) {
818
819                                 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
820                                 if( *buf==dontdo ) retval= dontdo;      /* if only color dontdo is available, still return dontdo */
821                                 
822                                 buf+= (dirvec[rc][0]+dirvec[rc][1]);
823
824                                 if(buf<bufmin || buf>=bufmax) return retval;
825                         }
826                         rc++;
827                         rc &= 3;
828                 }
829         }
830         return retval;
831 }
832 #endif
833
834
835 /* ************************** mouse select ************************* */
836
837
838 #define MAXPICKBUF      10000
839 /* The max number of menu items in an object select menu */
840 #define SEL_MENU_SIZE   22
841
842 void set_active_base(Scene *scene, Base *base)
843 {
844         Base *tbase;
845         
846         /* activating a non-mesh, should end a couple of modes... */
847 //      if(base && base->object->type!=OB_MESH)
848 // XXX          exit_paint_modes();
849         
850         /* sets scene->basact */
851         BASACT= base;
852         
853         if(base) {
854                 
855                 /* signals to buttons */
856 //              redraw_test_buttons(base->object);
857                 
858                 /* signal to ipo */
859 //              allqueue(REDRAWIPO, base->object->ipowin);
860                 
861 //              allqueue(REDRAWACTION, 0);
862 //              allqueue(REDRAWNLA, 0);
863 //              allqueue(REDRAWNODE, 0);
864                 
865                 /* signal to action */
866 //              select_actionchannel_by_name(base->object->action, "Object", 1);
867                 
868                 /* disable temporal locks */
869                 for(tbase=FIRSTBASE; tbase; tbase= tbase->next) {
870                         if(base!=tbase && (tbase->object->shapeflag & OB_SHAPE_TEMPLOCK)) {
871                                 tbase->object->shapeflag &= ~OB_SHAPE_TEMPLOCK;
872                                 DAG_object_flush_update(scene, tbase->object, OB_RECALC_DATA);
873                         }
874                 }
875         }
876 }
877
878
879 static void deselectall_except(Scene *scene, Base *b)   /* deselect all except b */
880 {
881         Base *base;
882         
883         for(base= FIRSTBASE; base; base= base->next) {
884                 if (base->flag & SELECT) {
885                         if(b!=base) {
886                                 select_base_v3d(base, BA_DESELECT);
887                         }
888                 }
889         }
890 }
891
892 static Base *mouse_select_menu(Scene *scene, ARegion *ar, View3D *v3d, unsigned int *buffer, int hits, short *mval)
893 {
894         Base *baseList[SEL_MENU_SIZE]={NULL}; /*baseList is used to store all possible bases to bring up a menu */
895         Base *base;
896         short baseCount = 0;
897         char menuText[20 + SEL_MENU_SIZE*32] = "Select Object%t";       /* max ob name = 22 */
898         char str[32];
899         
900         for(base=FIRSTBASE; base; base= base->next) {
901                 if (BASE_SELECTABLE(v3d, base)) {
902                         baseList[baseCount] = NULL;
903                         
904                         /* two selection methods, the CTRL select uses max dist of 15 */
905                         if(buffer) {
906                                 int a;
907                                 for(a=0; a<hits; a++) {
908                                         /* index was converted */
909                                         if(base->selcol==buffer[ (4 * a) + 3 ]) baseList[baseCount] = base;
910                                 }
911                         }
912                         else {
913                                 int temp, dist=15;
914                                 
915                                 project_short(ar, v3d, base->object->obmat[3], &base->sx);
916                                 
917                                 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
918                                 if(temp<dist ) baseList[baseCount] = base;
919                         }
920                         
921                         if(baseList[baseCount]) {
922                                 if (baseCount < SEL_MENU_SIZE) {
923                                         baseList[baseCount] = base;
924                                         sprintf(str, "|%s %%x%d", base->object->id.name+2, baseCount+1);        /* max ob name == 22 */
925                                                         strcat(menuText, str);
926                                                         baseCount++;
927                                 }
928                         }
929                 }
930         }
931
932         if(baseCount<=1) return baseList[0];
933         else {
934                 baseCount = -1; // XXX = pupmenu(menuText);
935                 
936                 if (baseCount != -1) { /* If nothing is selected then dont do anything */
937                         return baseList[baseCount-1];
938                 }
939                 else return NULL;
940         }
941 }
942
943 /* we want a select buffer with bones, if there are... */
944 /* so check three selection levels and compare */
945 static short mixed_bones_object_selectbuffer(Scene *scene, ARegion *ar, View3D *v3d, unsigned int *buffer, short *mval)
946 {
947         rcti rect;
948         int offs;
949         short a, hits15, hits9=0, hits5=0;
950         short has_bones15=0, has_bones9=0, has_bones5=0;
951         
952         BLI_init_rcti(&rect, mval[0]-14, mval[0]+14, mval[1]-14, mval[1]+14);
953         hits15= view3d_opengl_select(scene, ar, v3d, buffer, MAXPICKBUF, &rect);
954         if(hits15>0) {
955                 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
956                 
957                 offs= 4*hits15;
958                 BLI_init_rcti(&rect, mval[0]-9, mval[0]+9, mval[1]-9, mval[1]+9);
959                 hits9= view3d_opengl_select(scene, ar, v3d, buffer+offs, MAXPICKBUF-offs, &rect);
960                 if(hits9>0) {
961                         for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
962                         
963                         offs+= 4*hits9;
964                         BLI_init_rcti(&rect, mval[0]-5, mval[0]+5, mval[1]-5, mval[1]+5);
965                         hits5= view3d_opengl_select(scene, ar, v3d, buffer+offs, MAXPICKBUF-offs, &rect);
966                         if(hits5>0) {
967                                 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
968                         }
969                 }
970                 
971                 if(has_bones5) {
972                         offs= 4*hits15 + 4*hits9;
973                         memcpy(buffer, buffer+offs, 4*offs);
974                         return hits5;
975                 }
976                 if(has_bones9) {
977                         offs= 4*hits15;
978                         memcpy(buffer, buffer+offs, 4*offs);
979                         return hits9;
980                 }
981                 if(has_bones15) {
982                         return hits15;
983                 }
984                 
985                 if(hits5>0) {
986                         offs= 4*hits15 + 4*hits9;
987                         memcpy(buffer, buffer+offs, 4*offs);
988                         return hits5;
989                 }
990                 if(hits9>0) {
991                         offs= 4*hits15;
992                         memcpy(buffer, buffer+offs, 4*offs);
993                         return hits9;
994                 }
995                 return hits15;
996         }
997         
998         return 0;
999 }
1000
1001 /* mval is region coords */
1002 static void mouse_select(Scene *scene, ARegion *ar, View3D *v3d, short *mval)
1003 {
1004         Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
1005         unsigned int buffer[4*MAXPICKBUF];
1006         int temp, a, dist=100;
1007         short hits;
1008         short ctrl=0, shift=0, alt=0;
1009         
1010         /* always start list from basact in wire mode */
1011         startbase=  FIRSTBASE;
1012         if(BASACT && BASACT->next) startbase= BASACT->next;
1013         
1014         /* This block uses the control key to make the object selected by its center point rather then its contents */
1015         if(G.obedit==0 && ctrl) {
1016                 
1017                 /* note; shift+alt goes to group-flush-selecting */
1018                 if(alt && ctrl) 
1019                         basact= mouse_select_menu(scene, ar, v3d, NULL, 0, mval);
1020                 else {
1021                         base= startbase;
1022                         while(base) {
1023                                 if (BASE_SELECTABLE(v3d, base)) {
1024                                         project_short(ar, v3d, base->object->obmat[3], &base->sx);
1025                                         
1026                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
1027                                         if(base==BASACT) temp+=10;
1028                                         if(temp<dist ) {
1029                                                 
1030                                                 dist= temp;
1031                                                 basact= base;
1032                                         }
1033                                 }
1034                                 base= base->next;
1035                                 
1036                                 if(base==0) base= FIRSTBASE;
1037                                 if(base==startbase) break;
1038                         }
1039                 }
1040         }
1041         else {
1042                 /* if objects have posemode set, the bones are in the same selection buffer */
1043                 
1044                 hits= mixed_bones_object_selectbuffer(scene, ar, v3d, buffer, mval);
1045                 
1046                 if(hits>0) {
1047                         int has_bones= 0;
1048                         
1049                         for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1050
1051                         /* note; shift+alt goes to group-flush-selecting */
1052                         if(has_bones==0 && (alt)) 
1053                                 basact= mouse_select_menu(scene, ar, v3d, buffer, hits, mval);
1054                         else {
1055                                 static short lastmval[2]={-100, -100};
1056                                 int donearest= 0;
1057                                 
1058                                 /* define if we use solid nearest select or not */
1059                                 if(v3d->drawtype>OB_WIRE) {
1060                                         donearest= 1;
1061                                         if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
1062                                                 if(!has_bones)  /* hrms, if theres bones we always do nearest */
1063                                                         donearest= 0;
1064                                         }
1065                                 }
1066                                 lastmval[0]= mval[0]; lastmval[1]= mval[1];
1067                                 
1068                                 if(donearest) {
1069                                         unsigned int min= 0xFFFFFFFF;
1070                                         int selcol= 0, notcol=0;
1071                                         
1072
1073                                         if(has_bones) {
1074                                                 /* we skip non-bone hits */
1075                                                 for(a=0; a<hits; a++) {
1076                                                         if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
1077                                                                 min= buffer[4*a+1];
1078                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1079                                                         }
1080                                                 }
1081                                         }
1082                                         else {
1083                                                 /* only exclude active object when it is selected... */
1084                                                 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol; 
1085                                         
1086                                                 for(a=0; a<hits; a++) {
1087                                                         if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1088                                                                 min= buffer[4*a+1];
1089                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1090                                                         }
1091                                                 }
1092                                         }
1093
1094                                         base= FIRSTBASE;
1095                                         while(base) {
1096                                                 if(base->lay & v3d->lay) {
1097                                                         if(base->selcol==selcol) break;
1098                                                 }
1099                                                 base= base->next;
1100                                         }
1101                                         if(base) basact= base;
1102                                 }
1103                                 else {
1104                                         
1105                                         base= startbase;
1106                                         while(base) {
1107                                                 /* skip objects with select restriction, to prevent prematurely ending this loop
1108                                                  * with an un-selectable choice */
1109                                                 if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1110                                                         base=base->next;
1111                                                         if(base==NULL) base= FIRSTBASE;
1112                                                         if(base==startbase) break;
1113                                                 }
1114                                         
1115                                                 if(base->lay & v3d->lay) {
1116                                                         for(a=0; a<hits; a++) {
1117                                                                 if(has_bones) {
1118                                                                         /* skip non-bone objects */
1119                                                                         if((buffer[4*a+3] & 0xFFFF0000)) {
1120                                                                                 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1121                                                                                         basact= base;
1122                                                                         }
1123                                                                 }
1124                                                                 else {
1125                                                                         if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1126                                                                                 basact= base;
1127                                                                 }
1128                                                         }
1129                                                 }
1130                                                 
1131                                                 if(basact) break;
1132                                                 
1133                                                 base= base->next;
1134                                                 if(base==NULL) base= FIRSTBASE;
1135                                                 if(base==startbase) break;
1136                                         }
1137                                 }
1138                         }
1139                         
1140                         if(has_bones && basact) {
1141                                 if(0) {// XXX do_pose_selectbuffer(basact, buffer, hits) ) {    /* then bone is found */
1142                                 
1143                                         /* we make the armature selected: 
1144                                            not-selected active object in posemode won't work well for tools */
1145                                         basact->flag|= SELECT;
1146                                         basact->object->flag= basact->flag;
1147                                         
1148                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1149                                         if(G.f & G_WEIGHTPAINT) {
1150                                                 /* prevent activating */
1151                                                 basact= NULL;
1152                                         }
1153                                 }
1154                                 /* prevent bone selecting to pass on to object selecting */
1155                                 if(basact==BASACT)
1156                                         basact= NULL;
1157                         }
1158                 }
1159         }
1160         
1161         /* so, do we have something selected? */
1162         if(basact) {
1163                 
1164                 if(G.obedit) {
1165                         /* only do select */
1166                         deselectall_except(scene, basact);
1167                         select_base_v3d(basact, BA_SELECT);
1168                 }
1169                 /* also prevent making it active on mouse selection */
1170                 else if (BASE_SELECTABLE(v3d, basact)) {
1171
1172                         oldbasact= BASACT;
1173                         BASACT= basact;
1174                         
1175                         if(shift==0) {
1176                                 deselectall_except(scene, basact);
1177                                 select_base_v3d(basact, BA_SELECT);
1178                         }
1179                         else if(shift && alt) {
1180                                 // XXX select_all_from_groups(basact);
1181                         }
1182                         else {
1183                                 if(basact->flag & SELECT) {
1184                                         if(basact==oldbasact)
1185                                                 select_base_v3d(basact, BA_DESELECT);
1186                                 }
1187                                 else select_base_v3d(basact, BA_SELECT);
1188                         }
1189
1190                         if(oldbasact != basact) {
1191                                 set_active_base(scene, basact);
1192                         }
1193
1194                         /* for visual speed, only in wire mode */
1195                         if(v3d->drawtype==OB_WIRE) {
1196                                 /* however, not for posemodes */
1197 // XXX                          if(basact->object->flag & OB_POSEMODE);
1198 //                              else if(oldbasact && (oldbasact->object->flag & OB_POSEMODE));
1199 //                              else {
1200 //                                      if(oldbasact && oldbasact != basact && (oldbasact->lay & v3d->lay)) 
1201 //                                              draw_object_ext(oldbasact);
1202 //                                      draw_object_ext(basact);
1203 //                              }
1204                         }
1205                         
1206                 }
1207         }
1208
1209         /* note; make it notifier! */
1210         ED_region_tag_redraw(ar);
1211
1212 }
1213
1214 /* ********************  border and circle ************************************** */
1215
1216
1217 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1218 {
1219         int radsq= rad*rad;
1220         float v1[2], v2[2], v3[2];
1221         
1222         /* check points in circle itself */
1223         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1224         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1225         
1226         /* pointdistline */
1227         v3[0]= centx;
1228         v3[1]= centy;
1229         v1[0]= x1;
1230         v1[1]= y1;
1231         v2[0]= x2;
1232         v2[1]= y2;
1233         
1234         if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1235         
1236         return 0;
1237 }
1238
1239 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1240 {
1241         struct { rcti *rect; int select; } *data = userData;
1242
1243         if (BLI_in_rcti(data->rect, x, y)) {
1244                 if (bp) {
1245                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1246                 } else {
1247                         if (G.f & G_HIDDENHANDLES) {
1248                                 /* can only be beztindex==0 here since handles are hidden */
1249                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1250                         } else {
1251                                 if (beztindex==0) {
1252                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1253                                 } else if (beztindex==1) {
1254                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1255                                 } else {
1256                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1257                                 }
1258                         }
1259                 }
1260         }
1261 }
1262 static void do_nurbs_box_select(ARegion *ar, View3D *v3d, rcti *rect, int select)
1263 {
1264         struct { rcti *rect; int select; } data;
1265
1266         data.rect = rect;
1267         data.select = select;
1268
1269         nurbs_foreachScreenVert(ar, v3d, do_nurbs_box_select__doSelect, &data);
1270 }
1271
1272 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1273 {
1274         struct { rcti *rect; int select; } *data = userData;
1275
1276         if (BLI_in_rcti(data->rect, x, y)) {
1277                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1278         }
1279 }
1280 static void do_lattice_box_select(rcti *rect, int select)
1281 {
1282         struct { rcti *rect; int select, pass, done; } data;
1283
1284         data.rect = rect;
1285         data.select = select;
1286
1287         lattice_foreachScreenVert(do_lattice_box_select__doSelect, &data);
1288 }
1289
1290 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1291 {
1292         struct { rcti *rect; short select, pass, done; } *data = userData;
1293
1294         if (BLI_in_rcti(data->rect, x, y)) {
1295                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1296         }
1297 }
1298 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1299 {
1300         struct { rcti *rect; short select, pass, done; } *data = userData;
1301
1302         if(EM_check_backbuf(em_solidoffs+index)) {
1303                 if (data->pass==0) {
1304                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1305                                 EM_select_edge(eed, data->select);
1306                                 data->done = 1;
1307                         }
1308                 } else {
1309                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1310                                 EM_select_edge(eed, data->select);
1311                         }
1312                 }
1313         }
1314 }
1315 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1316 {
1317         struct { rcti *rect; short select, pass, done; } *data = userData;
1318
1319         if (BLI_in_rcti(data->rect, x, y)) {
1320                 EM_select_face_fgon(efa, data->select);
1321         }
1322 }
1323 static void do_mesh_box_select(Scene *scene, ARegion *ar, View3D *v3d, rcti *rect, int select)
1324 {
1325         struct { rcti *rect; short select, pass, done; } data;
1326         EditMesh *em = G.editMesh;
1327         int bbsel;
1328         
1329         data.rect = rect;
1330         data.select = select;
1331         data.pass = 0;
1332         data.done = 0;
1333
1334         bbsel= EM_init_backbuf_border(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1335
1336         if(scene->selectmode & SCE_SELECT_VERTEX) {
1337                 if (bbsel) {
1338                         EM_backbuf_checkAndSelectVerts(em, select);
1339                 } else {
1340                         mesh_foreachScreenVert(ar, v3d, do_mesh_box_select__doSelectVert, &data, 1);
1341                 }
1342         }
1343         if(scene->selectmode & SCE_SELECT_EDGE) {
1344                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1345
1346                 data.pass = 0;
1347                 mesh_foreachScreenEdge(ar, v3d, do_mesh_box_select__doSelectEdge, &data, 0);
1348
1349                 if (data.done==0) {
1350                         data.pass = 1;
1351                         mesh_foreachScreenEdge(ar, v3d, do_mesh_box_select__doSelectEdge, &data, 0);
1352                 }
1353         }
1354         
1355         if(scene->selectmode & SCE_SELECT_FACE) {
1356                 if(bbsel) {
1357                         EM_backbuf_checkAndSelectFaces(em, select);
1358                 } else {
1359                         mesh_foreachScreenFace(ar, v3d, do_mesh_box_select__doSelectFace, &data);
1360                 }
1361         }
1362         
1363         EM_free_backbuf();
1364                 
1365         EM_selectmode_flush();
1366 }
1367
1368 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
1369 {
1370         Scene *scene= CTX_data_scene(C);
1371         ScrArea *sa= CTX_wm_area(C);
1372         ARegion *ar= CTX_wm_region(C);
1373         View3D *v3d= sa->spacedata.first;
1374         rcti rect;
1375         Base *base;
1376         MetaElem *ml;
1377         unsigned int buffer[4*MAXPICKBUF];
1378         int a, index;
1379         short hits, val;
1380
1381         val= RNA_int_get(op->ptr, "event_type");
1382         rect.xmin= RNA_int_get(op->ptr, "xmin");
1383         rect.ymin= RNA_int_get(op->ptr, "ymin");
1384         rect.xmax= RNA_int_get(op->ptr, "xmax");
1385         rect.ymax= RNA_int_get(op->ptr, "ymax");
1386         
1387         if(G.obedit==NULL && (FACESEL_PAINT_TEST)) {
1388 // XXX          face_borderselect();
1389                 return OPERATOR_FINISHED;
1390         }
1391         else if(G.obedit==NULL && (G.f & G_PARTICLEEDIT)) {
1392 // XXX          PE_borderselect();
1393                 return OPERATOR_FINISHED;
1394         }
1395         
1396         if(G.obedit) {
1397                 if(G.obedit->type==OB_MESH) {
1398                         do_mesh_box_select(scene, ar, v3d, &rect, (val==LEFTMOUSE));
1399 //                      allqueue(REDRAWVIEW3D, 0);
1400 //                      if (EM_texFaceCheck())
1401 //                              allqueue(REDRAWIMAGE, 0);
1402                         
1403                 }
1404                 else if(ELEM(G.obedit->type, OB_CURVE, OB_SURF)) {
1405                         do_nurbs_box_select(ar, v3d, &rect, val==LEFTMOUSE);
1406 //                      allqueue(REDRAWVIEW3D, 0);
1407                 }
1408                 else if(G.obedit->type==OB_MBALL) {
1409                         hits= view3d_opengl_select(scene, ar, v3d, buffer, MAXPICKBUF, &rect);
1410                         
1411                         ml= NULL; // XXX editelems.first;
1412                         
1413                         while(ml) {
1414                                 for(a=0; a<hits; a++) {
1415                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1416                                                 ml->flag |= MB_SCALE_RAD;
1417                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1418                                                 else ml->flag &= ~SELECT;
1419                                                 break;
1420                                         }
1421                                         if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1422                                                 ml->flag &= ~MB_SCALE_RAD;
1423                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1424                                                 else ml->flag &= ~SELECT;
1425                                                 break;
1426                                         }
1427                                 }
1428                                 ml= ml->next;
1429                         }
1430                 }
1431                 else if(G.obedit->type==OB_ARMATURE) {
1432                         EditBone *ebone;
1433                         
1434                         /* clear flag we use to detect point was affected */
1435                         for(ebone= G.edbo.first; ebone; ebone= ebone->next)
1436                                 ebone->flag &= ~BONE_DONE;
1437                         
1438                         hits= view3d_opengl_select(scene, ar, v3d, buffer, MAXPICKBUF, &rect);
1439                         
1440                         /* first we only check points inside the border */
1441                         for (a=0; a<hits; a++){
1442                                 index = buffer[(4*a)+3];
1443                                 if (index!=-1) {
1444                                         ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1445                                         if (index & BONESEL_TIP) {
1446                                                 ebone->flag |= BONE_DONE;
1447                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
1448                                                 else ebone->flag &= ~BONE_TIPSEL;
1449                                         }
1450                                         
1451                                         if (index & BONESEL_ROOT) {
1452                                                 ebone->flag |= BONE_DONE;
1453                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
1454                                                 else ebone->flag &= ~BONE_ROOTSEL;
1455                                         }
1456                                 }
1457                         }
1458                         
1459                         /* now we have to flush tag from parents... */
1460                         for(ebone= G.edbo.first; ebone; ebone= ebone->next) {
1461                                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1462                                         if(ebone->parent->flag & BONE_DONE)
1463                                                 ebone->flag |= BONE_DONE;
1464                                 }
1465                         }
1466                         
1467                         /* only select/deselect entire bones when no points where in the rect */
1468                         for (a=0; a<hits; a++){
1469                                 index = buffer[(4*a)+3];
1470                                 if (index!=-1) {
1471                                         ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1472                                         if (index & BONESEL_BONE) {
1473                                                 if(!(ebone->flag & BONE_DONE)) {
1474                                                         if (val==LEFTMOUSE)
1475                                                                 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1476                                                         else
1477                                                                 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1478                                                 }
1479                                         }
1480                                 }
1481                         }
1482                         
1483                 }
1484                 else if(G.obedit->type==OB_LATTICE) {
1485                         do_lattice_box_select(&rect, val==LEFTMOUSE);
1486                 }
1487         }
1488         else {  /* no editmode, unified for bones and objects */
1489                 Bone *bone;
1490                 unsigned int *vbuffer=NULL; /* selection buffer */
1491                 unsigned int *col;                      /* color in buffer      */
1492                 short selecting = 0;
1493                 Object *ob= OBACT;
1494                 int bone_only;
1495                 
1496                 if((ob) && (ob->flag & OB_POSEMODE))
1497                         bone_only= 1;
1498                 else
1499                         bone_only= 0;
1500                 
1501                 if (val==LEFTMOUSE)
1502                         selecting = 1;
1503                 
1504                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1505                 vbuffer = MEM_mallocN(4 * (G.totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1506                 hits= view3d_opengl_select(scene, ar, v3d, vbuffer, 4*(G.totobj+MAXPICKBUF), &rect);
1507                 /*
1508                 LOGIC NOTES (theeth):
1509                 The buffer and ListBase have the same relative order, which makes the selection
1510                 very simple. Loop through both data sets at the same time, if the color
1511                 is the same as the object, we have a hit and can move to the next color
1512                 and object pair, if not, just move to the next object,
1513                 keeping the same color until we have a hit.
1514
1515                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1516                 does it incorrectly.
1517                 */
1518
1519                 if (hits>0) { /* no need to loop if there's no hit */
1520                         base= FIRSTBASE;
1521                         col = vbuffer + 3;
1522                         while(base && hits) {
1523                                 Base *next = base->next;
1524                                 if(base->lay & v3d->lay) {
1525                                         while (base->selcol == (*col & 0xFFFF)) {       /* we got an object */
1526                                                 
1527                                                 if(*col & 0xFFFF0000) {                                 /* we got a bone */
1528                                                         bone = NULL; // XXX get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1529                                                         if(bone) {
1530                                                                 if(selecting) {
1531                                                                         bone->flag |= BONE_SELECTED;
1532 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 1);
1533                                                                 }
1534                                                                 else {
1535                                                                         bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1536 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 0);
1537                                                                 }
1538                                                         }
1539                                                 }
1540                                                 else if(!bone_only) {
1541                                                         if (selecting)
1542                                                                 select_base_v3d(base, BA_SELECT);
1543                                                         else
1544                                                                 select_base_v3d(base, BA_DESELECT);
1545                                                 }
1546
1547                                                 col+=4; /* next color */
1548                                                 hits--;
1549                                                 if(hits==0) break;
1550                                         }
1551                                 }
1552                                 
1553                                 base= next;
1554                         }
1555                 }
1556                 MEM_freeN(vbuffer);
1557         }
1558
1559         BIF_undo_push("Border select");
1560         
1561         return OPERATOR_FINISHED;
1562
1563
1564
1565 /* *****************Selection Operators******************* */
1566
1567 /* ****** Border Select ****** */
1568 void VIEW3D_OT_borderselect(wmOperatorType *ot)
1569 {
1570         
1571         /* identifiers */
1572         ot->name= "Border Select";
1573         ot->idname= "VIEW3D_OT_borderselect";
1574         
1575         /* api callbacks */
1576         ot->invoke= WM_border_select_invoke;
1577         ot->exec= view3d_borderselect_exec;
1578         ot->modal= WM_border_select_modal;
1579         
1580         ot->poll= ED_operator_view3d_active;
1581         
1582         /* rna */
1583         RNA_def_property(ot->srna, "event_type", PROP_INT, PROP_NONE);
1584         RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
1585         RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
1586         RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
1587         RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
1588 }
1589
1590 /* ****** Mouse Select ****** */
1591 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1592 {
1593         ScrArea *sa= CTX_wm_area(C);
1594         ARegion *ar= CTX_wm_region(C);
1595         View3D *v3d= sa->spacedata.first;
1596         Scene *scene= CTX_data_scene(C);
1597         short mval[2];  
1598         
1599         mval[0]= event->x - ar->winrct.xmin;
1600         mval[1]= event->y - ar->winrct.ymin;
1601
1602         view3d_operator_needs_opengl(C);
1603         
1604         mouse_select(scene, ar, v3d, mval);
1605         
1606         return OPERATOR_FINISHED;
1607 }
1608
1609 void VIEW3D_OT_select(wmOperatorType *ot)
1610 {
1611
1612         /* identifiers */
1613         ot->name= "Activate/Select";
1614         ot->idname= "VIEW3D_OT_select";
1615         
1616         /* api callbacks */
1617         ot->invoke= view3d_select_invoke;
1618         ot->poll= ED_operator_view3d_active;
1619
1620 }
1621
1622 /* ****** Select by Type ****** */
1623 static EnumPropertyItem prop_select_object_types[] = {
1624         {OB_EMPTY, "EMPTY", "Empty", ""},
1625         {OB_MESH, "MESH", "Mesh", ""},
1626         {OB_CURVE, "CURVE", "Curve", ""},
1627         {OB_SURF, "SURFACE", "Surface", ""},
1628         {OB_FONT, "TEXT", "Text", ""},
1629         {OB_MBALL, "META", "Meta", ""},
1630         {OB_LAMP, "LAMP", "Lamp", ""},
1631         {OB_CAMERA, "CAMERA", "Camera", ""},
1632         {OB_LATTICE, "LATTICE", "Lattice", ""},
1633         {0, NULL, NULL, NULL}
1634 };
1635
1636 static int view3d_select_by_type_exec(bContext *C, wmOperator *op)
1637 {
1638         ARegion *ar= CTX_wm_region(C);
1639         short obtype;
1640         
1641         obtype = RNA_enum_get(op->ptr, "type");
1642                 
1643         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1644                 if(base->object->type==obtype) {
1645                         select_base_v3d(base, BA_SELECT);
1646                 }
1647         }
1648         CTX_DATA_END;
1649         
1650         /* undo? */
1651         ED_region_tag_redraw(ar);
1652         
1653         return OPERATOR_FINISHED;
1654 }
1655
1656 void VIEW3D_OT_select_by_type(wmOperatorType *ot)
1657 {
1658         PropertyRNA *prop;
1659         
1660         /* identifiers */
1661         ot->name= "Select By Type";
1662         ot->idname= "VIEW3D_OT_select_by_type";
1663         
1664         /* api callbacks */
1665         ot->invoke= WM_menu_invoke;
1666         ot->exec= view3d_select_by_type_exec;
1667         ot->poll= ED_operator_view3d_active;
1668         
1669         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
1670         RNA_def_property_enum_items(prop, prop_select_object_types);
1671
1672 }
1673
1674 /* ****** invert selection *******/
1675 static int view3d_select_invert_invoke(bContext *C, wmOperator *op, wmEvent *event)
1676 {
1677         ScrArea *sa= CTX_wm_area(C);
1678         View3D *v3d= sa->spacedata.first;
1679         ARegion *ar= CTX_wm_region(C);
1680         Scene *scene= CTX_data_scene(C);
1681         
1682         selectswap(scene, v3d);
1683         
1684         ED_region_tag_redraw(ar);
1685         
1686         return OPERATOR_FINISHED;
1687 }
1688
1689 void VIEW3D_OT_select_invert(wmOperatorType *ot)
1690 {
1691         
1692         /* identifiers */
1693         ot->name= "Invert selection";
1694         ot->idname= "VIEW3D_OT_select_invert";
1695         
1696         /* api callbacks */
1697         ot->invoke= view3d_select_invert_invoke;
1698         ot->poll= ED_operator_view3d_active;
1699
1700 }
1701 /* ****** (de)select All *******/
1702 static int view3d_de_select_all_invoke(bContext *C, wmOperator *op, wmEvent *event)
1703 {
1704         ScrArea *sa= CTX_wm_area(C);
1705         View3D *v3d= sa->spacedata.first;
1706         ARegion *ar= CTX_wm_region(C);
1707         Scene *scene= CTX_data_scene(C);
1708         
1709         deselectall(scene, v3d);
1710         
1711         ED_region_tag_redraw(ar);
1712         
1713         return OPERATOR_FINISHED;
1714 }
1715
1716 void VIEW3D_OT_de_select_all(wmOperatorType *ot)
1717 {
1718         
1719         /* identifiers */
1720         ot->name= "deselect all";
1721         ot->idname= "VIEW3D_OT_de_select_all";
1722         
1723         /* api callbacks */
1724         ot->invoke= view3d_de_select_all_invoke;
1725         ot->poll= ED_operator_view3d_active;
1726
1727 }
1728 /* ****** random selection *******/
1729 static int view3d_select_random_invoke(bContext *C, wmOperator *op, wmEvent *event)
1730 {
1731         ScrArea *sa= CTX_wm_area(C);
1732         View3D *v3d= sa->spacedata.first;
1733         ARegion *ar= CTX_wm_region(C);
1734         Scene *scene= CTX_data_scene(C);
1735         short randfac;
1736         
1737         /* uiPupmenuOperator(C, 0, op, "percent", "percent"); XXX - need a number popup */
1738         
1739         randfac = RNA_int_get(op->ptr, "percent");
1740         
1741         selectrandom(scene, v3d, randfac);
1742         
1743         ED_region_tag_redraw(ar);
1744         
1745         return OPERATOR_FINISHED;
1746 }
1747
1748 void VIEW3D_OT_select_random(wmOperatorType *ot)
1749 {
1750         PropertyRNA *prop;
1751         
1752         /* identifiers */
1753         ot->name= "Random selection";
1754         ot->idname= "VIEW3D_OT_select_random";
1755         
1756         /* api callbacks */
1757         ot->invoke= view3d_select_random_invoke;
1758         ot->poll= ED_operator_view3d_active;
1759         
1760         prop = RNA_def_property(ot->srna, "percent", PROP_INT, PROP_NONE);
1761         RNA_def_property_ui_range(prop, 1, 100,1, 1);
1762         RNA_def_property_ui_text(prop, "Percent", "Max persentage that will be selected");
1763         RNA_def_property_int_default(prop, 50);
1764 }
1765 /* ------------------------------------------------------------------------- */
1766
1767 /** The following functions are quick & dirty callback functions called
1768   * on the Circle select function (press B twice in Editmode)
1769   * They were torn out of the circle_select to make the latter more reusable
1770   * The callback version of circle_select (called circle_selectCB) was moved
1771   * to edit.c because of it's (wanted) generality.
1772
1773         XXX These callback functions are still dirty, because they call globals... 
1774   */
1775
1776 static void mesh_selectionCB__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1777 {
1778         struct { short select, mval[2]; float radius; } *data = userData;
1779         int mx = x - data->mval[0], my = y - data->mval[1];
1780         float r = sqrt(mx*mx + my*my);
1781
1782         if (r<=data->radius) {
1783                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1784         }
1785 }
1786 static void mesh_selectionCB__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1787 {
1788         struct { short select, mval[2]; float radius; } *data = userData;
1789
1790         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1791                 EM_select_edge(eed, data->select);
1792         }
1793 }
1794 static void mesh_selectionCB__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1795 {
1796         struct { short select, mval[2]; float radius; } *data = userData;
1797         int mx = x - data->mval[0], my = y - data->mval[1];
1798         float r = sqrt(mx*mx + my*my);
1799
1800         if (r<=data->radius) {
1801                 EM_select_face_fgon(efa, data->select);
1802         }
1803 }
1804
1805 static void mesh_selectionCB(Scene *scene, ARegion *ar, View3D *v3d, int selecting, Object *editobj, short *mval, float rad)
1806 {
1807         struct { short select, mval[2]; float radius; } data;
1808         EditMesh *em = G.editMesh;
1809         int bbsel;
1810
1811         if(!G.obedit && (FACESEL_PAINT_TEST)) {
1812                 Object *ob= OBACT;
1813                 Mesh *me = ob?ob->data:NULL;
1814
1815                 if (me) {
1816                         em_vertoffs= me->totface+1;     /* max index array */
1817
1818                         bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
1819                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1820                         EM_free_backbuf();
1821
1822 // XXX                  object_tface_flags_changed(OBACT, 0);
1823                 }
1824
1825                 return;
1826         }
1827
1828         bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
1829         
1830         data.select = (selecting==LEFTMOUSE);
1831         data.mval[0] = mval[0];
1832         data.mval[1] = mval[1];
1833         data.radius = rad;
1834
1835         if(scene->selectmode & SCE_SELECT_VERTEX) {
1836                 if(bbsel) {
1837                         EM_backbuf_checkAndSelectVerts(em, selecting==LEFTMOUSE);
1838                 } else {
1839                         mesh_foreachScreenVert(ar, v3d, mesh_selectionCB__doSelectVert, &data, 1);
1840                 }
1841         }
1842
1843         if(scene->selectmode & SCE_SELECT_EDGE) {
1844                 if (bbsel) {
1845                         EM_backbuf_checkAndSelectEdges(em, selecting==LEFTMOUSE);
1846                 } else {
1847                         mesh_foreachScreenEdge(ar, v3d, mesh_selectionCB__doSelectEdge, &data, 0);
1848                 }
1849         }
1850         
1851         if(scene->selectmode & SCE_SELECT_FACE) {
1852                 if(bbsel) {
1853                         EM_backbuf_checkAndSelectFaces(em, selecting==LEFTMOUSE);
1854                 } else {
1855                         mesh_foreachScreenFace(ar, v3d, mesh_selectionCB__doSelectFace, &data);
1856                 }
1857         }
1858
1859         EM_free_backbuf();
1860         EM_selectmode_flush();
1861 }
1862
1863
1864 static void nurbscurve_selectionCB__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, 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                 if (bp) {
1872                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1873                 } else {
1874                         if (beztindex==0) {
1875                                 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1876                         } else if (beztindex==1) {
1877                                 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1878                         } else {
1879                                 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1880                         }
1881                 }
1882         }
1883 }
1884 static void nurbscurve_selectionCB(ARegion *ar, View3D *v3d, int selecting, Object *editobj, short *mval, float rad)
1885 {
1886         struct { short select, mval[2]; float radius; } data;
1887
1888         data.select = (selecting==LEFTMOUSE);
1889         data.mval[0] = mval[0];
1890         data.mval[1] = mval[1];
1891         data.radius = rad;
1892
1893         nurbs_foreachScreenVert(ar, v3d, nurbscurve_selectionCB__doSelect, &data);
1894 }
1895
1896
1897 static void latticecurve_selectionCB__doSelect(void *userData, BPoint *bp, int x, int y)
1898 {
1899         struct { short select, mval[2]; float radius; } *data = userData;
1900         int mx = x - data->mval[0], my = y - data->mval[1];
1901         float r = sqrt(mx*mx + my*my);
1902
1903         if (r<=data->radius) {
1904                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1905         }
1906 }
1907 static void lattice_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1908 {
1909         struct { short select, mval[2]; float radius; } data;
1910
1911         data.select = (selecting==LEFTMOUSE);
1912         data.mval[0] = mval[0];
1913         data.mval[1] = mval[1];
1914         data.radius = rad;
1915
1916         lattice_foreachScreenVert(latticecurve_selectionCB__doSelect, &data);
1917 }
1918
1919 /** Callbacks for selection in Editmode */
1920
1921 void obedit_selectionCB(Scene *scene, ARegion *ar, View3D *v3d, short selecting, Object *editobj, short *mval, float rad) 
1922 {
1923         switch(editobj->type) {         
1924         case OB_MESH:
1925                 mesh_selectionCB(scene, ar, v3d, selecting, editobj, mval, rad);
1926                 break;
1927         case OB_CURVE:
1928         case OB_SURF:
1929                 nurbscurve_selectionCB(ar, v3d, selecting, editobj, mval, rad);
1930                 break;
1931         case OB_LATTICE:
1932                 lattice_selectionCB(selecting, editobj, mval, rad);
1933                 break;
1934         default:
1935                 return;
1936         }
1937
1938 //      draw_sel_circle(0, 0, 0, 0, 0); /* signal */
1939 //      force_draw(0);
1940 }
1941
1942 static int view3d_circle_select(bContext *C, wmOperator *op)
1943 {
1944         ScrArea *sa= CTX_wm_area(C);
1945         ARegion *ar= CTX_wm_region(C);
1946         Scene *scene= CTX_data_scene(C);
1947         View3D *v3d= sa->spacedata.first;
1948         Base *base;
1949
1950         int x= RNA_int_get(op->ptr, "x");
1951         int y= RNA_int_get(op->ptr, "y");
1952         int radius= RNA_int_get(op->ptr, "radius");
1953         
1954         for(base= FIRSTBASE; base; base= base->next) {
1955                 if(base->lay & v3d->lay) {
1956                         project_short(ar, v3d, base->object->obmat[3], &base->sx);
1957                         if(base->sx!=IS_CLIPPED) {
1958                                 int dx= base->sx-x;
1959                                 int dy= base->sy-y;
1960                                 if( dx*dx + dy*dy < radius*radius)
1961                                         select_base_v3d(base, BA_SELECT);
1962                         }
1963                 }
1964         }
1965         return 0;
1966 }
1967
1968 void VIEW3D_OT_circle_select(wmOperatorType *ot)
1969 {
1970         ot->name= "Circle Select";
1971         ot->idname= "VIEW3D_OT_circle_select";
1972         
1973         ot->invoke= WM_gesture_circle_invoke;
1974         ot->modal= WM_gesture_circle_modal;
1975         ot->exec= view3d_circle_select;
1976         ot->poll= ED_operator_view3d_active;
1977         
1978         RNA_def_property(ot->srna, "x", PROP_INT, PROP_NONE);
1979         RNA_def_property(ot->srna, "y", PROP_INT, PROP_NONE);
1980         RNA_def_property(ot->srna, "radius", PROP_INT, PROP_NONE);
1981         
1982 }