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