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