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