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