Code Cleanup:
[blender.git] / source / blender / editors / space_view3d / view3d_select.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  * 
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_view3d/view3d_select.c
28  *  \ingroup spview3d
29  */
30
31
32 #include <string.h>
33 #include <stdio.h>
34 #include <math.h>
35 #include <float.h>
36 #include <assert.h>
37
38 #include "DNA_action_types.h"
39 #include "DNA_armature_types.h"
40 #include "DNA_curve_types.h"
41 #include "DNA_meta_types.h"
42 #include "DNA_mesh_types.h"
43 #include "DNA_meshdata_types.h"
44 #include "DNA_object_types.h"
45 #include "DNA_scene_types.h"
46 #include "DNA_tracking_types.h"
47
48 #include "MEM_guardedalloc.h"
49
50 #include "BLI_math.h"
51 #include "BLI_blenlib.h"
52 #include "BLI_rand.h"
53 #include "BLI_linklist.h"
54 #include "BLI_utildefines.h"
55
56 /* vertex box select */
57 #include "IMB_imbuf_types.h"
58 #include "IMB_imbuf.h"
59 #include "BKE_global.h"
60
61 #include "BKE_context.h"
62 #include "BKE_paint.h"
63 #include "BKE_armature.h"
64 #include "BKE_tessmesh.h"
65 #include "BKE_movieclip.h"
66 #include "BKE_object.h"
67 #include "BKE_tracking.h"
68
69
70 #include "BIF_gl.h"
71 #include "BIF_glutil.h"
72
73 #include "WM_api.h"
74 #include "WM_types.h"
75
76 #include "RNA_access.h"
77 #include "RNA_define.h"
78 #include "RNA_enum_types.h"
79
80 #include "ED_armature.h"
81 #include "ED_curve.h"
82 #include "ED_particle.h"
83 #include "ED_mesh.h"
84 #include "ED_object.h"
85 #include "ED_screen.h"
86 #include "ED_mball.h"
87
88 #include "UI_interface.h"
89 #include "UI_resources.h"
90
91 #include "view3d_intern.h"      // own include
92
93 // TODO: should return whether there is valid context to continue
94 void view3d_set_viewcontext(bContext *C, ViewContext *vc)
95 {
96         memset(vc, 0, sizeof(ViewContext));
97         vc->ar= CTX_wm_region(C);
98         vc->scene= CTX_data_scene(C);
99         vc->v3d= CTX_wm_view3d(C);
100         vc->rv3d= CTX_wm_region_view3d(C);
101         vc->obact= CTX_data_active_object(C);
102         vc->obedit= CTX_data_edit_object(C); 
103 }
104
105 int view3d_get_view_aligned_coordinate(ViewContext *vc, float fp[3], const int mval[2], const short do_fallback)
106 {
107         float dvec[3];
108         int mval_cpy[2];
109
110         mval_cpy[0]= mval[0];
111         mval_cpy[1]= mval[1];
112
113         project_int_noclip(vc->ar, fp, mval_cpy);
114
115         initgrabz(vc->rv3d, fp[0], fp[1], fp[2]);
116
117         if (mval_cpy[0]!=IS_CLIPPED) {
118                 float mval_f[2];
119                 VECSUB2D(mval_f, mval_cpy, mval);
120                 ED_view3d_win_to_delta(vc->ar, mval_f, dvec);
121                 sub_v3_v3(fp, dvec);
122
123                 return TRUE;
124         }
125         else {
126                 /* fallback to the view center */
127                 if (do_fallback) {
128                         negate_v3_v3(fp, vc->rv3d->ofs);
129                         return view3d_get_view_aligned_coordinate(vc, fp, mval, FALSE);
130                 }
131                 else {
132                         return FALSE;
133                 }
134         }
135 }
136
137 /*
138  * ob == NULL if you want global matrices
139  * */
140 void view3d_get_transformation(const ARegion *ar, RegionView3D *rv3d, Object *ob, bglMats *mats)
141 {
142         float cpy[4][4];
143         int i, j;
144
145         if (ob) {
146                 mult_m4_m4m4(cpy, rv3d->viewmat, ob->obmat);
147         }
148         else {
149                 copy_m4_m4(cpy, rv3d->viewmat);
150         }
151
152         for (i = 0; i < 4; ++i) {
153                 for (j = 0; j < 4; ++j) {
154                         mats->projection[i*4+j] = rv3d->winmat[i][j];
155                         mats->modelview[i*4+j] = cpy[i][j];
156                 }
157         }
158
159         mats->viewport[0] = ar->winrct.xmin;
160         mats->viewport[1] = ar->winrct.ymin;
161         mats->viewport[2] = ar->winx;
162         mats->viewport[3] = ar->winy;   
163 }
164
165 /* ********************** view3d_select: selection manipulations ********************* */
166
167 /* local prototypes */
168
169 static void EDBM_backbuf_checkAndSelectVerts(BMEditMesh *em, int select)
170 {
171         BMVert *eve;
172         BMIter iter;
173         int index= bm_wireoffs;
174
175         eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
176         for ( ; eve; eve=BM_iter_step(&iter), index++) {
177                 if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
178                         if (EDBM_check_backbuf(index)) {
179                                 BM_vert_select_set(em->bm, eve, select);
180                         }
181                 }
182         }
183 }
184
185 static void EDBM_backbuf_checkAndSelectEdges(BMEditMesh *em, int select)
186 {
187         BMEdge *eed;
188         BMIter iter;
189         int index= bm_solidoffs;
190
191         eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
192         for ( ; eed; eed=BM_iter_step(&iter), index++) {
193                 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
194                         if (EDBM_check_backbuf(index)) {
195                                 BM_edge_select_set(em->bm, eed, select);
196                         }
197                 }
198         }
199 }
200
201 static void EDBM_backbuf_checkAndSelectFaces(BMEditMesh *em, int select)
202 {
203         BMFace *efa;
204         BMIter iter;
205         int index= 1;
206
207         efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL);
208         for ( ; efa; efa=BM_iter_step(&iter), index++) {
209                 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
210                         if (EDBM_check_backbuf(index)) {
211                                 BM_face_select_set(em->bm, efa, select);
212                         }
213                 }
214         }
215 }
216
217
218 /* object mode, EM_ prefix is confusing here, rename? */
219 static void EDBM_backbuf_checkAndSelectVerts_obmode(Mesh *me, int select)
220 {
221         MVert *mv = me->mvert;
222         int a;
223
224         if (mv) {
225                 for (a=1; a<=me->totvert; a++, mv++) {
226                         if (EDBM_check_backbuf(a)) {
227                                 if (!(mv->flag & ME_HIDE)) {
228                                         mv->flag = select?(mv->flag|SELECT):(mv->flag&~SELECT);
229                                 }
230                         }
231                 }
232         }
233 }
234 /* object mode, EM_ prefix is confusing here, rename? */
235
236 static void EDBM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
237 {
238         MPoly *mpoly = me->mpoly;
239         int a;
240
241         if (mpoly) {
242                 for (a=1; a<=me->totpoly; a++, mpoly++) {
243                         if (EDBM_check_backbuf(a)) {
244                                 mpoly->flag = select?(mpoly->flag|ME_FACE_SEL):(mpoly->flag&~ME_FACE_SEL);
245                         }
246                 }
247         }
248 }
249
250 /* *********************** GESTURE AND LASSO ******************* */
251
252 typedef struct LassoSelectUserData {
253         ViewContext *vc;
254         rcti *rect;
255         int (*mcords)[2], moves, select, pass, done;
256 } LassoSelectUserData;
257
258 static int view3d_selectable_data(bContext *C)
259 {
260         Object *ob = CTX_data_active_object(C);
261
262         if (!ED_operator_region_view3d_active(C))
263                 return 0;
264
265         if (ob) {
266                 if (ob->mode & OB_MODE_EDIT) {
267                         if (ob->type == OB_FONT) {
268                                 return 0;
269                         }
270                 }
271                 else {
272                         if (ob->mode & OB_MODE_SCULPT) {
273                                 return 0;
274                         }
275                         if ((ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT)) &&
276                             !paint_facesel_test(ob) && !paint_vertsel_test(ob))
277                         {
278                                 return 0;
279                         }
280                 }
281         }
282
283         return 1;
284 }
285
286
287 /* helper also for borderselect */
288 static int edge_fully_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
289 {
290         return BLI_in_rcti(rect, x1, y1) && BLI_in_rcti(rect, x2, y2);
291 }
292
293 static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
294 {
295         int d1, d2, d3, d4;
296         
297         /* check points in rect */
298         if (edge_fully_inside_rect(rect, x1, y1, x2, y2)) return 1;
299         
300         /* check points completely out rect */
301         if (x1<rect->xmin && x2<rect->xmin) return 0;
302         if (x1>rect->xmax && x2>rect->xmax) return 0;
303         if (y1<rect->ymin && y2<rect->ymin) return 0;
304         if (y1>rect->ymax && y2>rect->ymax) return 0;
305         
306         /* simple check lines intersecting. */
307         d1= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymin );
308         d2= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymax );
309         d3= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymax );
310         d4= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymin );
311         
312         if (d1<0 && d2<0 && d3<0 && d4<0) return 0;
313         if (d1>0 && d2>0 && d3>0 && d4>0) return 0;
314         
315         return 1;
316 }
317
318
319 #define MOVES_GESTURE 50
320 #define MOVES_LASSO 500
321
322 int lasso_inside(int mcords[][2], short moves, int sx, int sy)
323 {
324         /* we do the angle rule, define that all added angles should be about zero or 2*PI */
325         float angletot=0.0, len, dot, ang, cross, fp1[2], fp2[2];
326         int a;
327         int *p1, *p2;
328         
329         if (sx==IS_CLIPPED)
330                 return 0;
331         
332         p1= mcords[moves-1];
333         p2= mcords[0];
334         
335         /* first vector */
336         fp1[0]= (float)(p1[0]-sx);
337         fp1[1]= (float)(p1[1]-sy);
338         len= sqrt(fp1[0]*fp1[0] + fp1[1]*fp1[1]);
339         fp1[0]/= len;
340         fp1[1]/= len;
341         
342         for (a=0; a<moves; a++) {
343                 /* second vector */
344                 fp2[0]= (float)(p2[0]-sx);
345                 fp2[1]= (float)(p2[1]-sy);
346                 len= sqrt(fp2[0]*fp2[0] + fp2[1]*fp2[1]);
347                 fp2[0]/= len;
348                 fp2[1]/= len;
349                 
350                 /* dot and angle and cross */
351                 dot= fp1[0]*fp2[0] + fp1[1]*fp2[1];
352                 ang= fabs(saacos(dot));
353
354                 cross= (float)((p1[1]-p2[1])*(p1[0]-sx) + (p2[0]-p1[0])*(p1[1]-sy));
355                 
356                 if (cross<0.0f) angletot-= ang;
357                 else angletot+= ang;
358                 
359                 /* circulate */
360                 fp1[0]= fp2[0]; fp1[1]= fp2[1];
361                 p1= p2;
362                 p2= mcords[a+1];
363         }
364         
365         if ( fabs(angletot) > 4.0 ) return 1;
366         return 0;
367 }
368
369 /* edge version for lasso select. we assume boundbox check was done */
370 int lasso_inside_edge(int mcords[][2], short moves, int x0, int y0, int x1, int y1)
371 {
372         int v1[2], v2[2];
373         int a;
374
375         if (x0==IS_CLIPPED || x1==IS_CLIPPED)
376                 return 0;
377         
378         v1[0] = x0, v1[1] = y0;
379         v2[0] = x1, v2[1] = y1;
380
381         /* check points in lasso */
382         if (lasso_inside(mcords, moves, v1[0], v1[1])) return 1;
383         if (lasso_inside(mcords, moves, v2[0], v2[1])) return 1;
384         
385         /* no points in lasso, so we have to intersect with lasso edge */
386         
387         if ( isect_line_line_v2_int(mcords[0], mcords[moves-1], v1, v2) > 0) return 1;
388         for (a=0; a<moves-1; a++) {
389                 if ( isect_line_line_v2_int(mcords[a], mcords[a+1], v1, v2) > 0) return 1;
390         }
391         
392         return 0;
393 }
394
395
396 /* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN) 
397    and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK
398 */
399 static void do_lasso_select_pose(ViewContext *vc, Object *ob, int mcords[][2], short moves, short select)
400 {
401         bPoseChannel *pchan;
402         float vec[3];
403         int sco1[2], sco2[2];
404         bArmature *arm= ob->data;
405         
406         if (ob->type!=OB_ARMATURE || ob->pose==NULL) return;
407
408         for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
409                 if (PBONE_VISIBLE(arm, pchan->bone) && (pchan->bone->flag & BONE_UNSELECTABLE)==0) {
410                         mul_v3_m4v3(vec, ob->obmat, pchan->pose_head);
411                         project_int(vc->ar, vec, sco1);
412                         mul_v3_m4v3(vec, ob->obmat, pchan->pose_tail);
413                         project_int(vc->ar, vec, sco2);
414                         
415                         if (lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
416                                 if (select) pchan->bone->flag |= BONE_SELECTED;
417                                 else pchan->bone->flag &= ~BONE_SELECTED;
418                         }
419                 }
420         }
421 }
422
423 static void object_deselect_all_visible(Scene *scene, View3D *v3d)
424 {
425         Base *base;
426
427         for (base= scene->base.first; base; base= base->next) {
428                 if (BASE_SELECTABLE(v3d, base)) {
429                         ED_base_object_select(base, BA_DESELECT);
430                 }
431         }
432 }
433
434 static void do_lasso_select_objects(ViewContext *vc, int mcords[][2], short moves, short extend, short select)
435 {
436         Base *base;
437         
438         if (extend == 0 && select)
439                 object_deselect_all_visible(vc->scene, vc->v3d);
440
441         for (base= vc->scene->base.first; base; base= base->next) {
442                 if (BASE_SELECTABLE(vc->v3d, base)) { /* use this to avoid un-needed lasso lookups */
443                         project_short(vc->ar, base->object->obmat[3], &base->sx);
444                         if (lasso_inside(mcords, moves, base->sx, base->sy)) {
445                                 
446                                 if (select) ED_base_object_select(base, BA_SELECT);
447                                 else ED_base_object_select(base, BA_DESELECT);
448                                 base->object->flag= base->flag;
449                         }
450                         if (base->object->mode & OB_MODE_POSE) {
451                                 do_lasso_select_pose(vc, base->object, mcords, moves, select);
452                         }
453                 }
454         }
455 }
456
457 static void lasso_select_boundbox(rcti *rect, int mcords[][2], short moves)
458 {
459         short a;
460         
461         rect->xmin= rect->xmax= mcords[0][0];
462         rect->ymin= rect->ymax= mcords[0][1];
463         
464         for (a=1; a<moves; a++) {
465                 if (mcords[a][0]<rect->xmin) rect->xmin= mcords[a][0];
466                 else if (mcords[a][0]>rect->xmax) rect->xmax= mcords[a][0];
467                 if (mcords[a][1]<rect->ymin) rect->ymin= mcords[a][1];
468                 else if (mcords[a][1]>rect->ymax) rect->ymax= mcords[a][1];
469         }
470 }
471
472 static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, int x, int y, int UNUSED(index))
473 {
474         LassoSelectUserData *data = userData;
475
476         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
477                 BM_elem_select_set(data->vc->em->bm, eve, data->select);
478         }
479 }
480 static void do_lasso_select_mesh__doSelectEdge(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index)
481 {
482         LassoSelectUserData *data = userData;
483
484         if (EDBM_check_backbuf(bm_solidoffs+index)) {
485                 if (data->pass==0) {
486                         if (    edge_fully_inside_rect(data->rect, x0, y0, x1, y1)  &&
487                                         lasso_inside(data->mcords, data->moves, x0, y0) &&
488                                         lasso_inside(data->mcords, data->moves, x1, y1)) {
489                                 BM_elem_select_set(data->vc->em->bm, eed, data->select);
490                                 data->done = 1;
491                         }
492                 }
493                 else {
494                         if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) {
495                                 BM_elem_select_set(data->vc->em->bm, eed, data->select);
496                         }
497                 }
498         }
499 }
500 static void do_lasso_select_mesh__doSelectFace(void *userData, BMFace *efa, int x, int y, int UNUSED(index))
501 {
502         LassoSelectUserData *data = userData;
503
504         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
505                 BM_elem_select_set(data->vc->em->bm, efa, data->select);
506         }
507 }
508
509 static void do_lasso_select_mesh(ViewContext *vc, int mcords[][2], short moves, short extend, short select)
510 {
511         LassoSelectUserData data;
512         ToolSettings *ts= vc->scene->toolsettings;
513         rcti rect;
514         int bbsel;
515         
516         lasso_select_boundbox(&rect, mcords, moves);
517         
518         /* set editmesh */
519         vc->em= ((Mesh *)vc->obedit->data)->edit_btmesh;
520
521         data.vc= vc;
522         data.rect = &rect;
523         data.mcords = mcords;
524         data.moves = moves;
525         data.select = select;
526         data.done = 0;
527         data.pass = 0;
528
529         if (extend == 0 && select)
530                 EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT);
531
532          /* for non zbuf projections, dont change the GL state */
533         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
534
535         glLoadMatrixf(vc->rv3d->viewmat);
536         bbsel= EDBM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
537         
538         if (ts->selectmode & SCE_SELECT_VERTEX) {
539                 if (bbsel) {
540                         EDBM_backbuf_checkAndSelectVerts(vc->em, select);
541                 }
542                 else {
543                         mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, V3D_CLIP_TEST_RV3D_CLIPPING);
544                 }
545         }
546         if (ts->selectmode & SCE_SELECT_EDGE) {
547                 /* Does both bbsel and non-bbsel versions (need screen cos for both) */
548                 data.pass = 0;
549                 mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, V3D_CLIP_TEST_OFF);
550
551                 if (data.done==0) {
552                         data.pass = 1;
553                         mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, V3D_CLIP_TEST_OFF);
554                 }
555         }
556         
557         if (ts->selectmode & SCE_SELECT_FACE) {
558                 if (bbsel) {
559                         EDBM_backbuf_checkAndSelectFaces(vc->em, select);
560                 }
561                 else {
562                         mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data);
563                 }
564         }
565         
566         EDBM_free_backbuf();
567         EDBM_selectmode_flush(vc->em);
568 }
569
570 /* BMESH_TODO */
571 #if 0
572 /* this is an exception in that its the only lasso that dosnt use the 3d view (uses space image view) */
573 static void do_lasso_select_mesh_uv(int mcords[][2], short moves, short select)
574 {
575         EditFace *efa;
576         MTFace *tf;
577         int screenUV[2], nverts, i, ok = 1;
578         rcti rect;
579         
580         lasso_select_boundbox(&rect, mcords, moves);
581         
582         if (draw_uvs_face_check()) { /* Face Center Sel */
583                 float cent[2];
584                 ok = 0;
585                 for (efa= em->faces.first; efa; efa= efa->next) {
586                         /* assume not touched */
587                         efa->tmp.l = 0;
588                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
589                         if ((select) != (simaFaceSel_Check(efa, tf))) {
590                                 uv_center(tf->uv, cent, (void *)efa->v4);
591                                 uvco_to_areaco_noclip(cent, screenUV);
592                                 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
593                                         efa->tmp.l = ok = 1;
594                                 }
595                         }
596                 }
597                 /* (de)selects all tagged faces and deals with sticky modes */
598                 if (ok)
599                         uvface_setsel__internal(select);
600                 
601         }
602         else { /* Vert Sel*/
603                 for (efa= em->faces.first; efa; efa= efa->next) {
604                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
605                         if (uvedit_face_visible(scene, ima, efa, tf)) {         
606                                 nverts= efa->v4? 4: 3;
607                                 for (i=0; i<nverts; i++) {
608                                         if ((select) != (simaUVSel_Check(efa, tf, i))) {
609                                                 uvco_to_areaco_noclip(tf->uv[i], screenUV);
610                                                 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
611                                                         if (select) {
612                                                                 simaUVSel_Set(efa, tf, i);
613                                                         }
614                                                         else {
615                                                                 simaUVSel_UnSet(efa, tf, i);
616                                                         }
617                                                 }
618                                         }
619                                 }
620                         }
621                 }
622         }
623         if (ok && G.sima->flag & SI_SYNC_UVSEL) {
624                 if (select) EM_select_flush(vc->em);
625                 else            EM_deselect_flush(vc->em);
626         }
627 }
628 #endif
629
630 static void do_lasso_select_curve__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
631 {
632         LassoSelectUserData *data = userData;
633         Object *obedit= data->vc->obedit;
634         Curve *cu= (Curve*)obedit->data;
635
636         if (lasso_inside(data->mcords, data->moves, x, y)) {
637                 if (bp) {
638                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
639                         if (bp == cu->lastsel && !(bp->f1 & 1)) cu->lastsel = NULL;
640                 }
641                 else {
642                         if (cu->drawflag & CU_HIDE_HANDLES) {
643                                 /* can only be beztindex==0 here since handles are hidden */
644                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
645                         }
646                         else {
647                                 if (beztindex==0) {
648                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
649                                 }
650                                 else if (beztindex==1) {
651                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
652                                 }
653                                 else {
654                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
655                                 }
656                         }
657
658                         if (bezt == cu->lastsel && !(bezt->f2 & 1)) cu->lastsel = NULL;
659                 }
660         }
661 }
662
663 static void do_lasso_select_curve(ViewContext *vc, int mcords[][2], short moves, short extend, short select)
664 {
665         LassoSelectUserData data;
666
667         /* set vc->editnurb */
668         data.vc = vc;
669         data.mcords = mcords;
670         data.moves = moves;
671         data.select = select;
672
673         if (extend == 0 && select)
674                 CU_deselect_all(vc->obedit);
675
676         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
677         nurbs_foreachScreenVert(vc, do_lasso_select_curve__doSelect, &data);
678 }
679
680 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, int y)
681 {
682         LassoSelectUserData *data = userData;
683
684         if (lasso_inside(data->mcords, data->moves, x, y)) {
685                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
686         }
687 }
688 static void do_lasso_select_lattice(ViewContext *vc, int mcords[][2], short moves, short extend, short select)
689 {
690         LassoSelectUserData data;
691
692         /* set editdata in vc */
693         data.mcords = mcords;
694         data.moves = moves;
695         data.select = select;
696
697         if (extend == 0 && select)
698                 ED_setflagsLatt(vc->obedit, 0);
699
700         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
701         lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data);
702 }
703
704 static void do_lasso_select_armature(ViewContext *vc, int mcords[][2], short moves, short extend, short select)
705 {
706         bArmature *arm= vc->obedit->data;
707         EditBone *ebone;
708         float vec[3];
709         short sco1[2], sco2[2], didpoint;
710         int change= FALSE;
711
712         if (extend==0 && select)
713                 ED_armature_deselect_all_visible(vc->obedit);
714
715         /* set editdata in vc */
716         
717         for (ebone= arm->edbo->first; ebone; ebone=ebone->next) {
718                 if (EBONE_VISIBLE(arm, ebone) && (ebone->flag & BONE_UNSELECTABLE)==0) {
719                         mul_v3_m4v3(vec, vc->obedit->obmat, ebone->head);
720                         project_short(vc->ar, vec, sco1);
721                         mul_v3_m4v3(vec, vc->obedit->obmat, ebone->tail);
722                         project_short(vc->ar, vec, sco2);
723                         
724                         didpoint= 0;
725                         if (lasso_inside(mcords, moves, sco1[0], sco1[1])) {
726                                 if (select) ebone->flag |= BONE_ROOTSEL;
727                                 else ebone->flag &= ~BONE_ROOTSEL;
728                                 didpoint= 1;
729                                 change= TRUE;
730                         }
731                         if (lasso_inside(mcords, moves, sco2[0], sco2[1])) {
732                                 if (select) ebone->flag |= BONE_TIPSEL;
733                                 else ebone->flag &= ~BONE_TIPSEL;
734                                 didpoint= 1;
735                                 change= TRUE;
736                         }
737                         /* if one of points selected, we skip the bone itself */
738                         if (didpoint==0 && lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
739                                 if (select) ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
740                                 else ebone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
741                                 change= TRUE;
742                         }
743                 }
744         }
745         
746         if (change) {
747                 ED_armature_sync_selection(arm->edbo);
748                 ED_armature_validate_active(arm);
749                 WM_main_add_notifier(NC_OBJECT|ND_BONE_SELECT, vc->obedit);
750         }
751 }
752
753
754
755
756 static void do_lasso_select_meta(ViewContext *vc, int mcords[][2], short moves, short extend, short select)
757 {
758         MetaBall *mb = (MetaBall*)vc->obedit->data;
759         MetaElem *ml;
760         float vec[3];
761         short sco[2];
762
763         if (extend == 0 && select) {
764                 for (ml= mb->editelems->first; ml; ml= ml->next) {
765                         ml->flag &= ~SELECT;
766                 }
767         }
768
769         for (ml= mb->editelems->first; ml; ml= ml->next) {
770                 
771                 mul_v3_m4v3(vec, vc->obedit->obmat, &ml->x);
772                 project_short(vc->ar, vec, sco);
773
774                 if (lasso_inside(mcords, moves, sco[0], sco[1])) {
775                         if (select)     ml->flag |= SELECT;
776                         else            ml->flag &= ~SELECT;
777                 }
778         }
779 }
780
781 int do_paintvert_box_select(ViewContext *vc, rcti *rect, int select, int extend)
782 {
783         Mesh *me;
784         MVert *mvert;
785         struct ImBuf *ibuf;
786         unsigned int *rt;
787         int a, index;
788         char *selar;
789         int sx= rect->xmax-rect->xmin+1;
790         int sy= rect->ymax-rect->ymin+1;
791
792         me= vc->obact->data;
793
794         if (me==NULL || me->totvert==0 || sx*sy <= 0)
795                 return OPERATOR_CANCELLED;
796
797         selar= MEM_callocN(me->totvert+1, "selar");
798
799         if (extend == 0 && select)
800                 paintvert_deselect_all_visible(vc->obact, SEL_DESELECT, FALSE);
801
802         view3d_validate_backbuf(vc);
803
804         ibuf = IMB_allocImBuf(sx,sy,32,IB_rect);
805         rt = ibuf->rect;
806         glReadPixels(rect->xmin+vc->ar->winrct.xmin,  rect->ymin+vc->ar->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE,  ibuf->rect);
807         if (ENDIAN_ORDER==B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
808
809         a= sx*sy;
810         while (a--) {
811                 if (*rt) {
812                         index= WM_framebuffer_to_index(*rt);
813                         if (index<=me->totvert) selar[index]= 1;
814                 }
815                 rt++;
816         }
817
818         mvert= me->mvert;
819         for (a=1; a<=me->totvert; a++, mvert++) {
820                 if (selar[a]) {
821                         if (mvert->flag & ME_HIDE);
822                         else {
823                                 if (select) mvert->flag |= SELECT;
824                                 else mvert->flag &= ~SELECT;
825                         }
826                 }
827         }
828
829         IMB_freeImBuf(ibuf);
830         MEM_freeN(selar);
831
832 #ifdef __APPLE__        
833         glReadBuffer(GL_BACK);
834 #endif
835
836         paintvert_flush_flags(vc->obact);
837
838         return OPERATOR_FINISHED;
839 }
840
841 static void do_lasso_select_paintvert(ViewContext *vc, int mcords[][2], short moves, short extend, short select)
842 {
843         Object *ob= vc->obact;
844         Mesh *me= ob?ob->data:NULL;
845         rcti rect;
846
847         if (me==NULL || me->totvert==0)
848                 return;
849
850         if (extend==0 && select)
851                 paintvert_deselect_all_visible(ob, SEL_DESELECT, FALSE); /* flush selection at the end */
852         bm_vertoffs= me->totvert+1;     /* max index array */
853
854         lasso_select_boundbox(&rect, mcords, moves);
855         EDBM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
856
857         EDBM_backbuf_checkAndSelectVerts_obmode(me, select);
858
859         EDBM_free_backbuf();
860
861         paintvert_flush_flags(ob);
862 }
863 static void do_lasso_select_paintface(ViewContext *vc, int mcords[][2], short moves, short extend, short select)
864 {
865         Object *ob= vc->obact;
866         Mesh *me= ob?ob->data:NULL;
867         rcti rect;
868
869         if (me==NULL || me->totpoly==0)
870                 return;
871
872         if (extend==0 && select)
873                 paintface_deselect_all_visible(ob, SEL_DESELECT, FALSE); /* flush selection at the end */
874
875         bm_vertoffs= me->totpoly+1;     /* max index array */
876
877         lasso_select_boundbox(&rect, mcords, moves);
878         EDBM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
879         
880         EDBM_backbuf_checkAndSelectTFaces(me, select);
881
882         EDBM_free_backbuf();
883
884         paintface_flush_flags(ob);
885 }
886
887 #if 0
888 static void do_lasso_select_node(int mcords[][2], short moves, short select)
889 {
890         SpaceNode *snode = sa->spacedata.first;
891         
892         bNode *node;
893         rcti rect;
894         short node_cent[2];
895         float node_centf[2];
896         
897         lasso_select_boundbox(&rect, mcords, moves);
898         
899         /* store selection in temp test flag */
900         for (node= snode->edittree->nodes.first; node; node= node->next) {
901                 
902                 node_centf[0] = (node->totr.xmin+node->totr.xmax)/2;
903                 node_centf[1] = (node->totr.ymin+node->totr.ymax)/2;
904                 
905                 ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
906                 if (BLI_in_rcti(&rect, node_cent[0], node_cent[1]) && lasso_inside(mcords, moves, node_cent[0], node_cent[1])) {
907                         if (select) {
908                                 node->flag |= SELECT;
909                         }
910                         else {
911                                 node->flag &= ~SELECT;
912                         }
913                 }
914         }
915         BIF_undo_push("Lasso select nodes");
916 }
917 #endif
918
919 static void view3d_lasso_select(bContext *C, ViewContext *vc, int mcords[][2], short moves, short extend, short select)
920 {
921         Object *ob = CTX_data_active_object(C);
922
923         if (vc->obedit==NULL) { /* Object Mode */
924                 if (paint_facesel_test(ob))
925                         do_lasso_select_paintface(vc, mcords, moves, extend, select);
926                 else if (paint_vertsel_test(ob))
927                         do_lasso_select_paintvert(vc, mcords, moves, extend, select);
928                 else if (ob && ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT))
929                         ;
930                 else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT)
931                         PE_lasso_select(C, mcords, moves, extend, select);
932                 else {
933                         do_lasso_select_objects(vc, mcords, moves, extend, select);
934                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, vc->scene);
935                 }
936         }
937         else { /* Edit Mode */
938                 switch(vc->obedit->type) {
939                 case OB_MESH:
940                         do_lasso_select_mesh(vc, mcords, moves, extend, select);
941                         break;
942                 case OB_CURVE:
943                 case OB_SURF:
944                         do_lasso_select_curve(vc, mcords, moves, extend, select);
945                         break;
946                 case OB_LATTICE:
947                         do_lasso_select_lattice(vc, mcords, moves, extend, select);
948                         break;
949                 case OB_ARMATURE:
950                         do_lasso_select_armature(vc, mcords, moves, extend, select);
951                         break;
952                 case OB_MBALL:
953                         do_lasso_select_meta(vc, mcords, moves, extend, select);
954                         break;
955                 default:
956                         assert(!"lasso select on incorrect object type");
957                 }
958
959                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc->obedit->data);
960         }
961 }
962
963
964 /* lasso operator gives properties, but since old code works
965    with short array we convert */
966 static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
967 {
968         ViewContext vc;
969         int i= 0;
970         int mcords[1024][2];
971
972         RNA_BEGIN(op->ptr, itemptr, "path") {
973                 float loc[2];
974                 
975                 RNA_float_get_array(&itemptr, "loc", loc);
976                 mcords[i][0]= (int)loc[0];
977                 mcords[i][1]= (int)loc[1];
978                 i++;
979                 if (i>=1024) break;
980         }
981         RNA_END;
982         
983         if (i>1) {
984                 short extend, select;
985                 view3d_operator_needs_opengl(C);
986                 
987                 /* setup view context for argument to callbacks */
988                 view3d_set_viewcontext(C, &vc);
989                 
990                 extend= RNA_boolean_get(op->ptr, "extend");
991                 select= !RNA_boolean_get(op->ptr, "deselect");
992                 view3d_lasso_select(C, &vc, mcords, i, extend, select);
993                 
994                 return OPERATOR_FINISHED;
995         }
996         return OPERATOR_PASS_THROUGH;
997 }
998
999 void VIEW3D_OT_select_lasso(wmOperatorType *ot)
1000 {
1001         ot->name= "Lasso Select";
1002         ot->description= "Select items using lasso selection";
1003         ot->idname= "VIEW3D_OT_select_lasso";
1004         
1005         ot->invoke= WM_gesture_lasso_invoke;
1006         ot->modal= WM_gesture_lasso_modal;
1007         ot->exec= view3d_lasso_select_exec;
1008         ot->poll= view3d_selectable_data;
1009         ot->cancel= WM_gesture_lasso_cancel;
1010         
1011         /* flags */
1012         ot->flag= OPTYPE_UNDO;
1013         
1014         RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
1015         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items");
1016         RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection instead of deselecting everything first");
1017 }
1018
1019
1020 /* ************************************************* */
1021
1022 #if 0
1023 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
1024 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
1025 {
1026         Base *base;
1027         unsigned int *bufmin,*bufmax;
1028         int a,b,rc,tel,len,dirvec[4][2],maxob;
1029         unsigned int retval=0;
1030         
1031         base= LASTBASE;
1032         if (base==0) return 0;
1033         maxob= base->selcol;
1034
1035         len= (size-1)/2;
1036         rc= 0;
1037
1038         dirvec[0][0]= 1;
1039         dirvec[0][1]= 0;
1040         dirvec[1][0]= 0;
1041         dirvec[1][1]= -size;
1042         dirvec[2][0]= -1;
1043         dirvec[2][1]= 0;
1044         dirvec[3][0]= 0;
1045         dirvec[3][1]= size;
1046
1047         bufmin= buf;
1048         bufmax= buf+ size*size;
1049         buf+= len*size+ len;
1050
1051         for (tel=1;tel<=size;tel++) {
1052
1053                 for (a=0;a<2;a++) {
1054                         for (b=0;b<tel;b++) {
1055
1056                                 if (*buf && *buf<=maxob && *buf!=dontdo) return *buf;
1057                                 if ( *buf==dontdo ) retval= dontdo;     /* if only color dontdo is available, still return dontdo */
1058                                 
1059                                 buf+= (dirvec[rc][0]+dirvec[rc][1]);
1060
1061                                 if (buf<bufmin || buf>=bufmax) return retval;
1062                         }
1063                         rc++;
1064                         rc &= 3;
1065                 }
1066         }
1067         return retval;
1068 }
1069 #endif
1070
1071 /* ************************** mouse select ************************* */
1072
1073
1074 /* The max number of menu items in an object select menu */
1075 typedef struct SelMenuItemF {
1076         char idname[MAX_ID_NAME-2];
1077         int icon;
1078 } SelMenuItemF;
1079
1080 #define SEL_MENU_SIZE   22
1081 static SelMenuItemF object_mouse_select_menu_data[SEL_MENU_SIZE];
1082
1083 /* special (crappy) operator only for menu select */
1084 static EnumPropertyItem *object_select_menu_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
1085 {
1086         EnumPropertyItem *item= NULL, item_tmp= {0};
1087         int totitem= 0;
1088         int i= 0;
1089
1090         /* dont need context but avoid docgen using this */
1091         if (C == NULL || object_mouse_select_menu_data[i].idname[0] == '\0') {
1092                 return DummyRNA_NULL_items;
1093         }
1094
1095         for (; i < SEL_MENU_SIZE && object_mouse_select_menu_data[i].idname[0] != '\0'; i++) {
1096                 item_tmp.name= object_mouse_select_menu_data[i].idname;
1097                 item_tmp.identifier= object_mouse_select_menu_data[i].idname;
1098                 item_tmp.value= i;
1099                 item_tmp.icon= object_mouse_select_menu_data[i].icon;
1100                 RNA_enum_item_add(&item, &totitem, &item_tmp);
1101         }
1102
1103         RNA_enum_item_end(&item, &totitem);
1104         *free= 1;
1105
1106         return item;
1107 }
1108
1109 static int object_select_menu_exec(bContext *C, wmOperator *op)
1110 {
1111         int name_index= RNA_enum_get(op->ptr, "name");
1112         short extend= RNA_boolean_get(op->ptr, "extend");
1113         short changed = 0;
1114         const char *name= object_mouse_select_menu_data[name_index].idname;
1115
1116         if (!extend) {
1117                 CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
1118                         if (base->flag & SELECT) {
1119                                 ED_base_object_select(base, BA_DESELECT);
1120                                 changed= 1;
1121                         }
1122                 }
1123                 CTX_DATA_END;
1124         }
1125
1126         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
1127                 /* this is a bit dodjy, there should only be ONE object with this name, but library objects can mess this up */
1128                 if (strcmp(name, base->object->id.name+2)==0) {
1129                         ED_base_object_activate(C, base);
1130                         ED_base_object_select(base, BA_SELECT);
1131                         changed= 1;
1132                 }
1133         }
1134         CTX_DATA_END;
1135
1136         /* weak but ensures we activate menu again before using the enum */
1137         memset(object_mouse_select_menu_data, 0, sizeof(object_mouse_select_menu_data));
1138
1139         /* undo? */
1140         if (changed) {
1141                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1142                 return OPERATOR_FINISHED;
1143         }
1144         else {
1145                 return OPERATOR_CANCELLED;
1146         }
1147 }
1148
1149 void VIEW3D_OT_select_menu(wmOperatorType *ot)
1150 {
1151         PropertyRNA *prop;
1152
1153         /* identifiers */
1154         ot->name= "Select Menu";
1155         ot->description = "Menu object selection";
1156         ot->idname= "VIEW3D_OT_select_menu";
1157
1158         /* api callbacks */
1159         ot->invoke= WM_menu_invoke;
1160         ot->exec= object_select_menu_exec;
1161
1162         /* flags */
1163         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1164
1165         /* keyingset to use (dynamic enum) */
1166         prop= RNA_def_enum(ot->srna, "name", DummyRNA_NULL_items, 0, "Object Name", "");
1167         RNA_def_enum_funcs(prop, object_select_menu_enum_itemf);
1168         RNA_def_property_flag(prop, PROP_HIDDEN);
1169         ot->prop= prop;
1170
1171         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first");
1172 }
1173
1174 static void deselectall_except(Scene *scene, Base *b)   /* deselect all except b */
1175 {
1176         Base *base;
1177         
1178         for (base= FIRSTBASE; base; base= base->next) {
1179                 if (base->flag & SELECT) {
1180                         if (b!=base) {
1181                                 ED_base_object_select(base, BA_DESELECT);
1182                         }
1183                 }
1184         }
1185 }
1186
1187 static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int *buffer, int hits, const int mval[2], short extend)
1188 {
1189         short baseCount = 0;
1190         short ok;
1191         LinkNode *linklist= NULL;
1192         
1193         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
1194                 ok= FALSE;
1195
1196                 /* two selection methods, the CTRL select uses max dist of 15 */
1197                 if (buffer) {
1198                         int a;
1199                         for (a=0; a<hits; a++) {
1200                                 /* index was converted */
1201                                 if (base->selcol==buffer[ (4 * a) + 3 ])
1202                                         ok= TRUE;
1203                         }
1204                 }
1205                 else {
1206                         int temp, dist=15;
1207
1208                         project_short(vc->ar, base->object->obmat[3], &base->sx);
1209                         
1210                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
1211                         if (temp < dist)
1212                                 ok= TRUE;
1213                 }
1214
1215                 if (ok) {
1216                         baseCount++;
1217                         BLI_linklist_prepend(&linklist, base);
1218
1219                         if (baseCount==SEL_MENU_SIZE)
1220                                 break;
1221                 }
1222         }
1223         CTX_DATA_END;
1224
1225         if (baseCount==0) {
1226                 return NULL;
1227         }
1228         if (baseCount == 1) {
1229                 Base *base= (Base *)linklist->link;
1230                 BLI_linklist_free(linklist, NULL);
1231                 return base;
1232         }
1233         else {
1234                 /* UI, full in static array values that we later use in an enum function */
1235                 LinkNode *node;
1236                 int i;
1237
1238                 memset(object_mouse_select_menu_data, 0, sizeof(object_mouse_select_menu_data));
1239
1240                 for (node = linklist, i = 0; node; node= node->next, i++) {
1241                         Base *base=node->link;
1242                         Object *ob= base->object;
1243                         char *name= ob->id.name+2;
1244
1245                         BLI_strncpy(object_mouse_select_menu_data[i].idname, name, MAX_ID_NAME-2);
1246                         object_mouse_select_menu_data[i].icon = uiIconFromID(&ob->id);
1247                 }
1248
1249                 {
1250                         PointerRNA ptr;
1251
1252                         WM_operator_properties_create(&ptr, "VIEW3D_OT_select_menu");
1253                         RNA_boolean_set(&ptr, "extend", extend);
1254                         WM_operator_name_call(C, "VIEW3D_OT_select_menu", WM_OP_INVOKE_DEFAULT, &ptr);
1255                         WM_operator_properties_free(&ptr);
1256                 }
1257
1258                 BLI_linklist_free(linklist, NULL);
1259                 return NULL;
1260         }
1261 }
1262
1263 /* we want a select buffer with bones, if there are... */
1264 /* so check three selection levels and compare */
1265 static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, const int mval[2])
1266 {
1267         rcti rect;
1268         int offs;
1269         short a, hits15, hits9=0, hits5=0;
1270         short has_bones15=0, has_bones9=0, has_bones5=0;
1271         
1272         BLI_init_rcti(&rect, mval[0]-14, mval[0]+14, mval[1]-14, mval[1]+14);
1273         hits15= view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
1274         if (hits15>0) {
1275                 for (a=0; a<hits15; a++) if (buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
1276                 
1277                 offs= 4*hits15;
1278                 BLI_init_rcti(&rect, mval[0]-9, mval[0]+9, mval[1]-9, mval[1]+9);
1279                 hits9= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
1280                 if (hits9>0) {
1281                         for (a=0; a<hits9; a++) if (buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
1282                         
1283                         offs+= 4*hits9;
1284                         BLI_init_rcti(&rect, mval[0]-5, mval[0]+5, mval[1]-5, mval[1]+5);
1285                         hits5= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect);
1286                         if (hits5>0) {
1287                                 for (a=0; a<hits5; a++) if (buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
1288                         }
1289                 }
1290                 
1291                 if (has_bones5) {
1292                         offs= 4*hits15 + 4*hits9;
1293                         memcpy(buffer, buffer+offs, 4*offs);
1294                         return hits5;
1295                 }
1296                 if (has_bones9) {
1297                         offs= 4*hits15;
1298                         memcpy(buffer, buffer+offs, 4*offs);
1299                         return hits9;
1300                 }
1301                 if (has_bones15) {
1302                         return hits15;
1303                 }
1304                 
1305                 if (hits5>0) {
1306                         offs= 4*hits15 + 4*hits9;
1307                         memcpy(buffer, buffer+offs, 4*offs);
1308                         return hits5;
1309                 }
1310                 if (hits9>0) {
1311                         offs= 4*hits15;
1312                         memcpy(buffer, buffer+offs, 4*offs);
1313                         return hits9;
1314                 }
1315                 return hits15;
1316         }
1317         
1318         return 0;
1319 }
1320
1321 /* returns basact */
1322 static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits, const int mval[2], Base *startbase, int has_bones)
1323 {
1324         Scene *scene= vc->scene;
1325         View3D *v3d= vc->v3d;
1326         Base *base, *basact= NULL;
1327         static int lastmval[2]={-100, -100};
1328         int a, donearest= 0;
1329         
1330         /* define if we use solid nearest select or not */
1331         if (v3d->drawtype>OB_WIRE) {
1332                 donearest= 1;
1333                 if ( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
1334                         if (!has_bones) /* hrms, if theres bones we always do nearest */
1335                                 donearest= 0;
1336                 }
1337         }
1338         lastmval[0]= mval[0]; lastmval[1]= mval[1];
1339         
1340         if (donearest) {
1341                 unsigned int min= 0xFFFFFFFF;
1342                 int selcol= 0, notcol=0;
1343                 
1344                 
1345                 if (has_bones) {
1346                         /* we skip non-bone hits */
1347                         for (a=0; a<hits; a++) {
1348                                 if ( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
1349                                         min= buffer[4*a+1];
1350                                         selcol= buffer[4*a+3] & 0xFFFF;
1351                                 }
1352                         }
1353                 }
1354                 else {
1355                         /* only exclude active object when it is selected... */
1356                         if (BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol;        
1357                         
1358                         for (a=0; a<hits; a++) {
1359                                 if ( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1360                                         min= buffer[4*a+1];
1361                                         selcol= buffer[4*a+3] & 0xFFFF;
1362                                 }
1363                         }
1364                 }
1365                 
1366                 base= FIRSTBASE;
1367                 while (base) {
1368                         if (BASE_SELECTABLE(v3d, base)) {
1369                                 if (base->selcol==selcol) break;
1370                         }
1371                         base= base->next;
1372                 }
1373                 if (base) basact= base;
1374         }
1375         else {
1376                 
1377                 base= startbase;
1378                 while (base) {
1379                         /* skip objects with select restriction, to prevent prematurely ending this loop
1380                         * with an un-selectable choice */
1381                         if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1382                                 base=base->next;
1383                                 if (base==NULL) base= FIRSTBASE;
1384                                 if (base==startbase) break;
1385                         }
1386                         
1387                         if (BASE_SELECTABLE(v3d, base)) {
1388                                 for (a=0; a<hits; a++) {
1389                                         if (has_bones) {
1390                                                 /* skip non-bone objects */
1391                                                 if ((buffer[4*a+3] & 0xFFFF0000)) {
1392                                                         if (base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1393                                                                 basact= base;
1394                                                 }
1395                                         }
1396                                         else {
1397                                                 if (base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1398                                                         basact= base;
1399                                         }
1400                                 }
1401                         }
1402                         
1403                         if (basact) break;
1404                         
1405                         base= base->next;
1406                         if (base==NULL) base= FIRSTBASE;
1407                         if (base==startbase) break;
1408                 }
1409         }
1410         
1411         return basact;
1412 }
1413
1414 /* mval comes from event->mval, only use within region handlers */
1415 Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
1416 {
1417         ViewContext vc;
1418         Base *basact= NULL;
1419         unsigned int buffer[4*MAXPICKBUF];
1420         int hits;
1421         
1422         /* setup view context for argument to callbacks */
1423         view3d_operator_needs_opengl(C);
1424         view3d_set_viewcontext(C, &vc);
1425         
1426         hits= mixed_bones_object_selectbuffer(&vc, buffer, mval);
1427         
1428         if (hits>0) {
1429                 int a, has_bones= 0;
1430                 
1431                 for (a=0; a<hits; a++) if (buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1432                 
1433                 basact= mouse_select_eval_buffer(&vc, buffer, hits, mval, vc.scene->base.first, has_bones);
1434         }
1435         
1436         return basact;
1437 }
1438
1439 static void deselect_all_tracks(MovieTracking *tracking)
1440 {
1441         MovieTrackingObject *object;
1442
1443         object= tracking->objects.first;
1444         while (object) {
1445                 ListBase *tracksbase= BKE_tracking_object_tracks(tracking, object);
1446                 MovieTrackingTrack *track= tracksbase->first;
1447
1448                 while (track) {
1449                         BKE_tracking_deselect_track(track, TRACK_AREA_ALL);
1450
1451                         track= track->next;
1452                 }
1453
1454                 object= object->next;
1455         }
1456 }
1457
1458 /* mval is region coords */
1459 static int mouse_select(bContext *C, const int mval[2], short extend, short obcenter, short enumerate)
1460 {
1461         ViewContext vc;
1462         ARegion *ar= CTX_wm_region(C);
1463         View3D *v3d= CTX_wm_view3d(C);
1464         Scene *scene= CTX_data_scene(C);
1465         Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
1466         int temp, a, dist=100;
1467         int retval = 0;
1468         short hits;
1469         
1470         /* setup view context for argument to callbacks */
1471         view3d_set_viewcontext(C, &vc);
1472         
1473         /* always start list from basact in wire mode */
1474         startbase=  FIRSTBASE;
1475         if (BASACT && BASACT->next) startbase= BASACT->next;
1476         
1477         /* This block uses the control key to make the object selected by its center point rather than its contents */
1478         /* in editmode do not activate */
1479         if (obcenter) {
1480                 
1481                 /* note; shift+alt goes to group-flush-selecting */
1482                 if (enumerate) {
1483                         basact= object_mouse_select_menu(C, &vc, NULL, 0, mval, extend);
1484                 }
1485                 else {
1486                         base= startbase;
1487                         while (base) {
1488                                 if (BASE_SELECTABLE(v3d, base)) {
1489                                         project_short(ar, base->object->obmat[3], &base->sx);
1490                                         
1491                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
1492                                         if (base==BASACT) temp+=10;
1493                                         if (temp<dist ) {
1494                                                 
1495                                                 dist= temp;
1496                                                 basact= base;
1497                                         }
1498                                 }
1499                                 base= base->next;
1500                                 
1501                                 if (base==NULL) base= FIRSTBASE;
1502                                 if (base==startbase) break;
1503                         }
1504                 }
1505         }
1506         else {
1507                 unsigned int buffer[4*MAXPICKBUF];
1508
1509                 /* if objects have posemode set, the bones are in the same selection buffer */
1510                 
1511                 hits= mixed_bones_object_selectbuffer(&vc, buffer, mval);
1512                 
1513                 if (hits>0) {
1514                         int has_bones= 0;
1515                         
1516                         /* note: bundles are handling in the same way as bones */
1517                         for (a=0; a<hits; a++) if (buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1518
1519                         /* note; shift+alt goes to group-flush-selecting */
1520                         if (has_bones==0 && enumerate) {
1521                                 basact= object_mouse_select_menu(C, &vc, buffer, hits, mval, extend);
1522                         }
1523                         else {
1524                                 basact= mouse_select_eval_buffer(&vc, buffer, hits, mval, startbase, has_bones);
1525                         }
1526                         
1527                         if (has_bones && basact) {
1528                                 if (basact->object->type==OB_CAMERA) {
1529                                         if (BASACT==basact) {
1530                                                 int i, hitresult;
1531                                                 int changed= 0;
1532
1533                                                 for (i=0; i< hits; i++) {
1534                                                         hitresult= buffer[3+(i*4)];
1535
1536                                                         /* if there's bundles in buffer select bundles first,
1537                                                            so non-camera elements should be ignored in buffer */
1538                                                         if (basact->selcol != (hitresult & 0xFFFF)) {
1539                                                                 continue;
1540                                                         }
1541
1542                                                         /* index of bundle is 1<<16-based. if there's no "bone" index
1543                                                            in hight word, this buffer value belongs to camera,. not to bundle */
1544                                                         if (buffer[4*i+3] & 0xFFFF0000) {
1545                                                                 MovieClip *clip= object_get_movieclip(scene, basact->object, 0);
1546                                                                 MovieTracking *tracking= &clip->tracking;
1547                                                                 ListBase *tracksbase;
1548                                                                 MovieTrackingTrack *track;
1549
1550                                                                 track= BKE_tracking_indexed_track(&clip->tracking, hitresult >> 16, &tracksbase);
1551
1552                                                                 if (TRACK_SELECTED(track) && extend) {
1553                                                                         changed= 0;
1554                                                                         BKE_tracking_deselect_track(track, TRACK_AREA_ALL);
1555                                                                 }
1556                                                                 else {
1557                                                                         int oldsel= TRACK_SELECTED(track) ? 1 : 0;
1558                                                                         if (!extend)
1559                                                                                 deselect_all_tracks(tracking);
1560
1561                                                                         BKE_tracking_select_track(tracksbase, track, TRACK_AREA_ALL, extend);
1562
1563                                                                         if (oldsel!=(TRACK_SELECTED(track) ? 1 : 0))
1564                                                                                 changed= 1;
1565                                                                 }
1566
1567                                                                 basact->flag|= SELECT;
1568                                                                 basact->object->flag= basact->flag;
1569
1570                                                                 retval= 1;
1571
1572                                                                 WM_event_add_notifier(C, NC_MOVIECLIP|ND_SELECT, track);
1573                                                                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1574
1575                                                                 break;
1576                                                         }
1577                                                 }
1578
1579                                                 if (!changed) {
1580                                                         /* fallback to regular object selection if no new bundles were selected,
1581                                                            allows to select object parented to reconstruction object */
1582                                                         basact= mouse_select_eval_buffer(&vc, buffer, hits, mval, startbase, 0);
1583                                                 }
1584                                         }
1585                                 }
1586                                 else if (ED_do_pose_selectbuffer(scene, basact, buffer, hits, extend) ) {       /* then bone is found */
1587                                 
1588                                         /* we make the armature selected: 
1589                                            not-selected active object in posemode won't work well for tools */
1590                                         basact->flag|= SELECT;
1591                                         basact->object->flag= basact->flag;
1592                                         
1593                                         retval = 1;
1594                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, basact->object);
1595                                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, basact->object);
1596                                         
1597                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1598                                         if (BASACT && BASACT->object->mode & OB_MODE_WEIGHT_PAINT) {
1599                                                 /* prevent activating */
1600                                                 basact= NULL;
1601                                         }
1602
1603                                 }
1604                                 /* prevent bone selecting to pass on to object selecting */
1605                                 if (basact==BASACT)
1606                                         basact= NULL;
1607                         }
1608                 }
1609         }
1610         
1611         /* so, do we have something selected? */
1612         if (basact) {
1613                 retval = 1;
1614                 
1615                 if (vc.obedit) {
1616                         /* only do select */
1617                         deselectall_except(scene, basact);
1618                         ED_base_object_select(basact, BA_SELECT);
1619                 }
1620                 /* also prevent making it active on mouse selection */
1621                 else if (BASE_SELECTABLE(v3d, basact)) {
1622
1623                         oldbasact= BASACT;
1624                         
1625                         if (!extend) {
1626                                 deselectall_except(scene, basact);
1627                                 ED_base_object_select(basact, BA_SELECT);
1628                         }
1629                         else if (0) {
1630                                 // XXX select_all_from_groups(basact);
1631                         }
1632                         else {
1633                                 if (basact->flag & SELECT) {
1634                                         if (basact==oldbasact)
1635                                                 ED_base_object_select(basact, BA_DESELECT);
1636                                 }
1637                                 else ED_base_object_select(basact, BA_SELECT);
1638                         }
1639
1640                         if (oldbasact != basact) {
1641                                 ED_base_object_activate(C, basact); /* adds notifier */
1642                         }
1643                 }
1644
1645                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1646         }
1647
1648         return retval;
1649 }
1650
1651 /* ********************  border and circle ************************************** */
1652
1653 typedef struct BoxSelectUserData {
1654         ViewContext *vc;
1655         rcti *rect;
1656         int select, pass, done;
1657 } BoxSelectUserData;
1658
1659 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1660 {
1661         int radsq= rad*rad;
1662         float v1[2], v2[2], v3[2];
1663         
1664         /* check points in circle itself */
1665         if ( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1666         if ( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1667         
1668         /* pointdistline */
1669         v3[0]= centx;
1670         v3[1]= centy;
1671         v1[0]= x1;
1672         v1[1]= y1;
1673         v2[0]= x2;
1674         v2[1]= y2;
1675         
1676         if ( dist_to_line_segment_v2(v3, v1, v2) < (float)rad ) return 1;
1677         
1678         return 0;
1679 }
1680
1681 static void do_nurbs_box_select__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1682 {
1683         BoxSelectUserData *data = userData;
1684         Object *obedit= data->vc->obedit;
1685         Curve *cu= (Curve*)obedit->data;
1686
1687         if (BLI_in_rcti(data->rect, x, y)) {
1688                 if (bp) {
1689                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1690                         if (bp == cu->lastsel && !(bp->f1 & 1)) cu->lastsel = NULL;
1691                 }
1692                 else {
1693                         if (cu->drawflag & CU_HIDE_HANDLES) {
1694                                 /* can only be beztindex==0 here since handles are hidden */
1695                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1696                         }
1697                         else {
1698                                 if (beztindex==0) {
1699                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
1700                                 }
1701                                 else if (beztindex==1) {
1702                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
1703                                 }
1704                                 else {
1705                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
1706                                 }
1707                         }
1708
1709                         if (bezt == cu->lastsel && !(bezt->f2 & 1)) cu->lastsel = NULL;
1710                 }
1711         }
1712 }
1713 static int do_nurbs_box_select(ViewContext *vc, rcti *rect, int select, int extend)
1714 {
1715         BoxSelectUserData data;
1716         
1717         data.vc = vc;
1718         data.rect = rect;
1719         data.select = select;
1720
1721         if (extend == 0 && select)
1722                 CU_deselect_all(vc->obedit);
1723
1724         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1725         nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data);
1726
1727         return OPERATOR_FINISHED;
1728 }
1729
1730 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1731 {
1732         BoxSelectUserData *data = userData;
1733
1734         if (BLI_in_rcti(data->rect, x, y)) {
1735                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
1736         }
1737 }
1738 static int do_lattice_box_select(ViewContext *vc, rcti *rect, int select, int extend)
1739 {
1740         BoxSelectUserData data;
1741
1742         data.vc= vc;
1743         data.rect = rect;
1744         data.select = select;
1745
1746         if (extend == 0 && select)
1747                 ED_setflagsLatt(vc->obedit, 0);
1748
1749         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1750         lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data);
1751         
1752         return OPERATOR_FINISHED;
1753 }
1754
1755 static void do_mesh_box_select__doSelectVert(void *userData, BMVert *eve, int x, int y, int UNUSED(index))
1756 {
1757         BoxSelectUserData *data = userData;
1758
1759         if (BLI_in_rcti(data->rect, x, y)) {
1760                 BM_elem_select_set(data->vc->em->bm, eve, data->select);
1761         }
1762 }
1763 static void do_mesh_box_select__doSelectEdge(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index)
1764 {
1765         BoxSelectUserData *data = userData;
1766
1767         if (EDBM_check_backbuf(bm_solidoffs+index)) {
1768                 if (data->pass==0) {
1769                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1770                                 BM_elem_select_set(data->vc->em->bm, eed, data->select);
1771                                 data->done = 1;
1772                         }
1773                 }
1774                 else {
1775                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1776                                 BM_elem_select_set(data->vc->em->bm, eed, data->select);
1777                         }
1778                 }
1779         }
1780 }
1781 static void do_mesh_box_select__doSelectFace(void *userData, BMFace *efa, int x, int y, int UNUSED(index))
1782 {
1783         BoxSelectUserData *data = userData;
1784
1785         if (BLI_in_rcti(data->rect, x, y)) {
1786                 BM_elem_select_set(data->vc->em->bm, efa, data->select);
1787         }
1788 }
1789 static int do_mesh_box_select(ViewContext *vc, rcti *rect, int select, int extend)
1790 {
1791         BoxSelectUserData data;
1792         ToolSettings *ts= vc->scene->toolsettings;
1793         int bbsel;
1794         
1795         data.vc= vc;
1796         data.rect = rect;
1797         data.select = select;
1798         data.pass = 0;
1799         data.done = 0;
1800
1801         if (extend == 0 && select)
1802                 EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT);
1803
1804         /* for non zbuf projections, dont change the GL state */
1805         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
1806
1807         glLoadMatrixf(vc->rv3d->viewmat);
1808         bbsel= EDBM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1809
1810         if (ts->selectmode & SCE_SELECT_VERTEX) {
1811                 if (bbsel) {
1812                         EDBM_backbuf_checkAndSelectVerts(vc->em, select);
1813                 }
1814                 else {
1815                         mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, V3D_CLIP_TEST_RV3D_CLIPPING);
1816                 }
1817         }
1818         if (ts->selectmode & SCE_SELECT_EDGE) {
1819                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1820
1821                 data.pass = 0;
1822                 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, V3D_CLIP_TEST_OFF);
1823
1824                 if (data.done==0) {
1825                         data.pass = 1;
1826                         mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, V3D_CLIP_TEST_OFF);
1827                 }
1828         }
1829         
1830         if (ts->selectmode & SCE_SELECT_FACE) {
1831                 if (bbsel) {
1832                         EDBM_backbuf_checkAndSelectFaces(vc->em, select);
1833                 }
1834                 else {
1835                         mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data);
1836                 }
1837         }
1838         
1839         EDBM_free_backbuf();
1840                 
1841         EDBM_selectmode_flush(vc->em);
1842         
1843         return OPERATOR_FINISHED;
1844 }
1845
1846 static int do_meta_box_select(ViewContext *vc, rcti *rect, int select, int extend)
1847 {
1848         MetaBall *mb = (MetaBall*)vc->obedit->data;
1849         MetaElem *ml;
1850         int a;
1851
1852         unsigned int buffer[4*MAXPICKBUF];
1853         short hits;
1854
1855         hits= view3d_opengl_select(vc, buffer, MAXPICKBUF, rect);
1856
1857         if (extend == 0 && select) {
1858                 for (ml= mb->editelems->first; ml; ml= ml->next) {
1859                         ml->flag &= ~SELECT;
1860                 }
1861         }
1862         
1863         for (ml= mb->editelems->first; ml; ml= ml->next) {
1864                 for (a=0; a<hits; a++) {
1865                         if (ml->selcol1==buffer[ (4 * a) + 3 ]) {
1866                                 ml->flag |= MB_SCALE_RAD;
1867                                 if (select)     ml->flag |= SELECT;
1868                                 else            ml->flag &= ~SELECT;
1869                                 break;
1870                         }
1871                         if (ml->selcol2==buffer[ (4 * a) + 3 ]) {
1872                                 ml->flag &= ~MB_SCALE_RAD;
1873                                 if (select)     ml->flag |= SELECT;
1874                                 else            ml->flag &= ~SELECT;
1875                                 break;
1876                         }
1877                 }
1878         }
1879
1880         return OPERATOR_FINISHED;
1881 }
1882
1883 static int do_armature_box_select(ViewContext *vc, rcti *rect, short select, short extend)
1884 {
1885         bArmature *arm= vc->obedit->data;
1886         EditBone *ebone;
1887         int a;
1888
1889         unsigned int buffer[4*MAXPICKBUF];
1890         short hits;
1891
1892         hits= view3d_opengl_select(vc, buffer, MAXPICKBUF, rect);
1893         
1894         /* clear flag we use to detect point was affected */
1895         for (ebone= arm->edbo->first; ebone; ebone= ebone->next)
1896                 ebone->flag &= ~BONE_DONE;
1897         
1898         if (extend==0 && select)
1899                 ED_armature_deselect_all_visible(vc->obedit);
1900
1901         /* first we only check points inside the border */
1902         for (a=0; a<hits; a++) {
1903                 int index = buffer[(4*a)+3];
1904                 if (index!=-1) {
1905                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1906                         if ((ebone->flag & BONE_UNSELECTABLE)==0) {
1907                                 if (index & BONESEL_TIP) {
1908                                         ebone->flag |= BONE_DONE;
1909                                         if (select)     ebone->flag |= BONE_TIPSEL;
1910                                         else            ebone->flag &= ~BONE_TIPSEL;
1911                                 }
1912                                 
1913                                 if (index & BONESEL_ROOT) {
1914                                         ebone->flag |= BONE_DONE;
1915                                         if (select)     ebone->flag |= BONE_ROOTSEL;
1916                                         else            ebone->flag &= ~BONE_ROOTSEL;
1917                                 }
1918                         }
1919                 }
1920         }
1921         
1922         /* now we have to flush tag from parents... */
1923         for (ebone= arm->edbo->first; ebone; ebone= ebone->next) {
1924                 if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1925                         if (ebone->parent->flag & BONE_DONE)
1926                                 ebone->flag |= BONE_DONE;
1927                 }
1928         }
1929         
1930         /* only select/deselect entire bones when no points where in the rect */
1931         for (a=0; a<hits; a++) {
1932                 int index = buffer[(4*a)+3];
1933                 if (index!=-1) {
1934                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1935                         if (index & BONESEL_BONE) {
1936                                 if ((ebone->flag & BONE_UNSELECTABLE)==0) {
1937                                         if (!(ebone->flag & BONE_DONE)) {
1938                                                 if (select)
1939                                                         ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1940                                                 else
1941                                                         ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1942                                         }
1943                                 }
1944                         }
1945                 }
1946         }
1947         
1948         ED_armature_sync_selection(arm->edbo);
1949         
1950         return OPERATOR_CANCELLED;
1951 }
1952
1953 static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, int select, int extend)
1954 {
1955         Bone *bone;
1956         Object *ob= vc->obact;
1957         unsigned int *vbuffer=NULL; /* selection buffer */
1958         unsigned int *col;                      /* color in buffer      */
1959         int bone_only;
1960         int bone_selected=0;
1961         int totobj= MAXPICKBUF; // XXX solve later
1962         short hits;
1963         
1964         if ((ob) && (ob->mode & OB_MODE_POSE))
1965                 bone_only= 1;
1966         else
1967                 bone_only= 0;
1968         
1969         if (extend == 0 && select) {
1970                 if (bone_only) {
1971                         CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) {
1972                                 if ((pchan->bone->flag & BONE_UNSELECTABLE)==0) {
1973                                         pchan->bone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
1974                                 }
1975                         }
1976                         CTX_DATA_END;
1977                 }
1978                 else {
1979                         object_deselect_all_visible(vc->scene, vc->v3d);
1980                 }
1981         }
1982
1983         /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1984         vbuffer = MEM_mallocN(4 * (totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1985         hits= view3d_opengl_select(vc, vbuffer, 4*(totobj+MAXPICKBUF), rect);
1986         /*
1987         LOGIC NOTES (theeth):
1988         The buffer and ListBase have the same relative order, which makes the selection
1989         very simple. Loop through both data sets at the same time, if the color
1990         is the same as the object, we have a hit and can move to the next color
1991         and object pair, if not, just move to the next object,
1992         keeping the same color until we have a hit.
1993
1994         The buffer order is defined by OGL standard, hopefully no stupid GFX card
1995         does it incorrectly.
1996         */
1997
1998         if (hits>0) { /* no need to loop if there's no hit */
1999                 Base *base;
2000                 col = vbuffer + 3;
2001                 
2002                 for (base= vc->scene->base.first; base && hits; base= base->next) {
2003                         if (BASE_SELECTABLE(vc->v3d, base)) {
2004                                 while (base->selcol == (*col & 0xFFFF)) {       /* we got an object */
2005                                         
2006                                         if (*col & 0xFFFF0000) {                                        /* we got a bone */
2007                                                 bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
2008                                                 if (bone) {
2009                                                         if (select) {
2010                                                                 if ((bone->flag & BONE_UNSELECTABLE)==0) {
2011                                                                         bone->flag |= BONE_SELECTED;
2012                                                                         bone_selected=1;
2013 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 1);
2014                                                                 }
2015                                                         }
2016                                                         else {
2017                                                                 bArmature *arm= base->object->data;
2018                                                                 bone->flag &= ~BONE_SELECTED;
2019 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 0);
2020                                                                 if (arm->act_bone==bone)
2021                                                                         arm->act_bone= NULL;
2022                                                                 
2023                                                         }
2024                                                 }
2025                                         }
2026                                         else if (!bone_only) {
2027                                                 if (select)
2028                                                         ED_base_object_select(base, BA_SELECT);
2029                                                 else
2030                                                         ED_base_object_select(base, BA_DESELECT);
2031                                         }
2032
2033                                         col+=4; /* next color */
2034                                         hits--;
2035                                         if (hits==0) break;
2036                                 }
2037                         }
2038                         
2039                         if (bone_selected) {
2040                                 WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, base->object);
2041                         }
2042                 }
2043
2044                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, vc->scene);
2045
2046         }
2047         MEM_freeN(vbuffer);
2048
2049         return hits > 0 ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
2050 }
2051
2052 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
2053 {
2054         ViewContext vc;
2055         rcti rect;
2056         short extend;
2057         short select;
2058
2059         int ret= OPERATOR_CANCELLED;
2060
2061         view3d_operator_needs_opengl(C);
2062
2063         /* setup view context for argument to callbacks */
2064         view3d_set_viewcontext(C, &vc);
2065         
2066         select= (RNA_int_get(op->ptr, "gesture_mode")==GESTURE_MODAL_SELECT);
2067         rect.xmin= RNA_int_get(op->ptr, "xmin");
2068         rect.ymin= RNA_int_get(op->ptr, "ymin");
2069         rect.xmax= RNA_int_get(op->ptr, "xmax");
2070         rect.ymax= RNA_int_get(op->ptr, "ymax");
2071         extend = RNA_boolean_get(op->ptr, "extend");
2072
2073         if (vc.obedit) {
2074                 switch(vc.obedit->type) {
2075                 case OB_MESH:
2076                         vc.em= ((Mesh *)vc.obedit->data)->edit_btmesh;
2077                         ret= do_mesh_box_select(&vc, &rect, select, extend);
2078 //                      if (EM_texFaceCheck())
2079                         if (ret & OPERATOR_FINISHED) {
2080                                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
2081                         }
2082                         break;
2083                 case OB_CURVE:
2084                 case OB_SURF:
2085                         ret= do_nurbs_box_select(&vc, &rect, select, extend);
2086                         if (ret & OPERATOR_FINISHED) {
2087                                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
2088                         }
2089                         break;
2090                 case OB_MBALL:
2091                         ret= do_meta_box_select(&vc, &rect, select, extend);
2092                         if (ret & OPERATOR_FINISHED) {
2093                                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
2094                         }
2095                         break;
2096                 case OB_ARMATURE:
2097                         ret= do_armature_box_select(&vc, &rect, select, extend);
2098                         if (ret & OPERATOR_FINISHED) {
2099                                 WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, vc.obedit);
2100                         }
2101                         break;
2102                 case OB_LATTICE:
2103                         ret= do_lattice_box_select(&vc, &rect, select, extend);         
2104                         if (ret & OPERATOR_FINISHED) {
2105                                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
2106                         }
2107                         break;                  
2108                 default:
2109                         assert(!"border select on incorrect object type");
2110                 }
2111         }
2112         else {  /* no editmode, unified for bones and objects */
2113                 if (vc.obact && vc.obact->mode & OB_MODE_SCULPT) {
2114                         /* pass */
2115                 }
2116                 else if (vc.obact && paint_facesel_test(vc.obact)) {
2117                         ret= do_paintface_box_select(&vc, &rect, select, extend);
2118                 }
2119                 else if (vc.obact && paint_vertsel_test(vc.obact)) {
2120                         ret= do_paintvert_box_select(&vc, &rect, select, extend);
2121                 }
2122                 else if (vc.obact && vc.obact->mode & OB_MODE_PARTICLE_EDIT) {
2123                         ret= PE_border_select(C, &rect, select, extend);
2124                 }
2125                 else { /* object mode with none active */
2126                         ret= do_object_pose_box_select(C, &vc, &rect, select, extend);
2127                 }
2128         }
2129
2130         return ret;
2131
2132
2133
2134 /* *****************Selection Operators******************* */
2135
2136 /* ****** Border Select ****** */
2137 void VIEW3D_OT_select_border(wmOperatorType *ot)
2138 {
2139         /* identifiers */
2140         ot->name= "Border Select";
2141         ot->description= "Select items using border selection";
2142         ot->idname= "VIEW3D_OT_select_border";
2143         
2144         /* api callbacks */
2145         ot->invoke= WM_border_select_invoke;
2146         ot->exec= view3d_borderselect_exec;
2147         ot->modal= WM_border_select_modal;
2148         ot->poll= view3d_selectable_data;
2149         ot->cancel= WM_border_select_cancel;
2150         
2151         /* flags */
2152         ot->flag= OPTYPE_UNDO;
2153         
2154         /* rna */
2155         WM_operator_properties_gesture_border(ot, TRUE);
2156 }
2157
2158 /* much like facesel_face_pick()*/
2159 /* returns 0 if not found, otherwise 1 */
2160 static int vertsel_vert_pick(struct bContext *C, Mesh *me, const int mval[2], unsigned int *index, int size)
2161 {
2162         ViewContext vc;
2163         view3d_set_viewcontext(C, &vc);
2164
2165         if (!me || me->totvert==0)
2166                 return 0;
2167
2168         if (size > 0) {
2169                 /* sample rect to increase changes of selecting, so that when clicking
2170                    on an face in the backbuf, we can still select a vert */
2171
2172                 int dist;
2173                 *index = view3d_sample_backbuf_rect(&vc, mval, size, 1, me->totvert+1, &dist,0,NULL, NULL);
2174         }
2175         else {
2176                 /* sample only on the exact position */
2177                 *index = view3d_sample_backbuf(&vc, mval[0], mval[1]);
2178         }
2179
2180         if ((*index)<=0 || (*index)>(unsigned int)me->totvert)
2181                 return 0;
2182
2183         (*index)--;
2184         
2185         return 1;
2186 }
2187
2188 /* mouse selection in weight paint */
2189 /* gets called via generic mouse select operator */
2190 static int mouse_weight_paint_vertex_select(bContext *C, const int mval[2], short extend, Object *obact)
2191 {
2192         Mesh* me= obact->data; /* already checked for NULL */
2193         unsigned int index = 0;
2194         MVert *mv;
2195
2196         if (vertsel_vert_pick(C, me, mval, &index, 50)) {
2197                 mv = me->mvert+index;
2198                 if (extend) {
2199                         mv->flag ^= SELECT;
2200                 }
2201                 else {
2202                         paintvert_deselect_all_visible(obact, SEL_DESELECT, FALSE);
2203                         mv->flag |= SELECT;
2204                 }
2205                 paintvert_flush_flags(obact);
2206                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obact->data);
2207                 return 1;
2208         }
2209         return 0;
2210 }
2211
2212 /* ****** Mouse Select ****** */
2213
2214
2215 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
2216 {
2217         Object *obedit= CTX_data_edit_object(C);
2218         Object *obact= CTX_data_active_object(C);
2219         short extend= RNA_boolean_get(op->ptr, "extend");
2220         short center= RNA_boolean_get(op->ptr, "center");
2221         short enumerate= RNA_boolean_get(op->ptr, "enumerate");
2222         short object= RNA_boolean_get(op->ptr, "object");
2223         int     retval = 0;
2224
2225         view3d_operator_needs_opengl(C);
2226
2227         if (object) {
2228                 obedit= NULL;
2229                 obact= NULL;
2230
2231                 /* ack, this is incorrect but to do this correctly we would need an
2232                  * alternative editmode/objectmode keymap, this copies the functionality
2233                  * from 2.4x where Ctrl+Select in editmode does object select only */
2234                 center= FALSE;
2235         }
2236
2237         if (obedit && object==FALSE) {
2238                 if (obedit->type==OB_MESH)
2239                         retval = mouse_mesh(C, event->mval, extend);
2240                 else if (obedit->type==OB_ARMATURE)
2241                         retval = mouse_armature(C, event->mval, extend);
2242                 else if (obedit->type==OB_LATTICE)
2243                         retval = mouse_lattice(C, event->mval, extend);
2244                 else if (ELEM(obedit->type, OB_CURVE, OB_SURF))
2245                         retval = mouse_nurb(C, event->mval, extend);
2246                 else if (obedit->type==OB_MBALL)
2247                         retval = mouse_mball(C, event->mval, extend);
2248                         
2249         }
2250         else if (obact && obact->mode & OB_MODE_SCULPT)
2251                 return OPERATOR_CANCELLED;
2252         else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT)
2253                 return PE_mouse_particles(C, event->mval, extend);
2254         else if (obact && paint_facesel_test(obact))
2255                 retval = paintface_mouse_select(C, obact, event->mval, extend);
2256         else if (paint_vertsel_test(obact))
2257                 retval = mouse_weight_paint_vertex_select(C, event->mval, extend, obact);
2258         else
2259                 retval = mouse_select(C, event->mval, extend, center, enumerate);
2260
2261         /* passthrough allows tweaks
2262          * FINISHED to signal one operator worked
2263          * */
2264         if (retval)
2265                 return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED;
2266         else
2267                 return OPERATOR_PASS_THROUGH; /* nothing selected, just passthrough */
2268 }
2269
2270 void VIEW3D_OT_select(wmOperatorType *ot)
2271 {
2272         /* identifiers */
2273         ot->name= "Activate/Select";
2274         ot->description= "Activate/select item(s)";
2275         ot->idname= "VIEW3D_OT_select";
2276         
2277         /* api callbacks */
2278         ot->invoke= view3d_select_invoke;
2279         ot->poll= ED_operator_view3d_active;
2280         
2281         /* flags */
2282         ot->flag= OPTYPE_UNDO;
2283         
2284         /* properties */
2285         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first");
2286         RNA_def_boolean(ot->srna, "center", 0, "Center", "Use the object center when selecting, in editmode used to extend object selection");
2287         RNA_def_boolean(ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only)");
2288         RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (editmode only)");
2289 }
2290
2291
2292 /* -------------------- circle select --------------------------------------------- */
2293
2294 typedef struct CircleSelectUserData {
2295         ViewContext *vc;
2296         short select;
2297         int mval[2];
2298         float radius;
2299 } CircleSelectUserData;
2300
2301 static void mesh_circle_doSelectVert(void *userData, BMVert *eve, int x, int y, int UNUSED(index))
2302 {
2303         CircleSelectUserData *data = userData;
2304         int mx = x - data->mval[0], my = y - data->mval[1];
2305         float r = sqrt(mx*mx + my*my);
2306
2307         if (r<=data->radius) {
2308                 BM_elem_select_set(data->vc->em->bm, eve, data->select);
2309         }
2310 }
2311 static void mesh_circle_doSelectEdge(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int UNUSED(index))
2312 {
2313         CircleSelectUserData *data = userData;
2314
2315         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
2316                 BM_elem_select_set(data->vc->em->bm, eed, data->select);
2317         }
2318 }
2319 static void mesh_circle_doSelectFace(void *userData, BMFace *efa, int x, int y, int UNUSED(index))
2320 {
2321         CircleSelectUserData *data = userData;
2322         int mx = x - data->mval[0], my = y - data->mval[1];
2323         float r = sqrt(mx*mx + my*my);
2324         
2325         if (r<=data->radius) {
2326                 BM_elem_select_set(data->vc->em->bm, efa, data->select);
2327         }
2328 }
2329
2330 static void mesh_circle_select(ViewContext *vc, int select, const int mval[2], float rad)
2331 {
2332         ToolSettings *ts= vc->scene->toolsettings;
2333         int bbsel;
2334         CircleSelectUserData data;
2335         
2336         bbsel= EDBM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
2337         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
2338
2339         vc->em= ((Mesh *)vc->obedit->data)->edit_btmesh;
2340
2341         data.vc = vc;
2342         data.select = select;
2343         data.mval[0] = mval[0];
2344         data.mval[1] = mval[1];
2345         data.radius = rad;
2346
2347         if (ts->selectmode & SCE_SELECT_VERTEX) {
2348                 if (bbsel) {
2349                         EDBM_backbuf_checkAndSelectVerts(vc->em, select==LEFTMOUSE);
2350                 }
2351                 else {
2352                         mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, V3D_CLIP_TEST_RV3D_CLIPPING);
2353                 }
2354         }
2355
2356         if (ts->selectmode & SCE_SELECT_EDGE) {
2357                 if (bbsel) {
2358                         EDBM_backbuf_checkAndSelectEdges(vc->em, select==LEFTMOUSE);
2359                 }
2360                 else {
2361                         mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, V3D_CLIP_TEST_OFF);
2362                 }
2363         }
2364         
2365         if (ts->selectmode & SCE_SELECT_FACE) {
2366                 if (bbsel) {
2367                         EDBM_backbuf_checkAndSelectFaces(vc->em, select==LEFTMOUSE);
2368                 }
2369                 else {
2370                         mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data);
2371                 }
2372         }
2373
2374         EDBM_free_backbuf();
2375         EDBM_selectmode_flush(vc->em);
2376 }
2377
2378 static void paint_facesel_circle_select(ViewContext *vc, int select, const int mval[2], float rad)
2379 {
2380         Object *ob= vc->obact;
2381         Mesh *me = ob?ob->data:NULL;
2382         /* int bbsel; */ /* UNUSED */
2383
2384         if (me) {
2385                 bm_vertoffs= me->totpoly+1;     /* max index array */
2386
2387                 /* bbsel= */ /* UNUSED */ EDBM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
2388                 EDBM_backbuf_checkAndSelectTFaces(me, select==LEFTMOUSE);
2389                 EDBM_free_backbuf();
2390         }
2391 }
2392
2393
2394 static void paint_vertsel_circle_select(ViewContext *vc, int select, const int mval[2], float rad)
2395 {
2396         Object *ob= vc->obact;
2397         Mesh *me = ob?ob->data:NULL;
2398         /* int bbsel; */ /* UNUSED */
2399         /* CircleSelectUserData data = {NULL}; */ /* UNUSED */
2400         if (me) {
2401                 bm_vertoffs= me->totvert+1;     /* max index array */
2402
2403                 /* bbsel= */ /* UNUSED */ EDBM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0f));
2404                 EDBM_backbuf_checkAndSelectVerts_obmode(me, select==LEFTMOUSE);
2405                 EDBM_free_backbuf();
2406
2407                 paintvert_flush_flags(ob);
2408         }
2409 }
2410
2411
2412 static void nurbscurve_circle_doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
2413 {
2414         CircleSelectUserData *data = userData;
2415         int mx = x - data->mval[0], my = y - data->mval[1];
2416         float r = sqrt(mx*mx + my*my);
2417         Object *obedit= data->vc->obedit;
2418         Curve *cu= (Curve*)obedit->data;
2419
2420         if (r<=data->radius) {
2421                 if (bp) {
2422                         bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
2423
2424                         if (bp == cu->lastsel && !(bp->f1 & 1)) cu->lastsel = NULL;
2425                 }
2426                 else {
2427                         if (cu->drawflag & CU_HIDE_HANDLES) {
2428                                 /* can only be beztindex==0 here since handles are hidden */
2429                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
2430                         }
2431                         else {
2432                                 if (beztindex==0) {
2433                                         bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT);
2434                                 }
2435                                 else if (beztindex==1) {
2436                                         bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT);
2437                                 }
2438                                 else {
2439                                         bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT);
2440                                 }
2441                         }
2442
2443                         if (bezt == cu->lastsel && !(bezt->f2 & 1)) cu->lastsel = NULL;
2444                 }
2445         }
2446 }
2447 static void nurbscurve_circle_select(ViewContext *vc, int select, const int mval[2], float rad)
2448 {
2449         CircleSelectUserData data;
2450
2451         /* set vc-> edit data */
2452         
2453         data.select = select;
2454         data.mval[0] = mval[0];
2455         data.mval[1] = mval[1];
2456         data.radius = rad;
2457         data.vc = vc;
2458
2459         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
2460         nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data);
2461 }
2462
2463
2464 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, int x, int y)
2465 {
2466         CircleSelectUserData *data = userData;
2467         int mx = x - data->mval[0], my = y - data->mval[1];
2468         float r = sqrt(mx*mx + my*my);
2469
2470         if (r<=data->radius) {
2471                 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT);
2472         }
2473 }
2474 static void lattice_circle_select(ViewContext *vc, int select, const int mval[2], float rad)
2475 {
2476         CircleSelectUserData data;
2477
2478         /* set vc-> edit data */
2479         
2480         data.select = select;
2481         data.mval[0] = mval[0];
2482         data.mval[1] = mval[1];
2483         data.radius = rad;
2484
2485         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
2486         lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data);
2487 }
2488
2489
2490 // NOTE: pose-bone case is copied from editbone case...
2491 static short pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, int x, int y)
2492 {
2493         CircleSelectUserData *data = userData;
2494         int mx = x - data->mval[0], my = y - data->mval[1];
2495         float r = sqrt(mx*mx + my*my);
2496         
2497         if (r <= data->radius) {
2498                 if (data->select)
2499                         pchan->bone->flag |= BONE_SELECTED;
2500                 else
2501                         pchan->bone->flag &= ~BONE_SELECTED;
2502                 return 1;
2503         }
2504         return 0;
2505 }
2506 static void pose_circle_select(ViewContext *vc, int select, const int mval[2], float rad)
2507 {
2508         CircleSelectUserData data;
2509         bArmature *arm = vc->obact->data;
2510         bPose *pose = vc->obact->pose;
2511         bPoseChannel *pchan;
2512         int change= FALSE;
2513         
2514         /* set vc->edit data */
2515         data.select = select;
2516         data.mval[0] = mval[0];
2517         data.mval[1] = mval[1];
2518         data.radius = rad;
2519
2520         ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */
2521         
2522         /* check each PoseChannel... */
2523         // TODO: could be optimised at some point
2524         for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
2525                 short sco1[2], sco2[2], didpoint=0;
2526                 float vec[3];
2527                 
2528                 /* skip invisible bones */
2529                 if (PBONE_VISIBLE(arm, pchan->bone) == 0)
2530                         continue;
2531                 
2532                 /* project head location to screenspace */
2533                 mul_v3_m4v3(vec, vc->obact->obmat, pchan->pose_head);
2534                 project_short(vc->ar, vec, sco1);
2535                 
2536                 /* project tail location to screenspace */
2537                 mul_v3_m4v3(vec, vc->obact->obmat, pchan->pose_tail);
2538                 project_short(vc->ar, vec, sco2);
2539                 
2540                 /* check if the head and/or tail is in the circle 
2541                  *      - the call to check also does the selection already
2542                  */
2543                 if (pchan_circle_doSelectJoint(&data, pchan, sco1[0], sco1[1]))
2544                         didpoint= 1;
2545                 if (pchan_circle_doSelectJoint(&data, pchan, sco2[0], sco2[1]))
2546                         didpoint= 1;
2547                 
2548                 change |= didpoint;
2549         }
2550
2551         if (change) {
2552                 WM_main_add_notifier(NC_OBJECT|ND_BONE_SELECT, vc->obact);
2553         }
2554 }
2555
2556 static short armature_circle_doSelectJoint(void *userData, EditBone *ebone, int x, int y, short head)
2557 {
2558         CircleSelectUserData *data = userData;
2559         int mx = x - data->mval[0], my = y - data->mval[1];
2560         float r = sqrt(mx*mx + my*my);
2561         
2562         if (r <= data->radius) {
2563                 if (head) {
2564                         if (data->select)
2565                                 ebone->flag |= BONE_ROOTSEL;
2566                         else 
2567                                 ebone->flag &= ~BONE_ROOTSEL;
2568                 }
2569                 else {
2570                         if (data->select)
2571                                 ebone->flag |= BONE_TIPSEL;
2572                         else 
2573                                 ebone->flag &= ~BONE_TIPSEL;
2574                 }
2575                 return 1;
2576         }
2577         return 0;
2578 }
2579 static void armature_circle_select(ViewContext *vc, int select, const int mval[2], float rad)
2580 {
2581         CircleSelectUserData data;
2582         bArmature *arm= vc->obedit->data;
2583         EditBone *ebone;
2584         int change= FALSE;
2585         
2586         /* set vc->edit data */
2587         data.select = select;
2588         data.mval[0] = mval[0];
2589         data.mval[1] = mval[1];
2590         data.radius = rad;
2591
2592         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
2593         
2594         /* check each EditBone... */
2595         // TODO: could be optimised at some point
2596         for (ebone= arm->edbo->first; ebone; ebone=ebone->next) {
2597                 short sco1[2], sco2[2], didpoint=0;
2598                 float vec[3];
2599                 
2600                 /* project head location to screenspace */
2601                 mul_v3_m4v3(vec, vc->obedit->obmat, ebone->head);
2602                 project_short(vc->ar, vec, sco1);
2603                 
2604                 /* project tail location to screenspace */
2605                 mul_v3_m4v3(vec, vc->obedit->obmat, ebone->tail);
2606                 project_short(vc->ar, vec, sco2);
2607                 
2608                 /* check if the head and/or tail is in the circle 
2609                  *      - the call to check also does the selection already
2610                  */
2611                 if (armature_circle_doSelectJoint(&data, ebone, sco1[0], sco1[1], 1))
2612                         didpoint= 1;
2613                 if (armature_circle_doSelectJoint(&data, ebone, sco2[0], sco2[1], 0))
2614                         didpoint= 1;
2615                         
2616                 /* only if the endpoints didn't get selected, deal with the middle of the bone too */
2617                 // XXX should we just do this always?
2618                 if ( (didpoint==0) && edge_inside_circle(mval[0], mval[1], rad, sco1[0], sco1[1], sco2[0], sco2[1]) ) {
2619                         if (select) 
2620                                 ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
2621                         else 
2622                                 ebone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
2623                         change= TRUE;
2624                 }
2625                 
2626                 change |= didpoint;
2627         }
2628
2629         if (change) {
2630                 ED_armature_sync_selection(arm->edbo);
2631                 ED_armature_validate_active(arm);
2632                 WM_main_add_notifier(NC_OBJECT|ND_BONE_SELECT, vc->obedit);
2633         }
2634 }
2635
2636 /** Callbacks for circle selection in Editmode */
2637
2638 static void obedit_circle_select(ViewContext *vc, short select, const int mval[2], float rad)
2639 {
2640         switch(vc->obedit->type) {              
2641         case OB_MESH:
2642                 mesh_circle_select(vc, select, mval, rad);
2643                 break;
2644         case OB_CURVE:
2645         case OB_SURF:
2646                 nurbscurve_circle_select(vc, select, mval, rad);
2647                 break;
2648         case OB_LATTICE:
2649                 lattice_circle_select(vc, select, mval, rad);
2650                 break;
2651         case OB_ARMATURE:
2652                 armature_circle_select(vc, select, mval, rad);
2653                 break;
2654         default:
2655                 return;
2656         }
2657 }
2658
2659 /* not a real operator, only for circle test */
2660 static int view3d_circle_select_exec(bContext *C, wmOperator *op)
2661 {
2662         ScrArea *sa= CTX_wm_area(C);
2663         ARegion *ar= CTX_wm_region(C);
2664         Scene *scene= CTX_data_scene(C);
2665         Object *obact= CTX_data_active_object(C);
2666         View3D *v3d= sa->spacedata.first;
2667         int x= RNA_int_get(op->ptr, "x");
2668         int y= RNA_int_get(op->ptr, "y");
2669         int radius= RNA_int_get(op->ptr, "radius");
2670         int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
2671         int select;
2672         
2673         select= (gesture_mode==GESTURE_MODAL_SELECT);
2674
2675         if ( CTX_data_edit_object(C) || paint_facesel_test(obact) || paint_vertsel_test(obact) ||
2676                 (obact && (obact->mode & (OB_MODE_PARTICLE_EDIT|OB_MODE_POSE))) )
2677         {
2678                 ViewContext vc;
2679                 int mval[2];
2680                 
2681                 view3d_operator_needs_opengl(C);
2682                 
2683                 view3d_set_viewcontext(C, &vc);
2684                 mval[0]= x;
2685                 mval[1]= y;
2686
2687                 if (CTX_data_edit_object(C)) {
2688                         obedit_circle_select(&vc, select, mval, (float)radius);
2689                         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obact->data);
2690                 }
2691                 else if (paint_facesel_test(obact)) {
2692                         paint_facesel_circle_select(&vc, select, mval, (float)radius);
2693                         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obact->data);
2694                 }
2695                 else if (paint_vertsel_test(obact)) {
2696                         paint_vertsel_circle_select(&vc, select, mval, (float)radius);
2697                         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obact->data);
2698                 }
2699                 else if (obact->mode & OB_MODE_POSE)
2700                         pose_circle_select(&vc, select, mval, (float)radius);
2701                 else
2702                         return PE_circle_select(C, select, mval, (float)radius);
2703         }
2704         else if (obact && obact->mode & OB_MODE_SCULPT) {
2705                 return OPERATOR_CANCELLED;
2706         }
2707         else {
2708                 Base *base;
2709                 select= select?BA_SELECT:BA_DESELECT;
2710                 for (base= FIRSTBASE; base; base= base->next) {
2711                         if (BASE_SELECTABLE(v3d, base)) {
2712                                 project_short(ar, base->object->obmat[3], &base->sx);
2713                                 if (base->sx!=IS_CLIPPED) {
2714                                         int dx= base->sx-x;
2715                                         int dy= base->sy-y;
2716                                         if ( dx*dx + dy*dy < radius*radius)
2717                                                 ED_base_object_select(base, select);
2718                                 }
2719                         }
2720                 }
2721                 
2722                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
2723         }
2724         
2725         return OPERATOR_FINISHED;
2726 }
2727
2728 void VIEW3D_OT_select_circle(wmOperatorType *ot)
2729 {
2730         ot->name= "Circle Select";
2731         ot->description= "Select items using circle selection";
2732         ot->idname= "VIEW3D_OT_select_circle";
2733         
2734         ot->invoke= WM_gesture_circle_invoke;
2735         ot->modal= WM_gesture_circle_modal;
2736         ot->exec= view3d_circle_select_exec;
2737         ot->poll= view3d_selectable_data;
2738         ot->cancel= WM_gesture_circle_cancel;
2739         
2740         /* flags */
2741         ot->flag= OPTYPE_UNDO;
2742         
2743         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
2744         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
2745         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
2746         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2747 }