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