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