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