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