just silenced a warning, thx kaito for pointing it out
[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, short randfac)
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 /* ********************  border and circle ************************************** */
1238
1239
1240 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1241 {
1242         int radsq= rad*rad;
1243         float v1[2], v2[2], v3[2];
1244         
1245         /* check points in circle itself */
1246         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1247         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1248         
1249         /* pointdistline */
1250         v3[0]= centx;
1251         v3[1]= centy;
1252         v1[0]= x1;
1253         v1[1]= y1;
1254         v2[0]= x2;
1255         v2[1]= y2;
1256         
1257         if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1258         
1259         return 0;
1260 }
1261
1262 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1263 {
1264         struct { rcti *rect; int select; } *data = userData;
1265
1266         if (BLI_in_rcti(data->rect, x, y)) {
1267                 if (bp) {
1268                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1269                 } else {
1270                         if (G.f & G_HIDDENHANDLES) {
1271                                 /* can only be beztindex==0 here since handles are hidden */
1272                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1273                         } else {
1274                                 if (beztindex==0) {
1275                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1276                                 } else if (beztindex==1) {
1277                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1278                                 } else {
1279                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1280                                 }
1281                         }
1282                 }
1283         }
1284 }
1285 static void do_nurbs_box_select(ARegion *ar, View3D *v3d, rcti *rect, int select)
1286 {
1287         struct { rcti *rect; int select; } data;
1288
1289         data.rect = rect;
1290         data.select = select;
1291
1292         nurbs_foreachScreenVert(ar, v3d, do_nurbs_box_select__doSelect, &data);
1293 }
1294
1295 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1296 {
1297         struct { rcti *rect; int select; } *data = userData;
1298
1299         if (BLI_in_rcti(data->rect, x, y)) {
1300                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1301         }
1302 }
1303 static void do_lattice_box_select(rcti *rect, int select)
1304 {
1305         struct { rcti *rect; int select, pass, done; } data;
1306
1307         data.rect = rect;
1308         data.select = select;
1309
1310         lattice_foreachScreenVert(do_lattice_box_select__doSelect, &data);
1311 }
1312
1313 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1314 {
1315         struct { rcti *rect; short select, pass, done; } *data = userData;
1316
1317         if (BLI_in_rcti(data->rect, x, y)) {
1318                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1319         }
1320 }
1321 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1322 {
1323         struct { rcti *rect; short select, pass, done; } *data = userData;
1324
1325         if(EM_check_backbuf(em_solidoffs+index)) {
1326                 if (data->pass==0) {
1327                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1328                                 EM_select_edge(eed, data->select);
1329                                 data->done = 1;
1330                         }
1331                 } else {
1332                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1333                                 EM_select_edge(eed, data->select);
1334                         }
1335                 }
1336         }
1337 }
1338 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1339 {
1340         struct { rcti *rect; short select, pass, done; } *data = userData;
1341
1342         if (BLI_in_rcti(data->rect, x, y)) {
1343                 EM_select_face_fgon(efa, data->select);
1344         }
1345 }
1346 static void do_mesh_box_select(Scene *scene, ARegion *ar, View3D *v3d, rcti *rect, int select)
1347 {
1348         struct { rcti *rect; short select, pass, done; } data;
1349         EditMesh *em = G.editMesh;
1350         int bbsel;
1351         
1352         data.rect = rect;
1353         data.select = select;
1354         data.pass = 0;
1355         data.done = 0;
1356
1357         bbsel= EM_init_backbuf_border(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1358
1359         if(scene->selectmode & SCE_SELECT_VERTEX) {
1360                 if (bbsel) {
1361                         EM_backbuf_checkAndSelectVerts(em, select);
1362                 } else {
1363                         mesh_foreachScreenVert(ar, v3d, do_mesh_box_select__doSelectVert, &data, 1);
1364                 }
1365         }
1366         if(scene->selectmode & SCE_SELECT_EDGE) {
1367                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1368
1369                 data.pass = 0;
1370                 mesh_foreachScreenEdge(ar, v3d, do_mesh_box_select__doSelectEdge, &data, 0);
1371
1372                 if (data.done==0) {
1373                         data.pass = 1;
1374                         mesh_foreachScreenEdge(ar, v3d, do_mesh_box_select__doSelectEdge, &data, 0);
1375                 }
1376         }
1377         
1378         if(scene->selectmode & SCE_SELECT_FACE) {
1379                 if(bbsel) {
1380                         EM_backbuf_checkAndSelectFaces(em, select);
1381                 } else {
1382                         mesh_foreachScreenFace(ar, v3d, do_mesh_box_select__doSelectFace, &data);
1383                 }
1384         }
1385         
1386         EM_free_backbuf();
1387                 
1388         EM_selectmode_flush();
1389 }
1390
1391 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
1392 {
1393         Scene *scene= CTX_data_scene(C);
1394         ScrArea *sa= CTX_wm_area(C);
1395         ARegion *ar= CTX_wm_region(C);
1396         View3D *v3d= sa->spacedata.first;
1397         rcti rect;
1398         Base *base;
1399         MetaElem *ml;
1400         unsigned int buffer[4*MAXPICKBUF];
1401         int a, index;
1402         short hits, val;
1403
1404         val= RNA_int_get(op->ptr, "event_type");
1405         rect.xmin= RNA_int_get(op->ptr, "xmin");
1406         rect.ymin= RNA_int_get(op->ptr, "ymin");
1407         rect.xmax= RNA_int_get(op->ptr, "xmax");
1408         rect.ymax= RNA_int_get(op->ptr, "ymax");
1409         
1410         if(G.obedit==NULL && (FACESEL_PAINT_TEST)) {
1411 // XXX          face_borderselect();
1412                 return OPERATOR_FINISHED;
1413         }
1414         else if(G.obedit==NULL && (G.f & G_PARTICLEEDIT)) {
1415 // XXX          PE_borderselect();
1416                 return OPERATOR_FINISHED;
1417         }
1418         
1419         if(G.obedit) {
1420                 if(G.obedit->type==OB_MESH) {
1421                         do_mesh_box_select(scene, ar, v3d, &rect, (val==LEFTMOUSE));
1422 //                      allqueue(REDRAWVIEW3D, 0);
1423 //                      if (EM_texFaceCheck())
1424 //                              allqueue(REDRAWIMAGE, 0);
1425                         
1426                 }
1427                 else if(ELEM(G.obedit->type, OB_CURVE, OB_SURF)) {
1428                         do_nurbs_box_select(ar, v3d, &rect, val==LEFTMOUSE);
1429 //                      allqueue(REDRAWVIEW3D, 0);
1430                 }
1431                 else if(G.obedit->type==OB_MBALL) {
1432                         hits= view3d_opengl_select(scene, ar, v3d, buffer, MAXPICKBUF, &rect);
1433                         
1434                         ml= NULL; // XXX editelems.first;
1435                         
1436                         while(ml) {
1437                                 for(a=0; a<hits; a++) {
1438                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1439                                                 ml->flag |= MB_SCALE_RAD;
1440                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1441                                                 else ml->flag &= ~SELECT;
1442                                                 break;
1443                                         }
1444                                         if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1445                                                 ml->flag &= ~MB_SCALE_RAD;
1446                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1447                                                 else ml->flag &= ~SELECT;
1448                                                 break;
1449                                         }
1450                                 }
1451                                 ml= ml->next;
1452                         }
1453                 }
1454                 else if(G.obedit->type==OB_ARMATURE) {
1455                         EditBone *ebone;
1456                         
1457                         /* clear flag we use to detect point was affected */
1458                         for(ebone= G.edbo.first; ebone; ebone= ebone->next)
1459                                 ebone->flag &= ~BONE_DONE;
1460                         
1461                         hits= view3d_opengl_select(scene, ar, v3d, buffer, MAXPICKBUF, &rect);
1462                         
1463                         /* first we only check points inside the border */
1464                         for (a=0; a<hits; a++){
1465                                 index = buffer[(4*a)+3];
1466                                 if (index!=-1) {
1467                                         ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1468                                         if (index & BONESEL_TIP) {
1469                                                 ebone->flag |= BONE_DONE;
1470                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
1471                                                 else ebone->flag &= ~BONE_TIPSEL;
1472                                         }
1473                                         
1474                                         if (index & BONESEL_ROOT) {
1475                                                 ebone->flag |= BONE_DONE;
1476                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
1477                                                 else ebone->flag &= ~BONE_ROOTSEL;
1478                                         }
1479                                 }
1480                         }
1481                         
1482                         /* now we have to flush tag from parents... */
1483                         for(ebone= G.edbo.first; ebone; ebone= ebone->next) {
1484                                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1485                                         if(ebone->parent->flag & BONE_DONE)
1486                                                 ebone->flag |= BONE_DONE;
1487                                 }
1488                         }
1489                         
1490                         /* only select/deselect entire bones when no points where in the rect */
1491                         for (a=0; a<hits; a++){
1492                                 index = buffer[(4*a)+3];
1493                                 if (index!=-1) {
1494                                         ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1495                                         if (index & BONESEL_BONE) {
1496                                                 if(!(ebone->flag & BONE_DONE)) {
1497                                                         if (val==LEFTMOUSE)
1498                                                                 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1499                                                         else
1500                                                                 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1501                                                 }
1502                                         }
1503                                 }
1504                         }
1505                         
1506                 }
1507                 else if(G.obedit->type==OB_LATTICE) {
1508                         do_lattice_box_select(&rect, val==LEFTMOUSE);
1509                 }
1510         }
1511         else {  /* no editmode, unified for bones and objects */
1512                 Bone *bone;
1513                 unsigned int *vbuffer=NULL; /* selection buffer */
1514                 unsigned int *col;                      /* color in buffer      */
1515                 short selecting = 0;
1516                 Object *ob= OBACT;
1517                 int bone_only;
1518                 
1519                 if((ob) && (ob->flag & OB_POSEMODE))
1520                         bone_only= 1;
1521                 else
1522                         bone_only= 0;
1523                 
1524                 if (val==LEFTMOUSE)
1525                         selecting = 1;
1526                 
1527                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1528                 vbuffer = MEM_mallocN(4 * (G.totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1529                 hits= view3d_opengl_select(scene, ar, v3d, vbuffer, 4*(G.totobj+MAXPICKBUF), &rect);
1530                 /*
1531                 LOGIC NOTES (theeth):
1532                 The buffer and ListBase have the same relative order, which makes the selection
1533                 very simple. Loop through both data sets at the same time, if the color
1534                 is the same as the object, we have a hit and can move to the next color
1535                 and object pair, if not, just move to the next object,
1536                 keeping the same color until we have a hit.
1537
1538                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1539                 does it incorrectly.
1540                 */
1541
1542                 if (hits>0) { /* no need to loop if there's no hit */
1543                         base= FIRSTBASE;
1544                         col = vbuffer + 3;
1545                         while(base && hits) {
1546                                 Base *next = base->next;
1547                                 if(base->lay & v3d->lay) {
1548                                         while (base->selcol == (*col & 0xFFFF)) {       /* we got an object */
1549                                                 
1550                                                 if(*col & 0xFFFF0000) {                                 /* we got a bone */
1551                                                         bone = NULL; // XXX get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1552                                                         if(bone) {
1553                                                                 if(selecting) {
1554                                                                         bone->flag |= BONE_SELECTED;
1555 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 1);
1556                                                                 }
1557                                                                 else {
1558                                                                         bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1559 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 0);
1560                                                                 }
1561                                                         }
1562                                                 }
1563                                                 else if(!bone_only) {
1564                                                         if (selecting)
1565                                                                 select_base_v3d(base, BA_SELECT);
1566                                                         else
1567                                                                 select_base_v3d(base, BA_DESELECT);
1568
1569                                                         base->object->flag= base->flag;
1570                                                 }
1571
1572                                                 col+=4; /* next color */
1573                                                 hits--;
1574                                                 if(hits==0) break;
1575                                         }
1576                                 }
1577                                 
1578                                 base= next;
1579                         }
1580                 }
1581                 MEM_freeN(vbuffer);
1582         }
1583
1584         BIF_undo_push("Border select");
1585         
1586         return OPERATOR_FINISHED;
1587
1588
1589
1590 /* *****************Selection Operators******************* */
1591
1592 /* ****** Border Select ****** */
1593 void VIEW3D_OT_borderselect(wmOperatorType *ot)
1594 {
1595         
1596         /* identifiers */
1597         ot->name= "Border Select";
1598         ot->idname= "VIEW3D_OT_borderselect";
1599         
1600         /* api callbacks */
1601         ot->invoke= WM_border_select_invoke;
1602         ot->exec= view3d_borderselect_exec;
1603         ot->modal= WM_border_select_modal;
1604         
1605         ot->poll= ED_operator_view3d_active;
1606         
1607         /* rna */
1608         RNA_def_property(ot->srna, "event_type", PROP_INT, PROP_NONE);
1609         RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
1610         RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
1611         RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
1612         RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
1613 }
1614
1615 /* ****** Mouse Select ****** */
1616 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1617 {
1618         ScrArea *sa= CTX_wm_area(C);
1619         ARegion *ar= CTX_wm_region(C);
1620         View3D *v3d= sa->spacedata.first;
1621         Scene *scene= CTX_data_scene(C);
1622         short mval[2];  
1623         
1624         mval[0]= event->x - ar->winrct.xmin;
1625         mval[1]= event->y - ar->winrct.ymin;
1626
1627         view3d_operator_needs_opengl(C);
1628         
1629         mouse_select(scene, ar, v3d, mval);
1630         
1631         return OPERATOR_FINISHED;
1632 }
1633
1634 void VIEW3D_OT_select(wmOperatorType *ot)
1635 {
1636
1637         /* identifiers */
1638         ot->name= "Activate/Select";
1639         ot->idname= "VIEW3D_OT_select";
1640         
1641         /* api callbacks */
1642         ot->invoke= view3d_select_invoke;
1643         ot->poll= ED_operator_view3d_active;
1644
1645 }
1646
1647 /* ****** Select by Type ****** */
1648 static EnumPropertyItem prop_select_object_types[] = {
1649         {OB_EMPTY, "EMPTY", "Empty", ""},
1650         {OB_MESH, "MESH", "Mesh", ""},
1651         {OB_CURVE, "CURVE", "Curve", ""},
1652         {OB_SURF, "SURFACE", "Surface", ""},
1653         {OB_FONT, "TEXT", "Text", ""},
1654         {OB_MBALL, "META", "Meta", ""},
1655         {OB_LAMP, "LAMP", "Lamp", ""},
1656         {OB_CAMERA, "CAMERA", "Camera", ""},
1657         {OB_LATTICE, "LATTICE", "Lattice", ""},
1658         {0, NULL, NULL, NULL}
1659 };
1660
1661 static int view3d_select_by_type_exec(bContext *C, wmOperator *op)
1662 {
1663         ScrArea *sa= CTX_wm_area(C);
1664         ARegion *ar= CTX_wm_region(C);
1665         View3D *v3d= sa->spacedata.first;
1666         Scene *scene= CTX_data_scene(C);
1667         short obtype;
1668         
1669         obtype = RNA_enum_get(op->ptr, "type");
1670                 
1671         selectall_type(scene, v3d, obtype);
1672         
1673         ED_region_tag_redraw(ar);
1674         
1675         return OPERATOR_FINISHED;
1676 }
1677
1678 void VIEW3D_OT_select_by_type(wmOperatorType *ot)
1679 {
1680         PropertyRNA *prop;
1681         
1682         /* identifiers */
1683         ot->name= "Select By Type";
1684         ot->idname= "VIEW3D_OT_select_by_type";
1685         
1686         /* api callbacks */
1687         ot->invoke= WM_menu_invoke;
1688         ot->exec= view3d_select_by_type_exec;
1689         ot->poll= ED_operator_view3d_active;
1690         
1691         prop = RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
1692         RNA_def_property_enum_items(prop, prop_select_object_types);
1693
1694 }
1695
1696 /* ****** invert selection *******/
1697 static int view3d_select_invert_invoke(bContext *C, wmOperator *op, wmEvent *event)
1698 {
1699         ScrArea *sa= CTX_wm_area(C);
1700         View3D *v3d= sa->spacedata.first;
1701         ARegion *ar= CTX_wm_region(C);
1702         Scene *scene= CTX_data_scene(C);
1703         
1704         selectswap(scene, v3d);
1705         
1706         ED_region_tag_redraw(ar);
1707         
1708         return OPERATOR_FINISHED;
1709 }
1710
1711 void VIEW3D_OT_select_invert(wmOperatorType *ot)
1712 {
1713         
1714         /* identifiers */
1715         ot->name= "Invert selection";
1716         ot->idname= "VIEW3D_OT_select_invert";
1717         
1718         /* api callbacks */
1719         ot->invoke= view3d_select_invert_invoke;
1720         ot->poll= ED_operator_view3d_active;
1721
1722 }
1723 /* ****** (de)select All *******/
1724 static int view3d_de_select_all_invoke(bContext *C, wmOperator *op, wmEvent *event)
1725 {
1726         ScrArea *sa= CTX_wm_area(C);
1727         View3D *v3d= sa->spacedata.first;
1728         ARegion *ar= CTX_wm_region(C);
1729         Scene *scene= CTX_data_scene(C);
1730         
1731         deselectall(scene, v3d);
1732         
1733         ED_region_tag_redraw(ar);
1734         
1735         return OPERATOR_FINISHED;
1736 }
1737
1738 void VIEW3D_OT_de_select_all(wmOperatorType *ot)
1739 {
1740         
1741         /* identifiers */
1742         ot->name= "deselect all";
1743         ot->idname= "VIEW3D_OT_de_select_all";
1744         
1745         /* api callbacks */
1746         ot->invoke= view3d_de_select_all_invoke;
1747         ot->poll= ED_operator_view3d_active;
1748
1749 }
1750 /* ****** random selection *******/
1751 static int view3d_select_random_invoke(bContext *C, wmOperator *op, wmEvent *event)
1752 {
1753         ScrArea *sa= CTX_wm_area(C);
1754         View3D *v3d= sa->spacedata.first;
1755         ARegion *ar= CTX_wm_region(C);
1756         Scene *scene= CTX_data_scene(C);
1757         short randfac;
1758         
1759         /* uiPupmenuOperator(C, 0, op, "percent", "percent"); XXX - need a number popup */
1760         
1761         randfac = RNA_int_get(op->ptr, "percent");
1762         
1763         selectrandom(scene, v3d, randfac);
1764         
1765         ED_region_tag_redraw(ar);
1766         
1767         return OPERATOR_FINISHED;
1768 }
1769
1770 void VIEW3D_OT_select_random(wmOperatorType *ot)
1771 {
1772         PropertyRNA *prop;
1773         
1774         /* identifiers */
1775         ot->name= "Random selection";
1776         ot->idname= "VIEW3D_OT_select_random";
1777         
1778         /* api callbacks */
1779         ot->invoke= view3d_select_random_invoke;
1780         ot->poll= ED_operator_view3d_active;
1781         
1782         prop = RNA_def_property(ot->srna, "percent", PROP_INT, PROP_NONE);
1783         RNA_def_property_ui_range(prop, 1, 100,1, 1);
1784         RNA_def_property_ui_text(prop, "Percent", "Max persentage that will be selected");
1785         RNA_def_property_int_default(prop, 50);
1786 }
1787 /* ------------------------------------------------------------------------- */
1788
1789 /** The following functions are quick & dirty callback functions called
1790   * on the Circle select function (press B twice in Editmode)
1791   * They were torn out of the circle_select to make the latter more reusable
1792   * The callback version of circle_select (called circle_selectCB) was moved
1793   * to edit.c because of it's (wanted) generality.
1794
1795         XXX These callback functions are still dirty, because they call globals... 
1796   */
1797
1798 static void mesh_selectionCB__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1799 {
1800         struct { short select, mval[2]; float radius; } *data = userData;
1801         int mx = x - data->mval[0], my = y - data->mval[1];
1802         float r = sqrt(mx*mx + my*my);
1803
1804         if (r<=data->radius) {
1805                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1806         }
1807 }
1808 static void mesh_selectionCB__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1809 {
1810         struct { short select, mval[2]; float radius; } *data = userData;
1811
1812         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1813                 EM_select_edge(eed, data->select);
1814         }
1815 }
1816 static void mesh_selectionCB__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1817 {
1818         struct { short select, mval[2]; float radius; } *data = userData;
1819         int mx = x - data->mval[0], my = y - data->mval[1];
1820         float r = sqrt(mx*mx + my*my);
1821
1822         if (r<=data->radius) {
1823                 EM_select_face_fgon(efa, data->select);
1824         }
1825 }
1826
1827 static void mesh_selectionCB(Scene *scene, ARegion *ar, View3D *v3d, int selecting, Object *editobj, short *mval, float rad)
1828 {
1829         struct { short select, mval[2]; float radius; } data;
1830         EditMesh *em = G.editMesh;
1831         int bbsel;
1832
1833         if(!G.obedit && (FACESEL_PAINT_TEST)) {
1834                 Object *ob= OBACT;
1835                 Mesh *me = ob?ob->data:NULL;
1836
1837                 if (me) {
1838                         em_vertoffs= me->totface+1;     /* max index array */
1839
1840                         bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
1841                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1842                         EM_free_backbuf();
1843
1844 // XXX                  object_tface_flags_changed(OBACT, 0);
1845                 }
1846
1847                 return;
1848         }
1849
1850         bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
1851         
1852         data.select = (selecting==LEFTMOUSE);
1853         data.mval[0] = mval[0];
1854         data.mval[1] = mval[1];
1855         data.radius = rad;
1856
1857         if(scene->selectmode & SCE_SELECT_VERTEX) {
1858                 if(bbsel) {
1859                         EM_backbuf_checkAndSelectVerts(em, selecting==LEFTMOUSE);
1860                 } else {
1861                         mesh_foreachScreenVert(ar, v3d, mesh_selectionCB__doSelectVert, &data, 1);
1862                 }
1863         }
1864
1865         if(scene->selectmode & SCE_SELECT_EDGE) {
1866                 if (bbsel) {
1867                         EM_backbuf_checkAndSelectEdges(em, selecting==LEFTMOUSE);
1868                 } else {
1869                         mesh_foreachScreenEdge(ar, v3d, mesh_selectionCB__doSelectEdge, &data, 0);
1870                 }
1871         }
1872         
1873         if(scene->selectmode & SCE_SELECT_FACE) {
1874                 if(bbsel) {
1875                         EM_backbuf_checkAndSelectFaces(em, selecting==LEFTMOUSE);
1876                 } else {
1877                         mesh_foreachScreenFace(ar, v3d, mesh_selectionCB__doSelectFace, &data);
1878                 }
1879         }
1880
1881         EM_free_backbuf();
1882         EM_selectmode_flush();
1883 }
1884
1885
1886 static void nurbscurve_selectionCB__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1887 {
1888         struct { short select, mval[2]; float radius; } *data = userData;
1889         int mx = x - data->mval[0], my = y - data->mval[1];
1890         float r = sqrt(mx*mx + my*my);
1891
1892         if (r<=data->radius) {
1893                 if (bp) {
1894                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1895                 } else {
1896                         if (beztindex==0) {
1897                                 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1898                         } else if (beztindex==1) {
1899                                 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1900                         } else {
1901                                 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1902                         }
1903                 }
1904         }
1905 }
1906 static void nurbscurve_selectionCB(ARegion *ar, View3D *v3d, int selecting, Object *editobj, short *mval, float rad)
1907 {
1908         struct { short select, mval[2]; float radius; } data;
1909
1910         data.select = (selecting==LEFTMOUSE);
1911         data.mval[0] = mval[0];
1912         data.mval[1] = mval[1];
1913         data.radius = rad;
1914
1915         nurbs_foreachScreenVert(ar, v3d, nurbscurve_selectionCB__doSelect, &data);
1916 }
1917
1918
1919 static void latticecurve_selectionCB__doSelect(void *userData, BPoint *bp, int x, int y)
1920 {
1921         struct { short select, mval[2]; float radius; } *data = userData;
1922         int mx = x - data->mval[0], my = y - data->mval[1];
1923         float r = sqrt(mx*mx + my*my);
1924
1925         if (r<=data->radius) {
1926                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1927         }
1928 }
1929 static void lattice_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1930 {
1931         struct { short select, mval[2]; float radius; } data;
1932
1933         data.select = (selecting==LEFTMOUSE);
1934         data.mval[0] = mval[0];
1935         data.mval[1] = mval[1];
1936         data.radius = rad;
1937
1938         lattice_foreachScreenVert(latticecurve_selectionCB__doSelect, &data);
1939 }
1940
1941 /** Callbacks for selection in Editmode */
1942
1943 void obedit_selectionCB(Scene *scene, ARegion *ar, View3D *v3d, short selecting, Object *editobj, short *mval, float rad) 
1944 {
1945         switch(editobj->type) {         
1946         case OB_MESH:
1947                 mesh_selectionCB(scene, ar, v3d, selecting, editobj, mval, rad);
1948                 break;
1949         case OB_CURVE:
1950         case OB_SURF:
1951                 nurbscurve_selectionCB(ar, v3d, selecting, editobj, mval, rad);
1952                 break;
1953         case OB_LATTICE:
1954                 lattice_selectionCB(selecting, editobj, mval, rad);
1955                 break;
1956         default:
1957                 return;
1958         }
1959
1960 //      draw_sel_circle(0, 0, 0, 0, 0); /* signal */
1961 //      force_draw(0);
1962 }
1963
1964 static int view3d_circle_select(bContext *C, wmOperator *op)
1965 {
1966         ScrArea *sa= CTX_wm_area(C);
1967         ARegion *ar= CTX_wm_region(C);
1968         Scene *scene= CTX_data_scene(C);
1969         View3D *v3d= sa->spacedata.first;
1970         Base *base;
1971
1972         int x= RNA_int_get(op->ptr, "x");
1973         int y= RNA_int_get(op->ptr, "y");
1974         int radius= RNA_int_get(op->ptr, "radius");
1975         
1976         for(base= FIRSTBASE; base; base= base->next) {
1977                 if(base->lay & v3d->lay) {
1978                         project_short(ar, v3d, base->object->obmat[3], &base->sx);
1979                         if(base->sx!=IS_CLIPPED) {
1980                                 int dx= base->sx-x;
1981                                 int dy= base->sy-y;
1982                                 if( dx*dx + dy*dy < radius*radius)
1983                                 
1984                                         select_base_v3d(base, BA_SELECT);
1985                                 base->object->flag= base->flag;
1986                         }
1987                 }
1988         }
1989         return 0;
1990 }
1991
1992 void VIEW3D_OT_circle_select(wmOperatorType *ot)
1993 {
1994         ot->name= "Circle Select";
1995         ot->idname= "VIEW3D_OT_circle_select";
1996         
1997         ot->invoke= WM_gesture_circle_invoke;
1998         ot->modal= WM_gesture_circle_modal;
1999         ot->exec= view3d_circle_select;
2000         ot->poll= ED_operator_view3d_active;
2001         
2002         RNA_def_property(ot->srna, "x", PROP_INT, PROP_NONE);
2003         RNA_def_property(ot->srna, "y", PROP_INT, PROP_NONE);
2004         RNA_def_property(ot->srna, "radius", PROP_INT, PROP_NONE);
2005         
2006 }