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