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