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