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->v3d, 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->v3d, 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 /* mval is region coords */
839 static void mouse_select(bContext *C, short *mval, short modifier)
840 {
841         ViewContext vc;
842         ARegion *ar= CTX_wm_region(C);
843         View3D *v3d= (View3D *)CTX_wm_space_data(C);
844         Scene *scene= CTX_data_scene(C);
845         Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
846         unsigned int buffer[4*MAXPICKBUF];
847         int temp, a, dist=100;
848         short hits;
849         
850         /* setup view context for argument to callbacks */
851         memset(&vc, 0, sizeof(ViewContext));
852         vc.ar= ar;
853         vc.scene= scene;
854         vc.v3d= v3d;
855         vc.obact= OBACT;
856         
857         /* always start list from basact in wire mode */
858         startbase=  FIRSTBASE;
859         if(BASACT && BASACT->next) startbase= BASACT->next;
860         
861         /* This block uses the control key to make the object selected by its center point rather then its contents */
862         if(G.obedit==0 && modifier == KM_CTRL) {
863                 
864                 /* note; shift+alt goes to group-flush-selecting */
865                 if(modifier == KM_ALT && modifier == KM_CTRL) 
866                         basact= mouse_select_menu(&vc, NULL, 0, mval);
867                 else {
868                         base= startbase;
869                         while(base) {
870                                 if (BASE_SELECTABLE(v3d, base)) {
871                                         project_short(ar, v3d, base->object->obmat[3], &base->sx);
872                                         
873                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
874                                         if(base==BASACT) temp+=10;
875                                         if(temp<dist ) {
876                                                 
877                                                 dist= temp;
878                                                 basact= base;
879                                         }
880                                 }
881                                 base= base->next;
882                                 
883                                 if(base==0) base= FIRSTBASE;
884                                 if(base==startbase) break;
885                         }
886                 }
887         }
888         else {
889                 /* if objects have posemode set, the bones are in the same selection buffer */
890                 
891                 hits= mixed_bones_object_selectbuffer(&vc, buffer, mval);
892                 
893                 if(hits>0) {
894                         int has_bones= 0;
895                         
896                         for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
897
898                         /* note; shift+alt goes to group-flush-selecting */
899                         if(has_bones==0 && (modifier == KM_ALT)) 
900                                 basact= mouse_select_menu(&vc, buffer, hits, mval);
901                         else {
902                                 static short lastmval[2]={-100, -100};
903                                 int donearest= 0;
904                                 
905                                 /* define if we use solid nearest select or not */
906                                 if(v3d->drawtype>OB_WIRE) {
907                                         donearest= 1;
908                                         if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
909                                                 if(!has_bones)  /* hrms, if theres bones we always do nearest */
910                                                         donearest= 0;
911                                         }
912                                 }
913                                 lastmval[0]= mval[0]; lastmval[1]= mval[1];
914                                 
915                                 if(donearest) {
916                                         unsigned int min= 0xFFFFFFFF;
917                                         int selcol= 0, notcol=0;
918                                         
919
920                                         if(has_bones) {
921                                                 /* we skip non-bone hits */
922                                                 for(a=0; a<hits; a++) {
923                                                         if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
924                                                                 min= buffer[4*a+1];
925                                                                 selcol= buffer[4*a+3] & 0xFFFF;
926                                                         }
927                                                 }
928                                         }
929                                         else {
930                                                 /* only exclude active object when it is selected... */
931                                                 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol; 
932                                         
933                                                 for(a=0; a<hits; a++) {
934                                                         if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
935                                                                 min= buffer[4*a+1];
936                                                                 selcol= buffer[4*a+3] & 0xFFFF;
937                                                         }
938                                                 }
939                                         }
940
941                                         base= FIRSTBASE;
942                                         while(base) {
943                                                 if(base->lay & v3d->lay) {
944                                                         if(base->selcol==selcol) break;
945                                                 }
946                                                 base= base->next;
947                                         }
948                                         if(base) basact= base;
949                                 }
950                                 else {
951                                         
952                                         base= startbase;
953                                         while(base) {
954                                                 /* skip objects with select restriction, to prevent prematurely ending this loop
955                                                  * with an un-selectable choice */
956                                                 if (base->object->restrictflag & OB_RESTRICT_SELECT) {
957                                                         base=base->next;
958                                                         if(base==NULL) base= FIRSTBASE;
959                                                         if(base==startbase) break;
960                                                 }
961                                         
962                                                 if(base->lay & v3d->lay) {
963                                                         for(a=0; a<hits; a++) {
964                                                                 if(has_bones) {
965                                                                         /* skip non-bone objects */
966                                                                         if((buffer[4*a+3] & 0xFFFF0000)) {
967                                                                                 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
968                                                                                         basact= base;
969                                                                         }
970                                                                 }
971                                                                 else {
972                                                                         if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
973                                                                                 basact= base;
974                                                                 }
975                                                         }
976                                                 }
977                                                 
978                                                 if(basact) break;
979                                                 
980                                                 base= base->next;
981                                                 if(base==NULL) base= FIRSTBASE;
982                                                 if(base==startbase) break;
983                                         }
984                                 }
985                         }
986                         
987                         if(has_bones && basact) {
988                                 if(0) {// XXX do_pose_selectbuffer(basact, buffer, hits) ) {    /* then bone is found */
989                                 
990                                         /* we make the armature selected: 
991                                            not-selected active object in posemode won't work well for tools */
992                                         basact->flag|= SELECT;
993                                         basact->object->flag= basact->flag;
994                                         
995                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
996                                         if(G.f & G_WEIGHTPAINT) {
997                                                 /* prevent activating */
998                                                 basact= NULL;
999                                         }
1000                                         
1001                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, basact->object);
1002                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, basact->object);
1003
1004                                 }
1005                                 /* prevent bone selecting to pass on to object selecting */
1006                                 if(basact==BASACT)
1007                                         basact= NULL;
1008                         }
1009                 }
1010         }
1011         
1012         /* so, do we have something selected? */
1013         if(basact) {
1014                 
1015                 if(G.obedit) {
1016                         /* only do select */
1017                         deselectall_except(scene, basact);
1018                         ED_base_object_select(basact, BA_SELECT);
1019                 }
1020                 /* also prevent making it active on mouse selection */
1021                 else if (BASE_SELECTABLE(v3d, basact)) {
1022
1023                         oldbasact= BASACT;
1024                         BASACT= basact;
1025                         
1026                         if(modifier != KM_SHIFT) {
1027                                 deselectall_except(scene, basact);
1028                                 ED_base_object_select(basact, BA_SELECT);
1029                         }
1030                         else if(modifier == KM_CTRL && modifier == KM_ALT) {
1031                                 // XXX select_all_from_groups(basact);
1032                         }
1033                         else {
1034                                 if(basact->flag & SELECT) {
1035                                         if(basact==oldbasact)
1036                                                 ED_base_object_select(basact, BA_DESELECT);
1037                                 }
1038                                 else ED_base_object_select(basact, BA_SELECT);
1039                         }
1040
1041                         if(oldbasact != basact) {
1042                                 ED_base_object_activate(C, basact); /* adds notifier */
1043                         }
1044
1045                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1046                         
1047                 }
1048         }
1049
1050 }
1051
1052 /* ********************  border and circle ************************************** */
1053
1054
1055 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1056 {
1057         int radsq= rad*rad;
1058         float v1[2], v2[2], v3[2];
1059         
1060         /* check points in circle itself */
1061         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1062         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1063         
1064         /* pointdistline */
1065         v3[0]= centx;
1066         v3[1]= centy;
1067         v1[0]= x1;
1068         v1[1]= y1;
1069         v2[0]= x2;
1070         v2[1]= y2;
1071         
1072         if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1073         
1074         return 0;
1075 }
1076
1077 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1078 {
1079         struct { ViewContext vc; rcti *rect; int select; } *data = userData;
1080
1081         if (BLI_in_rcti(data->rect, x, y)) {
1082                 if (bp) {
1083                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1084                 } else {
1085                         if (G.f & G_HIDDENHANDLES) {
1086                                 /* can only be beztindex==0 here since handles are hidden */
1087                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1088                         } else {
1089                                 if (beztindex==0) {
1090                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1091                                 } else if (beztindex==1) {
1092                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1093                                 } else {
1094                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1095                                 }
1096                         }
1097                 }
1098         }
1099 }
1100 static void do_nurbs_box_select(ViewContext *vc, rcti *rect, int select)
1101 {
1102         struct { ViewContext vc; rcti *rect; int select; } data;
1103         
1104         data.vc= *vc;
1105         data.rect = rect;
1106         data.select = select;
1107
1108         nurbs_foreachScreenVert(vc, 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 { ViewContext vc; 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(ViewContext *vc, rcti *rect, int select)
1120 {
1121         struct { ViewContext vc; rcti *rect; int select, pass, done; } data;
1122
1123         data.vc= *vc;
1124         data.rect = rect;
1125         data.select = select;
1126
1127         lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data);
1128 }
1129
1130 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1131 {
1132         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1133
1134         if (BLI_in_rcti(data->rect, x, y)) {
1135                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1136         }
1137 }
1138 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1139 {
1140         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1141
1142         if(EM_check_backbuf(em_solidoffs+index)) {
1143                 if (data->pass==0) {
1144                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1145                                 EM_select_edge(eed, data->select);
1146                                 data->done = 1;
1147                         }
1148                 } else {
1149                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1150                                 EM_select_edge(eed, data->select);
1151                         }
1152                 }
1153         }
1154 }
1155 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1156 {
1157         struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
1158
1159         if (BLI_in_rcti(data->rect, x, y)) {
1160                 EM_select_face_fgon(data->vc.em, efa, data->select);
1161         }
1162 }
1163 static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select)
1164 {
1165         struct { ViewContext vc; rcti *rect; short select, pass, done; } data;
1166         int bbsel;
1167         
1168         data.vc= *vc;
1169         data.rect = rect;
1170         data.select = select;
1171         data.pass = 0;
1172         data.done = 0;
1173
1174         bbsel= EM_init_backbuf_border(vc->v3d, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1175
1176         if(vc->scene->selectmode & SCE_SELECT_VERTEX) {
1177                 if (bbsel) {
1178                         EM_backbuf_checkAndSelectVerts(vc->em, select);
1179                 } else {
1180                         mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1);
1181                 }
1182         }
1183         if(vc->scene->selectmode & SCE_SELECT_EDGE) {
1184                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1185
1186                 data.pass = 0;
1187                 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1188
1189                 if (data.done==0) {
1190                         data.pass = 1;
1191                         mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0);
1192                 }
1193         }
1194         
1195         if(vc->scene->selectmode & SCE_SELECT_FACE) {
1196                 if(bbsel) {
1197                         EM_backbuf_checkAndSelectFaces(vc->em, select);
1198                 } else {
1199                         mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data);
1200                 }
1201         }
1202         
1203         EM_free_backbuf();
1204                 
1205         EM_selectmode_flush(vc->em);
1206 }
1207
1208 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
1209 {
1210         ViewContext vc;
1211         Scene *scene= CTX_data_scene(C);
1212         ScrArea *sa= CTX_wm_area(C);
1213         ARegion *ar= CTX_wm_region(C);
1214         View3D *v3d= sa->spacedata.first;
1215         rcti rect;
1216         Base *base;
1217         MetaElem *ml;
1218         unsigned int buffer[4*MAXPICKBUF];
1219         int a, index;
1220         short hits, val;
1221
1222         /* setup view context for argument to callbacks */
1223         memset(&vc, 0, sizeof(ViewContext));
1224         vc.ar= ar;
1225         vc.scene= scene;
1226         vc.v3d= v3d;
1227         vc.obact= OBACT;
1228         
1229         
1230         val= RNA_int_get(op->ptr, "event_type");
1231         rect.xmin= RNA_int_get(op->ptr, "xmin");
1232         rect.ymin= RNA_int_get(op->ptr, "ymin");
1233         rect.xmax= RNA_int_get(op->ptr, "xmax");
1234         rect.ymax= RNA_int_get(op->ptr, "ymax");
1235         
1236         if(G.obedit==NULL && (FACESEL_PAINT_TEST)) {
1237 // XXX          face_borderselect();
1238                 return OPERATOR_FINISHED;
1239         }
1240         else if(G.obedit==NULL && (G.f & G_PARTICLEEDIT)) {
1241 // XXX          PE_borderselect();
1242                 return OPERATOR_FINISHED;
1243         }
1244         
1245         if(G.obedit) {
1246                 if(G.obedit->type==OB_MESH) {
1247                         do_mesh_box_select(&vc, &rect, (val==LEFTMOUSE));
1248 //                      allqueue(REDRAWVIEW3D, 0);
1249 //                      if (EM_texFaceCheck())
1250 //                              allqueue(REDRAWIMAGE, 0);
1251                         
1252                 }
1253                 else if(ELEM(G.obedit->type, OB_CURVE, OB_SURF)) {
1254                         do_nurbs_box_select(&vc, &rect, val==LEFTMOUSE);
1255 //                      allqueue(REDRAWVIEW3D, 0);
1256                 }
1257                 else if(G.obedit->type==OB_MBALL) {
1258                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1259                         
1260                         ml= NULL; // XXX editelems.first;
1261                         
1262                         while(ml) {
1263                                 for(a=0; a<hits; a++) {
1264                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1265                                                 ml->flag |= MB_SCALE_RAD;
1266                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1267                                                 else ml->flag &= ~SELECT;
1268                                                 break;
1269                                         }
1270                                         if(ml->selcol2==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                                 }
1277                                 ml= ml->next;
1278                         }
1279                 }
1280                 else if(G.obedit->type==OB_ARMATURE) {
1281                         EditBone *ebone;
1282                         
1283                         /* clear flag we use to detect point was affected */
1284                         for(ebone= G.edbo.first; ebone; ebone= ebone->next)
1285                                 ebone->flag &= ~BONE_DONE;
1286                         
1287                         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
1288                         
1289                         /* first we only check points inside the border */
1290                         for (a=0; a<hits; a++){
1291                                 index = buffer[(4*a)+3];
1292                                 if (index!=-1) {
1293                                         ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1294                                         if (index & BONESEL_TIP) {
1295                                                 ebone->flag |= BONE_DONE;
1296                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
1297                                                 else ebone->flag &= ~BONE_TIPSEL;
1298                                         }
1299                                         
1300                                         if (index & BONESEL_ROOT) {
1301                                                 ebone->flag |= BONE_DONE;
1302                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
1303                                                 else ebone->flag &= ~BONE_ROOTSEL;
1304                                         }
1305                                 }
1306                         }
1307                         
1308                         /* now we have to flush tag from parents... */
1309                         for(ebone= G.edbo.first; ebone; ebone= ebone->next) {
1310                                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1311                                         if(ebone->parent->flag & BONE_DONE)
1312                                                 ebone->flag |= BONE_DONE;
1313                                 }
1314                         }
1315                         
1316                         /* only select/deselect entire bones when no points where in the rect */
1317                         for (a=0; a<hits; a++){
1318                                 index = buffer[(4*a)+3];
1319                                 if (index!=-1) {
1320                                         ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1321                                         if (index & BONESEL_BONE) {
1322                                                 if(!(ebone->flag & BONE_DONE)) {
1323                                                         if (val==LEFTMOUSE)
1324                                                                 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1325                                                         else
1326                                                                 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1327                                                 }
1328                                         }
1329                                 }
1330                         }
1331                         
1332                 }
1333                 else if(G.obedit->type==OB_LATTICE) {
1334                         do_lattice_box_select(&vc, &rect, val==LEFTMOUSE);
1335                 }
1336         }
1337         else {  /* no editmode, unified for bones and objects */
1338                 Bone *bone;
1339                 unsigned int *vbuffer=NULL; /* selection buffer */
1340                 unsigned int *col;                      /* color in buffer      */
1341                 short selecting = 0;
1342                 Object *ob= OBACT;
1343                 int bone_only;
1344                 
1345                 if((ob) && (ob->flag & OB_POSEMODE))
1346                         bone_only= 1;
1347                 else
1348                         bone_only= 0;
1349                 
1350                 if (val==LEFTMOUSE)
1351                         selecting = 1;
1352                 
1353                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1354                 vbuffer = MEM_mallocN(4 * (G.totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1355                 hits= view3d_opengl_select(&vc, vbuffer, 4*(G.totobj+MAXPICKBUF), &rect);
1356                 /*
1357                 LOGIC NOTES (theeth):
1358                 The buffer and ListBase have the same relative order, which makes the selection
1359                 very simple. Loop through both data sets at the same time, if the color
1360                 is the same as the object, we have a hit and can move to the next color
1361                 and object pair, if not, just move to the next object,
1362                 keeping the same color until we have a hit.
1363
1364                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1365                 does it incorrectly.
1366                 */
1367
1368                 if (hits>0) { /* no need to loop if there's no hit */
1369                         base= FIRSTBASE;
1370                         col = vbuffer + 3;
1371                         
1372                         while(base && hits) {
1373                                 Base *next = base->next;
1374                                 if(base->lay & v3d->lay) {
1375                                         while (base->selcol == (*col & 0xFFFF)) {       /* we got an object */
1376                                                 
1377                                                 if(*col & 0xFFFF0000) {                                 /* we got a bone */
1378                                                         bone = NULL; // XXX get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1379                                                         if(bone) {
1380                                                                 if(selecting) {
1381                                                                         bone->flag |= BONE_SELECTED;
1382 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 1);
1383                                                                 }
1384                                                                 else {
1385                                                                         bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1386 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 0);
1387                                                                 }
1388                                                         }
1389                                                 }
1390                                                 else if(!bone_only) {
1391                                                         if (selecting)
1392                                                                 ED_base_object_select(base, BA_SELECT);
1393                                                         else
1394                                                                 ED_base_object_select(base, BA_DESELECT);
1395                                                 }
1396
1397                                                 col+=4; /* next color */
1398                                                 hits--;
1399                                                 if(hits==0) break;
1400                                         }
1401                                 }
1402                                 
1403                                 base= next;
1404                         }
1405
1406                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1407
1408                 }
1409                 MEM_freeN(vbuffer);
1410         }
1411
1412         BIF_undo_push("Border select");
1413         
1414         return OPERATOR_FINISHED;
1415
1416
1417
1418 /* *****************Selection Operators******************* */
1419
1420 /* ****** Border Select ****** */
1421 void VIEW3D_OT_borderselect(wmOperatorType *ot)
1422 {
1423         
1424         /* identifiers */
1425         ot->name= "Border Select";
1426         ot->idname= "VIEW3D_OT_borderselect";
1427         
1428         /* api callbacks */
1429         ot->invoke= WM_border_select_invoke;
1430         ot->exec= view3d_borderselect_exec;
1431         ot->modal= WM_border_select_modal;
1432         
1433         ot->poll= ED_operator_view3d_active;
1434         
1435         /* rna */
1436         RNA_def_property(ot->srna, "event_type", PROP_INT, PROP_NONE);
1437         RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
1438         RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
1439         RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
1440         RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
1441 }
1442
1443 /* ****** Mouse Select ****** */
1444
1445 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1446 {
1447         ARegion *ar= CTX_wm_region(C);
1448         short mval[2];  
1449         
1450         mval[0]= event->x - ar->winrct.xmin;
1451         mval[1]= event->y - ar->winrct.ymin;
1452
1453         view3d_operator_needs_opengl(C);
1454         
1455         mouse_select(C, mval, 0);
1456         
1457         return OPERATOR_FINISHED;
1458 }
1459
1460 void VIEW3D_OT_select(wmOperatorType *ot)
1461 {
1462
1463         /* identifiers */
1464         ot->name= "Activate/Select";
1465         ot->idname= "VIEW3D_OT_select";
1466         
1467         /* api callbacks */
1468         ot->invoke= view3d_select_invoke;
1469         ot->poll= ED_operator_view3d_active;
1470
1471 }
1472 static EnumPropertyItem prop_select_extend_types[] = {
1473         {KM_SHIFT, "SHIFT", "Shift", ""},
1474         {KM_CTRL, "CTRL", "Ctrl", ""},
1475         {KM_ALT, "ALT", "Alt", ""},
1476         {0, NULL, NULL, NULL}
1477 };
1478
1479 static int view3d_select_extend_invoke(bContext *C, wmOperator *op, wmEvent *event)
1480 {
1481         ARegion *ar= CTX_wm_region(C);
1482         short mval[2], modifier;        
1483         
1484         mval[0]= event->x - ar->winrct.xmin;
1485         mval[1]= event->y - ar->winrct.ymin;
1486
1487         modifier = RNA_enum_get(op->ptr, "modifier");
1488         
1489         view3d_operator_needs_opengl(C);        
1490         
1491         mouse_select(C, mval, modifier);
1492         
1493         return OPERATOR_FINISHED;
1494 }
1495
1496 void VIEW3D_OT_select_extend(wmOperatorType *ot)
1497 {
1498         PropertyRNA *prop;
1499         
1500         /* identifiers */
1501         ot->name= "Activate/Select Extend";
1502         ot->idname= "VIEW3D_OT_select_extend";
1503         
1504         /* api callbacks */
1505         ot->invoke= view3d_select_extend_invoke;
1506         ot->poll= ED_operator_view3d_active;    
1507         
1508         prop = RNA_def_property(ot->srna, "modifier", PROP_ENUM, PROP_NONE);
1509         RNA_def_property_enum_items(prop, prop_select_extend_types);
1510
1511 }
1512
1513
1514 /* ------------------------------------------------------------------------- */
1515
1516 /** The following functions are quick & dirty callback functions called
1517   * on the Circle select function (press B twice in Editmode)
1518   * They were torn out of the circle_select to make the latter more reusable
1519   * The callback version of circle_select (called circle_selectCB) was moved
1520   * to edit.c because of it's (wanted) generality.
1521
1522         XXX These callback functions are still dirty, because they call globals... 
1523   */
1524
1525 static void mesh_selectionCB__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1526 {
1527         struct { short select, mval[2]; float radius; } *data = userData;
1528         int mx = x - data->mval[0], my = y - data->mval[1];
1529         float r = sqrt(mx*mx + my*my);
1530
1531         if (r<=data->radius) {
1532                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1533         }
1534 }
1535 static void mesh_selectionCB__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1536 {
1537         struct { short select, mval[2]; float radius; } *data = userData;
1538
1539         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1540                 EM_select_edge(eed, data->select);
1541         }
1542 }
1543 static void mesh_selectionCB__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1544 {
1545         struct { short select, mval[2]; float radius; } *data = userData;
1546         int mx = x - data->mval[0], my = y - data->mval[1];
1547         float r = sqrt(mx*mx + my*my);
1548         EditMesh *em= NULL; // XXX
1549         
1550         if (r<=data->radius) {
1551                 EM_select_face_fgon(em, efa, data->select);
1552         }
1553 }
1554
1555 static void mesh_selectionCB(ViewContext *vc, int selecting, Object *editobj, short *mval, float rad)
1556 {
1557         struct { short select, mval[2]; float radius; } data;
1558         int bbsel;
1559
1560         if(!G.obedit && (FACESEL_PAINT_TEST)) {
1561                 Object *ob= vc->obact;
1562                 Mesh *me = ob?ob->data:NULL;
1563
1564                 if (me) {
1565                         em_vertoffs= me->totface+1;     /* max index array */
1566
1567                         bbsel= EM_init_backbuf_circle(vc->v3d, mval[0], mval[1], (short)(rad+1.0));
1568                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1569                         EM_free_backbuf();
1570
1571 // XXX                  object_tface_flags_changed(OBACT, 0);
1572                 }
1573
1574                 return;
1575         }
1576
1577         bbsel= EM_init_backbuf_circle(vc->v3d, mval[0], mval[1], (short)(rad+1.0));
1578         
1579         data.select = (selecting==LEFTMOUSE);
1580         data.mval[0] = mval[0];
1581         data.mval[1] = mval[1];
1582         data.radius = rad;
1583
1584         if(vc->scene->selectmode & SCE_SELECT_VERTEX) {
1585                 if(bbsel) {
1586                         EM_backbuf_checkAndSelectVerts(vc->em, selecting==LEFTMOUSE);
1587                 } else {
1588                         mesh_foreachScreenVert(vc, mesh_selectionCB__doSelectVert, &data, 1);
1589                 }
1590         }
1591
1592         if(vc->scene->selectmode & SCE_SELECT_EDGE) {
1593                 if (bbsel) {
1594                         EM_backbuf_checkAndSelectEdges(vc->em, selecting==LEFTMOUSE);
1595                 } else {
1596                         mesh_foreachScreenEdge(vc, mesh_selectionCB__doSelectEdge, &data, 0);
1597                 }
1598         }
1599         
1600         if(vc->scene->selectmode & SCE_SELECT_FACE) {
1601                 if(bbsel) {
1602                         EM_backbuf_checkAndSelectFaces(vc->em, selecting==LEFTMOUSE);
1603                 } else {
1604                         mesh_foreachScreenFace(vc, mesh_selectionCB__doSelectFace, &data);
1605                 }
1606         }
1607
1608         EM_free_backbuf();
1609         EM_selectmode_flush(vc->em);
1610 }
1611
1612
1613 static void nurbscurve_selectionCB__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1614 {
1615         struct { short select, mval[2]; float radius; } *data = userData;
1616         int mx = x - data->mval[0], my = y - data->mval[1];
1617         float r = sqrt(mx*mx + my*my);
1618
1619         if (r<=data->radius) {
1620                 if (bp) {
1621                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1622                 } else {
1623                         if (beztindex==0) {
1624                                 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1625                         } else if (beztindex==1) {
1626                                 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1627                         } else {
1628                                 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1629                         }
1630                 }
1631         }
1632 }
1633 static void nurbscurve_selectionCB(ViewContext *vc, int selecting, Object *editobj, short *mval, float rad)
1634 {
1635         struct { short select, mval[2]; float radius; } data;
1636
1637         data.select = (selecting==LEFTMOUSE);
1638         data.mval[0] = mval[0];
1639         data.mval[1] = mval[1];
1640         data.radius = rad;
1641
1642         nurbs_foreachScreenVert(vc, nurbscurve_selectionCB__doSelect, &data);
1643 }
1644
1645
1646 static void latticecurve_selectionCB__doSelect(void *userData, BPoint *bp, int x, int y)
1647 {
1648         struct { short select, mval[2]; float radius; } *data = userData;
1649         int mx = x - data->mval[0], my = y - data->mval[1];
1650         float r = sqrt(mx*mx + my*my);
1651
1652         if (r<=data->radius) {
1653                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1654         }
1655 }
1656 static void lattice_selectionCB(ViewContext *vc, int selecting, Object *editobj, short *mval, float rad)
1657 {
1658         struct { short select, mval[2]; float radius; } data;
1659
1660         data.select = (selecting==LEFTMOUSE);
1661         data.mval[0] = mval[0];
1662         data.mval[1] = mval[1];
1663         data.radius = rad;
1664
1665         lattice_foreachScreenVert(vc, latticecurve_selectionCB__doSelect, &data);
1666 }
1667
1668 /** Callbacks for selection in Editmode */
1669
1670 void obedit_selectionCB(ViewContext *vc, short selecting, Object *editobj, short *mval, float rad) 
1671 {
1672         switch(editobj->type) {         
1673         case OB_MESH:
1674                 mesh_selectionCB(vc, selecting, editobj, mval, rad);
1675                 break;
1676         case OB_CURVE:
1677         case OB_SURF:
1678                 nurbscurve_selectionCB(vc, selecting, editobj, mval, rad);
1679                 break;
1680         case OB_LATTICE:
1681                 lattice_selectionCB(vc, selecting, editobj, mval, rad);
1682                 break;
1683         default:
1684                 return;
1685         }
1686
1687 //      draw_sel_circle(0, 0, 0, 0, 0); /* signal */
1688 //      force_draw(0);
1689 }
1690
1691 /* not a real operator, only for circle test */
1692 static int view3d_circle_select(bContext *C, wmOperator *op)
1693 {
1694         ScrArea *sa= CTX_wm_area(C);
1695         ARegion *ar= CTX_wm_region(C);
1696         Scene *scene= CTX_data_scene(C);
1697         View3D *v3d= sa->spacedata.first;
1698         Base *base;
1699
1700         int x= RNA_int_get(op->ptr, "x");
1701         int y= RNA_int_get(op->ptr, "y");
1702         int radius= RNA_int_get(op->ptr, "radius");
1703         
1704         for(base= FIRSTBASE; base; base= base->next) {
1705                 if(base->lay & v3d->lay) {
1706                         project_short(ar, v3d, base->object->obmat[3], &base->sx);
1707                         if(base->sx!=IS_CLIPPED) {
1708                                 int dx= base->sx-x;
1709                                 int dy= base->sy-y;
1710                                 if( dx*dx + dy*dy < radius*radius)
1711                                         ED_base_object_select(base, BA_SELECT);
1712                         }
1713                 }
1714         }
1715         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1716         return 0;
1717 }
1718
1719 void VIEW3D_OT_circle_select(wmOperatorType *ot)
1720 {
1721         ot->name= "Circle Select";
1722         ot->idname= "VIEW3D_OT_circle_select";
1723         
1724         ot->invoke= WM_gesture_circle_invoke;
1725         ot->modal= WM_gesture_circle_modal;
1726         ot->exec= view3d_circle_select;
1727         ot->poll= ED_operator_view3d_active;
1728         
1729         RNA_def_property(ot->srna, "x", PROP_INT, PROP_NONE);
1730         RNA_def_property(ot->srna, "y", PROP_INT, PROP_NONE);
1731         RNA_def_property(ot->srna, "radius", PROP_INT, PROP_NONE);
1732         
1733 }