code cleanup: prefer BM_face/edge/vert_select_set() over BM_elem_select_set() when...
[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_check_and_select_verts(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_backbuf_check(index)) {
179                                 BM_vert_select_set(em->bm, eve, select);
180                         }
181                 }
182         }
183 }
184
185 static void edbm_backbuf_check_and_select_edges(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_backbuf_check(index)) {
195                                 BM_edge_select_set(em->bm, eed, select);
196                         }
197                 }
198         }
199 }
200
201 static void edbm_backbuf_check_and_select_faces(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_backbuf_check(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_check_and_select_verts_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_backbuf_check(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_check_and_select_tfaces(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_backbuf_check(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_vert_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_backbuf_check(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_edge_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_edge_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_face_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 = BMEdit_FromObject(vc->obedit);
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, don't change the GL state */
533         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
534
535         glLoadMatrixf(vc->rv3d->viewmat);
536         bbsel = EDBM_backbuf_border_mask_init(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_check_and_select_verts(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_check_and_select_faces(vc->em, select);
560                 }
561                 else {
562                         mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data);
563                 }
564         }
565         
566         EDBM_backbuf_free();
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) == 0) {
822                                 if (select) mvert->flag |=  SELECT;
823                                 else        mvert->flag &= ~SELECT;
824                         }
825                 }
826         }
827
828         IMB_freeImBuf(ibuf);
829         MEM_freeN(selar);
830
831 #ifdef __APPLE__        
832         glReadBuffer(GL_BACK);
833 #endif
834
835         paintvert_flush_flags(vc->obact);
836
837         return OPERATOR_FINISHED;
838 }
839
840 static void do_lasso_select_paintvert(ViewContext *vc, int mcords[][2], short moves, short extend, short select)
841 {
842         Object *ob = vc->obact;
843         Mesh *me = ob ? ob->data : NULL;
844         rcti rect;
845
846         if (me == NULL || me->totvert == 0)
847                 return;
848
849         if (extend == 0 && select)
850                 paintvert_deselect_all_visible(ob, SEL_DESELECT, FALSE);  /* flush selection at the end */
851         bm_vertoffs = me->totvert + 1; /* max index array */
852
853         lasso_select_boundbox(&rect, mcords, moves);
854         EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
855
856         edbm_backbuf_check_and_select_verts_obmode(me, select);
857
858         EDBM_backbuf_free();
859
860         paintvert_flush_flags(ob);
861 }
862 static void do_lasso_select_paintface(ViewContext *vc, int mcords[][2], short moves, short extend, short select)
863 {
864         Object *ob = vc->obact;
865         Mesh *me = ob ? ob->data : NULL;
866         rcti rect;
867
868         if (me == NULL || me->totpoly == 0)
869                 return;
870
871         if (extend == 0 && select)
872                 paintface_deselect_all_visible(ob, SEL_DESELECT, FALSE);  /* flush selection at the end */
873
874         bm_vertoffs = me->totpoly + 1; /* max index array */
875
876         lasso_select_boundbox(&rect, mcords, moves);
877         EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
878         
879         edbm_backbuf_check_and_select_tfaces(me, select);
880
881         EDBM_backbuf_free();
882
883         paintface_flush_flags(ob);
884 }
885
886 #if 0
887 static void do_lasso_select_node(int mcords[][2], short moves, short select)
888 {
889         SpaceNode *snode = sa->spacedata.first;
890         
891         bNode *node;
892         rcti rect;
893         short node_cent[2];
894         float node_centf[2];
895         
896         lasso_select_boundbox(&rect, mcords, moves);
897         
898         /* store selection in temp test flag */
899         for (node = snode->edittree->nodes.first; node; node = node->next) {
900                 
901                 node_centf[0] = (node->totr.xmin + node->totr.xmax) / 2;
902                 node_centf[1] = (node->totr.ymin + node->totr.ymax) / 2;
903                 
904                 ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
905                 if (BLI_in_rcti(&rect, node_cent[0], node_cent[1]) && lasso_inside(mcords, moves, node_cent[0], node_cent[1])) {
906                         if (select) {
907                                 node->flag |= SELECT;
908                         }
909                         else {
910                                 node->flag &= ~SELECT;
911                         }
912                 }
913         }
914         BIF_undo_push("Lasso select nodes");
915 }
916 #endif
917
918 static void view3d_lasso_select(bContext *C, ViewContext *vc, int mcords[][2], short moves, short extend, short select)
919 {
920         Object *ob = CTX_data_active_object(C);
921
922         if (vc->obedit == NULL) { /* Object Mode */
923                 if (paint_facesel_test(ob))
924                         do_lasso_select_paintface(vc, mcords, moves, extend, select);
925                 else if (paint_vertsel_test(ob))
926                         do_lasso_select_paintvert(vc, mcords, moves, extend, select);
927                 else if (ob && ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))
928                         ;
929                 else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT)
930                         PE_lasso_select(C, mcords, moves, extend, select);
931                 else {
932                         do_lasso_select_objects(vc, mcords, moves, extend, select);
933                         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene);
934                 }
935         }
936         else { /* Edit Mode */
937                 switch (vc->obedit->type) {
938                         case OB_MESH:
939                                 do_lasso_select_mesh(vc, mcords, moves, extend, select);
940                                 break;
941                         case OB_CURVE:
942                         case OB_SURF:
943                                 do_lasso_select_curve(vc, mcords, moves, extend, select);
944                                 break;
945                         case OB_LATTICE:
946                                 do_lasso_select_lattice(vc, mcords, moves, extend, select);
947                                 break;
948                         case OB_ARMATURE:
949                                 do_lasso_select_armature(vc, mcords, moves, extend, select);
950                                 break;
951                         case OB_MBALL:
952                                 do_lasso_select_meta(vc, mcords, moves, extend, select);
953                                 break;
954                         default:
955                                 assert(!"lasso select on incorrect object type");
956                 }
957
958                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc->obedit->data);
959         }
960 }
961
962
963 /* lasso operator gives properties, but since old code works
964  * with short array we convert */
965 static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
966 {
967         ViewContext vc;
968         int i = 0;
969         int mcords[1024][2];
970
971         RNA_BEGIN(op->ptr, itemptr, "path") {
972                 float loc[2];
973                 
974                 RNA_float_get_array(&itemptr, "loc", loc);
975                 mcords[i][0] = (int)loc[0];
976                 mcords[i][1] = (int)loc[1];
977                 i++;
978                 if (i >= 1024) break;
979         }
980         RNA_END;
981         
982         if (i > 1) {
983                 short extend, select;
984                 view3d_operator_needs_opengl(C);
985                 
986                 /* setup view context for argument to callbacks */
987                 view3d_set_viewcontext(C, &vc);
988                 
989                 extend = RNA_boolean_get(op->ptr, "extend");
990                 select = !RNA_boolean_get(op->ptr, "deselect");
991                 view3d_lasso_select(C, &vc, mcords, i, extend, select);
992                 
993                 return OPERATOR_FINISHED;
994         }
995         return OPERATOR_PASS_THROUGH;
996 }
997
998 void VIEW3D_OT_select_lasso(wmOperatorType *ot)
999 {
1000         ot->name = "Lasso Select";
1001         ot->description = "Select items using lasso selection";
1002         ot->idname = "VIEW3D_OT_select_lasso";
1003         
1004         ot->invoke = WM_gesture_lasso_invoke;
1005         ot->modal = WM_gesture_lasso_modal;
1006         ot->exec = view3d_lasso_select_exec;
1007         ot->poll = view3d_selectable_data;
1008         ot->cancel = WM_gesture_lasso_cancel;
1009         
1010         /* flags */
1011         ot->flag = OPTYPE_UNDO;
1012         
1013         RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
1014         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items");
1015         RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection instead of deselecting everything first");
1016 }
1017
1018
1019 /* ************************************************* */
1020
1021 #if 0
1022 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
1023 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
1024 {
1025         Base *base;
1026         unsigned int *bufmin, *bufmax;
1027         int a, b, rc, tel, len, dirvec[4][2], maxob;
1028         unsigned int retval = 0;
1029         
1030         base = LASTBASE;
1031         if (base == 0) return 0;
1032         maxob = base->selcol;
1033
1034         len = (size - 1) / 2;
1035         rc = 0;
1036
1037         dirvec[0][0] = 1;
1038         dirvec[0][1] = 0;
1039         dirvec[1][0] = 0;
1040         dirvec[1][1] = -size;
1041         dirvec[2][0] = -1;
1042         dirvec[2][1] = 0;
1043         dirvec[3][0] = 0;
1044         dirvec[3][1] = size;
1045
1046         bufmin = buf;
1047         bufmax = buf + size * size;
1048         buf += len * size + len;
1049
1050         for (tel = 1; tel <= size; tel++) {
1051
1052                 for (a = 0; a < 2; a++) {
1053                         for (b = 0; b < tel; b++) {
1054
1055                                 if (*buf && *buf <= maxob && *buf != dontdo) return *buf;
1056                                 if (*buf == dontdo) retval = dontdo;  /* if only color dontdo is available, still return dontdo */
1057                                 
1058                                 buf += (dirvec[rc][0] + dirvec[rc][1]);
1059
1060                                 if (buf < bufmin || buf >= bufmax) return retval;
1061                         }
1062                         rc++;
1063                         rc &= 3;
1064                 }
1065         }
1066         return retval;
1067 }
1068 #endif
1069
1070 /* ************************** mouse select ************************* */
1071
1072
1073 /* The max number of menu items in an object select menu */
1074 typedef struct SelMenuItemF {
1075         char idname[MAX_ID_NAME - 2];
1076         int icon;
1077 } SelMenuItemF;
1078
1079 #define SEL_MENU_SIZE   22
1080 static SelMenuItemF object_mouse_select_menu_data[SEL_MENU_SIZE];
1081
1082 /* special (crappy) operator only for menu select */
1083 static EnumPropertyItem *object_select_menu_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
1084 {
1085         EnumPropertyItem *item = NULL, item_tmp = {0};
1086         int totitem = 0;
1087         int i = 0;
1088
1089         /* don't need context but avoid docgen using this */
1090         if (C == NULL || object_mouse_select_menu_data[i].idname[0] == '\0') {
1091                 return DummyRNA_NULL_items;
1092         }
1093
1094         for (; i < SEL_MENU_SIZE && object_mouse_select_menu_data[i].idname[0] != '\0'; i++) {
1095                 item_tmp.name = object_mouse_select_menu_data[i].idname;
1096                 item_tmp.identifier = object_mouse_select_menu_data[i].idname;
1097                 item_tmp.value = i;
1098                 item_tmp.icon = object_mouse_select_menu_data[i].icon;
1099                 RNA_enum_item_add(&item, &totitem, &item_tmp);
1100         }
1101
1102         RNA_enum_item_end(&item, &totitem);
1103         *free = 1;
1104
1105         return item;
1106 }
1107
1108 static int object_select_menu_exec(bContext *C, wmOperator *op)
1109 {
1110         int name_index = RNA_enum_get(op->ptr, "name");
1111         short extend = RNA_boolean_get(op->ptr, "extend");
1112         short changed = 0;
1113         const char *name = object_mouse_select_menu_data[name_index].idname;
1114
1115         if (!extend) {
1116                 CTX_DATA_BEGIN(C, Base *, base, selectable_bases) {
1117                         if (base->flag & SELECT) {
1118                                 ED_base_object_select(base, BA_DESELECT);
1119                                 changed = 1;
1120                         }
1121                 }
1122                 CTX_DATA_END;
1123         }
1124
1125         CTX_DATA_BEGIN(C, Base *, base, selectable_bases) {
1126                 /* this is a bit dodjy, there should only be ONE object with this name, but library objects can mess this up */
1127                 if (strcmp(name, base->object->id.name + 2) == 0) {
1128                         ED_base_object_activate(C, base);
1129                         ED_base_object_select(base, BA_SELECT);
1130                         changed = 1;
1131                 }
1132         }
1133         CTX_DATA_END;
1134
1135         /* weak but ensures we activate menu again before using the enum */
1136         memset(object_mouse_select_menu_data, 0, sizeof(object_mouse_select_menu_data));
1137
1138         /* undo? */
1139         if (changed) {
1140                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
1141                 return OPERATOR_FINISHED;
1142         }
1143         else {
1144                 return OPERATOR_CANCELLED;
1145         }
1146 }
1147
1148 void VIEW3D_OT_select_menu(wmOperatorType *ot)
1149 {
1150         PropertyRNA *prop;
1151
1152         /* identifiers */
1153         ot->name = "Select Menu";
1154         ot->description = "Menu object selection";
1155         ot->idname = "VIEW3D_OT_select_menu";
1156
1157         /* api callbacks */
1158         ot->invoke = WM_menu_invoke;
1159         ot->exec = object_select_menu_exec;
1160
1161         /* flags */
1162         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1163
1164         /* keyingset to use (dynamic enum) */
1165         prop = RNA_def_enum(ot->srna, "name", DummyRNA_NULL_items, 0, "Object Name", "");
1166         RNA_def_enum_funcs(prop, object_select_menu_enum_itemf);
1167         RNA_def_property_flag(prop, PROP_HIDDEN);
1168         ot->prop = prop;
1169
1170         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first");
1171 }
1172
1173 static void deselectall_except(Scene *scene, Base *b)   /* deselect all except b */
1174 {
1175         Base *base;
1176         
1177         for (base = FIRSTBASE; base; base = base->next) {
1178                 if (base->flag & SELECT) {
1179                         if (b != base) {
1180                                 ED_base_object_select(base, BA_DESELECT);
1181                         }
1182                 }
1183         }
1184 }
1185
1186 static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int *buffer, int hits, const int mval[2], short extend)
1187 {
1188         short baseCount = 0;
1189         short ok;
1190         LinkNode *linklist = NULL;
1191         
1192         CTX_DATA_BEGIN(C, Base *, base, selectable_bases) {
1193                 ok = FALSE;
1194
1195                 /* two selection methods, the CTRL select uses max dist of 15 */
1196                 if (buffer) {
1197                         int a;
1198                         for (a = 0; a < hits; a++) {
1199                                 /* index was converted */
1200                                 if (base->selcol == buffer[(4 * a) + 3])
1201                                         ok = TRUE;
1202                         }
1203                 }
1204                 else {
1205                         int temp, dist = 15;
1206
1207                         project_short(vc->ar, base->object->obmat[3], &base->sx);
1208                         
1209                         temp = abs(base->sx - mval[0]) + abs(base->sy - mval[1]);
1210                         if (temp < dist)
1211                                 ok = TRUE;
1212                 }
1213
1214                 if (ok) {
1215                         baseCount++;
1216                         BLI_linklist_prepend(&linklist, base);
1217
1218                         if (baseCount == SEL_MENU_SIZE)
1219                                 break;
1220                 }
1221         }
1222         CTX_DATA_END;
1223
1224         if (baseCount == 0) {
1225                 return NULL;
1226         }
1227         if (baseCount == 1) {
1228                 Base *base = (Base *)linklist->link;
1229                 BLI_linklist_free(linklist, NULL);
1230                 return base;
1231         }
1232         else {
1233                 /* UI, full in static array values that we later use in an enum function */
1234                 LinkNode *node;
1235                 int i;
1236
1237                 memset(object_mouse_select_menu_data, 0, sizeof(object_mouse_select_menu_data));
1238
1239                 for (node = linklist, i = 0; node; node = node->next, i++) {
1240                         Base *base = node->link;
1241                         Object *ob = base->object;
1242                         char *name = ob->id.name + 2;
1243
1244                         BLI_strncpy(object_mouse_select_menu_data[i].idname, name, MAX_ID_NAME - 2);
1245                         object_mouse_select_menu_data[i].icon = uiIconFromID(&ob->id);
1246                 }
1247
1248                 {
1249                         PointerRNA ptr;
1250
1251                         WM_operator_properties_create(&ptr, "VIEW3D_OT_select_menu");
1252                         RNA_boolean_set(&ptr, "extend", extend);
1253                         WM_operator_name_call(C, "VIEW3D_OT_select_menu", WM_OP_INVOKE_DEFAULT, &ptr);
1254                         WM_operator_properties_free(&ptr);
1255                 }
1256
1257                 BLI_linklist_free(linklist, NULL);
1258                 return NULL;
1259         }
1260 }
1261
1262 /* we want a select buffer with bones, if there are... */
1263 /* so check three selection levels and compare */
1264 static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, const int mval[2])
1265 {
1266         rcti rect;
1267         int offs;
1268         short a, hits15, hits9 = 0, hits5 = 0;
1269         short has_bones15 = 0, has_bones9 = 0, has_bones5 = 0;
1270         
1271         BLI_init_rcti(&rect, mval[0] - 14, mval[0] + 14, mval[1] - 14, mval[1] + 14);
1272         hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
1273         if (hits15 > 0) {
1274                 for (a = 0; a < hits15; a++) if (buffer[4 * a + 3] & 0xFFFF0000) has_bones15 = 1;
1275
1276                 offs = 4 * hits15;
1277                 BLI_init_rcti(&rect, mval[0] - 9, mval[0] + 9, mval[1] - 9, mval[1] + 9);
1278                 hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect);
1279                 if (hits9 > 0) {
1280                         for (a = 0; a < hits9; a++) if (buffer[offs + 4 * a + 3] & 0xFFFF0000) has_bones9 = 1;
1281
1282                         offs += 4 * hits9;
1283                         BLI_init_rcti(&rect, mval[0] - 5, mval[0] + 5, mval[1] - 5, mval[1] + 5);
1284                         hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect);
1285                         if (hits5 > 0) {
1286                                 for (a = 0; a < hits5; a++) if (buffer[offs + 4 * a + 3] & 0xFFFF0000) has_bones5 = 1;
1287                         }
1288                 }
1289                 
1290                 if (has_bones5) {
1291                         offs = 4 * hits15 + 4 * hits9;
1292                         memcpy(buffer, buffer + offs, 4 * offs);
1293                         return hits5;
1294                 }
1295                 if (has_bones9) {
1296                         offs = 4 * hits15;
1297                         memcpy(buffer, buffer + offs, 4 * offs);
1298                         return hits9;
1299                 }
1300                 if (has_bones15) {
1301                         return hits15;
1302                 }
1303                 
1304                 if (hits5 > 0) {
1305                         offs = 4 * hits15 + 4 * hits9;
1306                         memcpy(buffer, buffer + offs, 4 * offs);
1307                         return hits5;
1308                 }
1309                 if (hits9 > 0) {
1310                         offs = 4 * hits15;
1311                         memcpy(buffer, buffer + offs, 4 * offs);
1312                         return hits9;
1313                 }
1314                 return hits15;
1315         }
1316         
1317         return 0;
1318 }
1319
1320 /* returns basact */
1321 static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits, const int mval[2], Base *startbase, int has_bones)
1322 {
1323         Scene *scene = vc->scene;
1324         View3D *v3d = vc->v3d;
1325         Base *base, *basact = NULL;
1326         static int lastmval[2] = {-100, -100};
1327         int a, donearest = 0;
1328         
1329         /* define if we use solid nearest select or not */
1330         if (v3d->drawtype > OB_WIRE) {
1331                 donearest = 1;
1332                 if (ABS(mval[0] - lastmval[0]) < 3 && ABS(mval[1] - lastmval[1]) < 3) {
1333                         if (!has_bones) /* hrms, if theres bones we always do nearest */
1334                                 donearest = 0;
1335                 }
1336         }
1337         lastmval[0] = mval[0]; lastmval[1] = mval[1];
1338         
1339         if (donearest) {
1340                 unsigned int min = 0xFFFFFFFF;
1341                 int selcol = 0, notcol = 0;
1342                 
1343                 
1344                 if (has_bones) {
1345                         /* we skip non-bone hits */
1346                         for (a = 0; a < hits; a++) {
1347                                 if (min > buffer[4 * a + 1] && (buffer[4 * a + 3] & 0xFFFF0000) ) {
1348                                         min = buffer[4 * a + 1];
1349                                         selcol = buffer[4 * a + 3] & 0xFFFF;
1350                                 }
1351                         }
1352                 }
1353                 else {
1354                         /* only exclude active object when it is selected... */
1355                         if (BASACT && (BASACT->flag & SELECT) && hits > 1) notcol = BASACT->selcol;
1356                         
1357                         for (a = 0; a < hits; a++) {
1358                                 if (min > buffer[4 * a + 1] && notcol != (buffer[4 * a + 3] & 0xFFFF)) {
1359                                         min = buffer[4 * a + 1];
1360                                         selcol = buffer[4 * a + 3] & 0xFFFF;
1361                                 }
1362                         }
1363                 }
1364                 
1365                 base = FIRSTBASE;
1366                 while (base) {
1367                         if (BASE_SELECTABLE(v3d, base)) {
1368                                 if (base->selcol == selcol) break;
1369                         }
1370                         base = base->next;
1371                 }
1372                 if (base) basact = base;
1373         }
1374         else {
1375                 
1376                 base = startbase;
1377                 while (base) {
1378                         /* skip objects with select restriction, to prevent prematurely ending this loop
1379                          * with an un-selectable choice */
1380                         if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1381                                 base = base->next;
1382                                 if (base == NULL) base = FIRSTBASE;
1383                                 if (base == startbase) break;
1384                         }
1385                         
1386                         if (BASE_SELECTABLE(v3d, base)) {
1387                                 for (a = 0; a < hits; a++) {
1388                                         if (has_bones) {
1389                                                 /* skip non-bone objects */
1390                                                 if ((buffer[4 * a + 3] & 0xFFFF0000)) {
1391                                                         if (base->selcol == (buffer[(4 * a) + 3] & 0xFFFF))
1392                                                                 basact = base;
1393                                                 }
1394                                         }
1395                                         else {
1396                                                 if (base->selcol == (buffer[(4 * a) + 3] & 0xFFFF))
1397                                                         basact = base;
1398                                         }
1399                                 }
1400                         }
1401                         
1402                         if (basact) break;
1403                         
1404                         base = base->next;
1405                         if (base == NULL) base = FIRSTBASE;
1406                         if (base == startbase) break;
1407                 }
1408         }
1409         
1410         return basact;
1411 }
1412
1413 /* mval comes from event->mval, only use within region handlers */
1414 Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
1415 {
1416         ViewContext vc;
1417         Base *basact = NULL;
1418         unsigned int buffer[4 * MAXPICKBUF];
1419         int hits;
1420         
1421         /* setup view context for argument to callbacks */
1422         view3d_operator_needs_opengl(C);
1423         view3d_set_viewcontext(C, &vc);
1424         
1425         hits = mixed_bones_object_selectbuffer(&vc, buffer, mval);
1426         
1427         if (hits > 0) {
1428                 int a, has_bones = 0;
1429                 
1430                 for (a = 0; a < hits; a++) if (buffer[4 * a + 3] & 0xFFFF0000) has_bones = 1;
1431                 
1432                 basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, vc.scene->base.first, has_bones);
1433         }
1434         
1435         return basact;
1436 }
1437
1438 static void deselect_all_tracks(MovieTracking *tracking)
1439 {
1440         MovieTrackingObject *object;
1441
1442         object = tracking->objects.first;
1443         while (object) {
1444                 ListBase *tracksbase = BKE_tracking_object_tracks(tracking, object);
1445                 MovieTrackingTrack *track = tracksbase->first;
1446
1447                 while (track) {
1448                         BKE_tracking_deselect_track(track, TRACK_AREA_ALL);
1449
1450                         track = track->next;
1451                 }
1452
1453                 object = object->next;
1454         }
1455 }
1456
1457 /* mval is region coords */
1458 static int mouse_select(bContext *C, const int mval[2], short extend, short obcenter, short enumerate)
1459 {
1460         ViewContext vc;
1461         ARegion *ar = CTX_wm_region(C);
1462         View3D *v3d = CTX_wm_view3d(C);
1463         Scene *scene = CTX_data_scene(C);
1464         Base *base, *startbase = NULL, *basact = NULL, *oldbasact = NULL;
1465         int temp, a, dist = 100;
1466         int retval = 0;
1467         short hits;
1468         
1469         /* setup view context for argument to callbacks */
1470         view3d_set_viewcontext(C, &vc);
1471         
1472         /* always start list from basact in wire mode */
1473         startbase =  FIRSTBASE;
1474         if (BASACT && BASACT->next) startbase = BASACT->next;
1475         
1476         /* This block uses the control key to make the object selected by its center point rather than its contents */
1477         /* in editmode do not activate */
1478         if (obcenter) {
1479                 
1480                 /* note; shift+alt goes to group-flush-selecting */
1481                 if (enumerate) {
1482                         basact = object_mouse_select_menu(C, &vc, NULL, 0, mval, extend);
1483                 }
1484                 else {
1485                         base = startbase;
1486                         while (base) {
1487                                 if (BASE_SELECTABLE(v3d, base)) {
1488                                         project_short(ar, base->object->obmat[3], &base->sx);
1489                                         
1490                                         temp = abs(base->sx - mval[0]) + abs(base->sy - mval[1]);
1491                                         if (base == BASACT) temp += 10;
1492                                         if (temp < dist) {
1493                                                 
1494                                                 dist = temp;
1495                                                 basact = base;
1496                                         }
1497                                 }
1498                                 base = base->next;
1499                                 
1500                                 if (base == NULL) base = FIRSTBASE;
1501                                 if (base == startbase) break;
1502                         }
1503                 }
1504         }
1505         else {
1506                 unsigned int buffer[4 * MAXPICKBUF];
1507
1508                 /* if objects have posemode set, the bones are in the same selection buffer */
1509                 
1510                 hits = mixed_bones_object_selectbuffer(&vc, buffer, mval);
1511                 
1512                 if (hits > 0) {
1513                         int has_bones = 0;
1514                         
1515                         /* note: bundles are handling in the same way as bones */
1516                         for (a = 0; a < hits; a++) if (buffer[4 * a + 3] & 0xFFFF0000) has_bones = 1;
1517
1518                         /* note; shift+alt goes to group-flush-selecting */
1519                         if (has_bones == 0 && enumerate) {
1520                                 basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, extend);
1521                         }
1522                         else {
1523                                 basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, startbase, has_bones);
1524                         }
1525                         
1526                         if (has_bones && basact) {
1527                                 if (basact->object->type == OB_CAMERA) {
1528                                         if (BASACT == basact) {
1529                                                 int i, hitresult;
1530                                                 int changed = 0;
1531
1532                                                 for (i = 0; i < hits; i++) {
1533                                                         hitresult = buffer[3 + (i * 4)];
1534
1535                                                         /* if there's bundles in buffer select bundles first,
1536                                                          * so non-camera elements should be ignored in buffer */
1537                                                         if (basact->selcol != (hitresult & 0xFFFF)) {
1538                                                                 continue;
1539                                                         }
1540
1541                                                         /* index of bundle is 1<<16-based. if there's no "bone" index
1542                                                          * in hight word, this buffer value belongs to camera,. not to bundle */
1543                                                         if (buffer[4 * i + 3] & 0xFFFF0000) {
1544                                                                 MovieClip *clip = object_get_movieclip(scene, basact->object, 0);
1545                                                                 MovieTracking *tracking = &clip->tracking;
1546                                                                 ListBase *tracksbase;
1547                                                                 MovieTrackingTrack *track;
1548
1549                                                                 track = BKE_tracking_indexed_track(&clip->tracking, hitresult >> 16, &tracksbase);
1550
1551                                                                 if (TRACK_SELECTED(track) && extend) {
1552                                                                         changed = 0;
1553                                                                         BKE_tracking_deselect_track(track, TRACK_AREA_ALL);
1554                                                                 }
1555                                                                 else {
1556                                                                         int oldsel = TRACK_SELECTED(track) ? 1 : 0;
1557                                                                         if (!extend)
1558                                                                                 deselect_all_tracks(tracking);
1559
1560                                                                         BKE_tracking_select_track(tracksbase, track, TRACK_AREA_ALL, extend);
1561
1562                                                                         if (oldsel != (TRACK_SELECTED(track) ? 1 : 0))
1563                                                                                 changed = 1;
1564                                                                 }
1565
1566                                                                 basact->flag |= SELECT;
1567                                                                 basact->object->flag = basact->flag;
1568
1569                                                                 retval = 1;
1570
1571                                                                 WM_event_add_notifier(C, NC_MOVIECLIP | ND_SELECT, track);
1572                                                                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
1573
1574                                                                 break;
1575                                                         }
1576                                                 }
1577
1578                                                 if (!changed) {
1579                                                         /* fallback to regular object selection if no new bundles were selected,
1580                                                          * allows to select object parented to reconstruction object */
1581                                                         basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, startbase, 0);
1582                                                 }
1583                                         }
1584                                 }
1585                                 else if (ED_do_pose_selectbuffer(scene, basact, buffer, hits, extend) ) {   /* then bone is found */
1586                                 
1587                                         /* we make the armature selected: 
1588                                          * not-selected active object in posemode won't work well for tools */
1589                                         basact->flag |= SELECT;
1590                                         basact->object->flag = basact->flag;
1591                                         
1592                                         retval = 1;
1593                                         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
1594                                         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, basact->object);
1595                                         
1596                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1597                                         if (BASACT && (BASACT->object->mode & OB_MODE_WEIGHT_PAINT)) {
1598                                                 /* prevent activating */
1599                                                 basact = NULL;
1600                                         }
1601
1602                                 }
1603                                 /* prevent bone selecting to pass on to object selecting */
1604                                 if (basact == BASACT)
1605                                         basact = NULL;
1606                         }
1607                 }
1608         }
1609         
1610         /* so, do we have something selected? */
1611         if (basact) {
1612                 retval = 1;
1613                 
1614                 if (vc.obedit) {
1615                         /* only do select */
1616                         deselectall_except(scene, basact);
1617                         ED_base_object_select(basact, BA_SELECT);
1618                 }
1619                 /* also prevent making it active on mouse selection */
1620                 else if (BASE_SELECTABLE(v3d, basact)) {
1621
1622                         oldbasact = BASACT;
1623                         
1624                         if (!extend) {
1625                                 deselectall_except(scene, basact);
1626                                 ED_base_object_select(basact, BA_SELECT);
1627                         }
1628                         else if (0) {
1629                                 // XXX select_all_from_groups(basact);
1630                         }
1631                         else {
1632                                 if (basact->flag & SELECT) {
1633                                         if (basact == oldbasact)
1634                                                 ED_base_object_select(basact, BA_DESELECT);
1635                                 }
1636                                 else ED_base_object_select(basact, BA_SELECT);
1637                         }
1638
1639                         if (oldbasact != basact) {
1640                                 ED_base_object_activate(C, basact); /* adds notifier */
1641                         }
1642                 }
1643
1644                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
1645         }
1646
1647         return retval;
1648 }
1649
1650 /* ********************  border and circle ************************************** */
1651
1652 typedef struct BoxSelectUserData {
1653         ViewContext *vc;
1654         rcti *rect;
1655         int select, pass, done;
1656 } BoxSelectUserData;
1657
1658 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1659 {
1660         int radsq = rad * rad;
1661         float v1[2], v2[2], v3[2];
1662         
1663         /* check points in circle itself */
1664         if ( (x1 - centx) * (x1 - centx) + (y1 - centy) * (y1 - centy) <= radsq) return 1;
1665         if ( (x2 - centx) * (x2 - centx) + (y2 - centy) * (y2 - centy) <= radsq) return 1;
1666         
1667         /* pointdistline */
1668         v3[0] = centx;
1669         v3[1] = centy;
1670         v1[0] = x1;
1671         v1[1] = y1;
1672         v2[0] = x2;
1673         v2[1] = y2;
1674         
1675         if (dist_to_line_segment_v2(v3, v1, v2) < (float)rad) return 1;
1676         
1677         return 0;
1678 }
1679
1680 static void do_nurbs_box_select__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1681 {
1682         BoxSelectUserData *data = userData;
1683         Object *obedit = data->vc->obedit;
1684         Curve *cu = (Curve *)obedit->data;
1685
1686         if (BLI_in_rcti(data->rect, x, y)) {
1687                 if (bp) {
1688                         bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
1689                         if (bp == cu->lastsel && !(bp->f1 & 1)) cu->lastsel = NULL;
1690                 }
1691                 else {
1692                         if (cu->drawflag & CU_HIDE_HANDLES) {
1693                                 /* can only be beztindex==0 here since handles are hidden */
1694                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
1695                         }
1696                         else {
1697                                 if (beztindex == 0) {
1698                                         bezt->f1 = data->select ? (bezt->f1 | SELECT) : (bezt->f1 & ~SELECT);
1699                                 }
1700                                 else if (beztindex == 1) {
1701                                         bezt->f2 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
1702                                 }
1703                                 else {
1704                                         bezt->f3 = data->select ? (bezt->f3 | SELECT) : (bezt->f3 & ~SELECT);
1705                                 }
1706                         }
1707
1708                         if (bezt == cu->lastsel && !(bezt->f2 & 1)) cu->lastsel = NULL;
1709                 }
1710         }
1711 }
1712 static int do_nurbs_box_select(ViewContext *vc, rcti *rect, int select, int extend)
1713 {
1714         BoxSelectUserData data;
1715         
1716         data.vc = vc;
1717         data.rect = rect;
1718         data.select = select;
1719
1720         if (extend == 0 && select)
1721                 CU_deselect_all(vc->obedit);
1722
1723         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1724         nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data);
1725
1726         return OPERATOR_FINISHED;
1727 }
1728
1729 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1730 {
1731         BoxSelectUserData *data = userData;
1732
1733         if (BLI_in_rcti(data->rect, x, y)) {
1734                 bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
1735         }
1736 }
1737 static int do_lattice_box_select(ViewContext *vc, rcti *rect, int select, int extend)
1738 {
1739         BoxSelectUserData data;
1740
1741         data.vc = vc;
1742         data.rect = rect;
1743         data.select = select;
1744
1745         if (extend == 0 && select)
1746                 ED_setflagsLatt(vc->obedit, 0);
1747
1748         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
1749         lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data);
1750         
1751         return OPERATOR_FINISHED;
1752 }
1753
1754 static void do_mesh_box_select__doSelectVert(void *userData, BMVert *eve, int x, int y, int UNUSED(index))
1755 {
1756         BoxSelectUserData *data = userData;
1757
1758         if (BLI_in_rcti(data->rect, x, y)) {
1759                 BM_vert_select_set(data->vc->em->bm, eve, data->select);
1760         }
1761 }
1762 static void do_mesh_box_select__doSelectEdge(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index)
1763 {
1764         BoxSelectUserData *data = userData;
1765
1766         if (EDBM_backbuf_check(bm_solidoffs + index)) {
1767                 if (data->pass == 0) {
1768                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1769                                 BM_edge_select_set(data->vc->em->bm, eed, data->select);
1770                                 data->done = 1;
1771                         }
1772                 }
1773                 else {
1774                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1775                                 BM_edge_select_set(data->vc->em->bm, eed, data->select);
1776                         }
1777                 }
1778         }
1779 }
1780 static void do_mesh_box_select__doSelectFace(void *userData, BMFace *efa, int x, int y, int UNUSED(index))
1781 {
1782         BoxSelectUserData *data = userData;
1783
1784         if (BLI_in_rcti(data->rect, x, y)) {
1785                 BM_face_select_set(data->vc->em->bm, efa, data->select);
1786         }
1787 }
1788 static int do_mesh_box_select(ViewContext *vc, rcti *rect, int select, int extend)
1789 {
1790         BoxSelectUserData data;
1791         ToolSettings *ts = vc->scene->toolsettings;
1792         int bbsel;
1793         
1794         data.vc = vc;
1795         data.rect = rect;
1796         data.select = select;
1797         data.pass = 0;
1798         data.done = 0;
1799
1800         if (extend == 0 && select)
1801                 EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT);
1802
1803         /* for non zbuf projections, don't change the GL state */
1804         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
1805
1806         glLoadMatrixf(vc->rv3d->viewmat);
1807         bbsel = EDBM_backbuf_border_init(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1808
1809         if (ts->selectmode & SCE_SELECT_VERTEX) {
1810                 if (bbsel) {
1811                         edbm_backbuf_check_and_select_verts(vc->em, select);
1812                 }
1813                 else {
1814                         mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, V3D_CLIP_TEST_RV3D_CLIPPING);
1815                 }
1816         }
1817         if (ts->selectmode & SCE_SELECT_EDGE) {
1818                 /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1819
1820                 data.pass = 0;
1821                 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, V3D_CLIP_TEST_OFF);
1822
1823                 if (data.done == 0) {
1824                         data.pass = 1;
1825                         mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, V3D_CLIP_TEST_OFF);
1826                 }
1827         }
1828         
1829         if (ts->selectmode & SCE_SELECT_FACE) {
1830                 if (bbsel) {
1831                         edbm_backbuf_check_and_select_faces(vc->em, select);
1832                 }
1833                 else {
1834                         mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data);
1835                 }
1836         }
1837         
1838         EDBM_backbuf_free();
1839                 
1840         EDBM_selectmode_flush(vc->em);
1841         
1842         return OPERATOR_FINISHED;
1843 }
1844
1845 static int do_meta_box_select(ViewContext *vc, rcti *rect, int select, int extend)
1846 {
1847         MetaBall *mb = (MetaBall *)vc->obedit->data;
1848         MetaElem *ml;
1849         int a;
1850
1851         unsigned int buffer[4 * MAXPICKBUF];
1852         short hits;
1853
1854         hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect);
1855
1856         if (extend == 0 && select) {
1857                 for (ml = mb->editelems->first; ml; ml = ml->next) {
1858                         ml->flag &= ~SELECT;
1859                 }
1860         }
1861         
1862         for (ml = mb->editelems->first; ml; ml = ml->next) {
1863                 for (a = 0; a < hits; a++) {
1864                         if (ml->selcol1 == buffer[(4 * a) + 3]) {
1865                                 ml->flag |= MB_SCALE_RAD;
1866                                 if (select) ml->flag |= SELECT;
1867                                 else ml->flag &= ~SELECT;
1868                                 break;
1869                         }
1870                         if (ml->selcol2 == buffer[(4 * a) + 3]) {
1871                                 ml->flag &= ~MB_SCALE_RAD;
1872                                 if (select) ml->flag |= SELECT;
1873                                 else ml->flag &= ~SELECT;
1874                                 break;
1875                         }
1876                 }
1877         }
1878
1879         return OPERATOR_FINISHED;
1880 }
1881
1882 static int do_armature_box_select(ViewContext *vc, rcti *rect, short select, short extend)
1883 {
1884         bArmature *arm = vc->obedit->data;
1885         EditBone *ebone;
1886         int a;
1887
1888         unsigned int buffer[4 * MAXPICKBUF];
1889         short hits;
1890
1891         hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect);
1892         
1893         /* clear flag we use to detect point was affected */
1894         for (ebone = arm->edbo->first; ebone; ebone = ebone->next)
1895                 ebone->flag &= ~BONE_DONE;
1896         
1897         if (extend == 0 && select)
1898                 ED_armature_deselect_all_visible(vc->obedit);
1899
1900         /* first we only check points inside the border */
1901         for (a = 0; a < hits; a++) {
1902                 int index = buffer[(4 * a) + 3];
1903                 if (index != -1) {
1904                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1905                         if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
1906                                 if (index & BONESEL_TIP) {
1907                                         ebone->flag |= BONE_DONE;
1908                                         if (select) ebone->flag |= BONE_TIPSEL;
1909                                         else ebone->flag &= ~BONE_TIPSEL;
1910                                 }
1911                                 
1912                                 if (index & BONESEL_ROOT) {
1913                                         ebone->flag |= BONE_DONE;
1914                                         if (select) ebone->flag |= BONE_ROOTSEL;
1915                                         else ebone->flag &= ~BONE_ROOTSEL;
1916                                 }
1917                         }
1918                 }
1919         }
1920         
1921         /* now we have to flush tag from parents... */
1922         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
1923                 if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1924                         if (ebone->parent->flag & BONE_DONE)
1925                                 ebone->flag |= BONE_DONE;
1926                 }
1927         }
1928         
1929         /* only select/deselect entire bones when no points where in the rect */
1930         for (a = 0; a < hits; a++) {
1931                 int index = buffer[(4 * a) + 3];
1932                 if (index != -1) {
1933                         ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
1934                         if (index & BONESEL_BONE) {
1935                                 if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
1936                                         if (!(ebone->flag & BONE_DONE)) {
1937                                                 if (select)
1938                                                         ebone->flag |= (BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED);
1939                                                 else
1940                                                         ebone->flag &= ~(BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED);
1941                                         }
1942                                 }
1943                         }
1944                 }
1945         }
1946         
1947         ED_armature_sync_selection(arm->edbo);
1948         
1949         return OPERATOR_CANCELLED;
1950 }
1951
1952 static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, int select, int extend)
1953 {
1954         Bone *bone;
1955         Object *ob = vc->obact;
1956         unsigned int *vbuffer = NULL; /* selection buffer       */
1957         unsigned int *col;          /* color in buffer  */
1958         int bone_only;
1959         int bone_selected = 0;
1960         int totobj = MAXPICKBUF; // XXX solve later
1961         short hits;
1962         
1963         if ((ob) && (ob->mode & OB_MODE_POSE))
1964                 bone_only = 1;
1965         else
1966                 bone_only = 0;
1967         
1968         if (extend == 0 && select) {
1969                 if (bone_only) {
1970                         CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) {
1971                                 if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
1972                                         pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
1973                                 }
1974                         }
1975                         CTX_DATA_END;
1976                 }
1977                 else {
1978                         object_deselect_all_visible(vc->scene, vc->v3d);
1979                 }
1980         }
1981
1982         /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1983         vbuffer = MEM_mallocN(4 * (totobj + MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1984         hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKBUF), rect);
1985         /*
1986          * LOGIC NOTES (theeth):
1987          * The buffer and ListBase have the same relative order, which makes the selection
1988          * very simple. Loop through both data sets at the same time, if the color
1989          * is the same as the object, we have a hit and can move to the next color
1990          * and object pair, if not, just move to the next object,
1991          * keeping the same color until we have a hit.
1992          * 
1993          * The buffer order is defined by OGL standard, hopefully no stupid GFX card
1994          * does it incorrectly.
1995          */
1996
1997         if (hits > 0) { /* no need to loop if there's no hit */
1998                 Base *base;
1999                 col = vbuffer + 3;
2000                 
2001                 for (base = vc->scene->base.first; base && hits; base = base->next) {
2002                         if (BASE_SELECTABLE(vc->v3d, base)) {
2003                                 while (base->selcol == (*col & 0xFFFF)) {   /* we got an object */
2004                                         
2005                                         if (*col & 0xFFFF0000) {                    /* we got a bone */
2006                                                 bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
2007                                                 if (bone) {
2008                                                         if (select) {
2009                                                                 if ((bone->flag & BONE_UNSELECTABLE) == 0) {
2010                                                                         bone->flag |= BONE_SELECTED;
2011                                                                         bone_selected = 1;
2012 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 1);
2013                                                                 }
2014                                                         }
2015                                                         else {
2016                                                                 bArmature *arm = base->object->data;
2017                                                                 bone->flag &= ~BONE_SELECTED;
2018 // XXX                                                                  select_actionchannel_by_name(base->object->action, bone->name, 0);
2019                                                                 if (arm->act_bone == bone)
2020                                                                         arm->act_bone = NULL;
2021                                                                 
2022                                                         }
2023                                                 }
2024                                         }
2025                                         else if (!bone_only) {
2026                                                 if (select)
2027                                                         ED_base_object_select(base, BA_SELECT);
2028                                                 else
2029                                                         ED_base_object_select(base, BA_DESELECT);
2030                                         }
2031
2032                                         col += 4; /* next color */
2033                                         hits--;
2034                                         if (hits == 0) break;
2035                                 }
2036                         }
2037                         
2038                         if (bone_selected) {
2039                                 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object);
2040                         }
2041                 }
2042
2043                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene);
2044
2045         }
2046         MEM_freeN(vbuffer);
2047
2048         return hits > 0 ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
2049 }
2050
2051 static int view3d_borderselect_exec(bContext *C, wmOperator *op)
2052 {
2053         ViewContext vc;
2054         rcti rect;
2055         short extend;
2056         short select;
2057
2058         int ret = OPERATOR_CANCELLED;
2059
2060         view3d_operator_needs_opengl(C);
2061
2062         /* setup view context for argument to callbacks */
2063         view3d_set_viewcontext(C, &vc);
2064         
2065         select = (RNA_int_get(op->ptr, "gesture_mode") == GESTURE_MODAL_SELECT);
2066         rect.xmin = RNA_int_get(op->ptr, "xmin");
2067         rect.ymin = RNA_int_get(op->ptr, "ymin");
2068         rect.xmax = RNA_int_get(op->ptr, "xmax");
2069         rect.ymax = RNA_int_get(op->ptr, "ymax");
2070         extend = RNA_boolean_get(op->ptr, "extend");
2071
2072         if (vc.obedit) {
2073                 switch (vc.obedit->type) {
2074                         case OB_MESH:
2075                                 vc.em = BMEdit_FromObject(vc.obedit);
2076                                 ret = do_mesh_box_select(&vc, &rect, select, extend);
2077 //                      if (EM_texFaceCheck())
2078                                 if (ret & OPERATOR_FINISHED) {
2079                                         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
2080                                 }
2081                                 break;
2082                         case OB_CURVE:
2083                         case OB_SURF:
2084                                 ret = do_nurbs_box_select(&vc, &rect, select, extend);
2085                                 if (ret & OPERATOR_FINISHED) {
2086                                         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
2087                                 }
2088                                 break;
2089                         case OB_MBALL:
2090                                 ret = do_meta_box_select(&vc, &rect, select, extend);
2091                                 if (ret & OPERATOR_FINISHED) {
2092                                         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
2093                                 }
2094                                 break;
2095                         case OB_ARMATURE:
2096                                 ret = do_armature_box_select(&vc, &rect, select, extend);
2097                                 if (ret & OPERATOR_FINISHED) {
2098                                         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit);
2099                                 }
2100                                 break;
2101                         case OB_LATTICE:
2102                                 ret = do_lattice_box_select(&vc, &rect, select, extend);
2103                                 if (ret & OPERATOR_FINISHED) {
2104                                         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
2105                                 }
2106                                 break;
2107                         default:
2108                                 assert(!"border select on incorrect object type");
2109                 }
2110         }
2111         else {  /* no editmode, unified for bones and objects */
2112                 if (vc.obact && vc.obact->mode & OB_MODE_SCULPT) {
2113                         /* pass */
2114                 }
2115                 else if (vc.obact && paint_facesel_test(vc.obact)) {
2116                         ret = do_paintface_box_select(&vc, &rect, select, extend);
2117                 }
2118                 else if (vc.obact && paint_vertsel_test(vc.obact)) {
2119                         ret = do_paintvert_box_select(&vc, &rect, select, extend);
2120                 }
2121                 else if (vc.obact && vc.obact->mode & OB_MODE_PARTICLE_EDIT) {
2122                         ret = PE_border_select(C, &rect, select, extend);
2123                 }
2124                 else { /* object mode with none active */
2125                         ret = do_object_pose_box_select(C, &vc, &rect, select, extend);
2126                 }
2127         }
2128
2129         return ret;
2130
2131
2132
2133 /* *****************Selection Operators******************* */
2134
2135 /* ****** Border Select ****** */
2136 void VIEW3D_OT_select_border(wmOperatorType *ot)
2137 {
2138         /* identifiers */
2139         ot->name = "Border Select";
2140         ot->description = "Select items using border selection";
2141         ot->idname = "VIEW3D_OT_select_border";
2142         
2143         /* api callbacks */
2144         ot->invoke = WM_border_select_invoke;
2145         ot->exec = view3d_borderselect_exec;
2146         ot->modal = WM_border_select_modal;
2147         ot->poll = view3d_selectable_data;
2148         ot->cancel = WM_border_select_cancel;
2149         
2150         /* flags */
2151         ot->flag = OPTYPE_UNDO;
2152         
2153         /* rna */
2154         WM_operator_properties_gesture_border(ot, TRUE);
2155 }
2156
2157 /* much like facesel_face_pick()*/
2158 /* returns 0 if not found, otherwise 1 */
2159 static int vertsel_vert_pick(struct bContext *C, Mesh *me, const int mval[2], unsigned int *index, int size)
2160 {
2161         ViewContext vc;
2162         view3d_set_viewcontext(C, &vc);
2163
2164         if (!me || me->totvert == 0)
2165                 return 0;
2166
2167         if (size > 0) {
2168                 /* sample rect to increase changes of selecting, so that when clicking
2169                  * on an face in the backbuf, we can still select a vert */
2170
2171                 int dist;
2172                 *index = view3d_sample_backbuf_rect(&vc, mval, size, 1, me->totvert + 1, &dist, 0, NULL, NULL);
2173         }
2174         else {
2175                 /* sample only on the exact position */
2176                 *index = view3d_sample_backbuf(&vc, mval[0], mval[1]);
2177         }
2178
2179         if ((*index) <= 0 || (*index) > (unsigned int)me->totvert)
2180                 return 0;
2181
2182         (*index)--;
2183         
2184         return 1;
2185 }
2186
2187 /* mouse selection in weight paint */
2188 /* gets called via generic mouse select operator */
2189 static int mouse_weight_paint_vertex_select(bContext *C, const int mval[2], short extend, Object *obact)
2190 {
2191         Mesh*me = obact->data; /* already checked for NULL */
2192         unsigned int index = 0;
2193         MVert *mv;
2194
2195         if (vertsel_vert_pick(C, me, mval, &index, 50)) {
2196                 mv = me->mvert + index;
2197                 if (extend) {
2198                         mv->flag ^= SELECT;
2199                 }
2200                 else {
2201                         paintvert_deselect_all_visible(obact, SEL_DESELECT, FALSE);
2202                         mv->flag |= SELECT;
2203                 }
2204                 paintvert_flush_flags(obact);
2205                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
2206                 return 1;
2207         }
2208         return 0;
2209 }
2210
2211 /* ****** Mouse Select ****** */
2212
2213
2214 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
2215 {
2216         Object *obedit = CTX_data_edit_object(C);
2217         Object *obact = CTX_data_active_object(C);
2218         short extend = RNA_boolean_get(op->ptr, "extend");
2219         short center = RNA_boolean_get(op->ptr, "center");
2220         short enumerate = RNA_boolean_get(op->ptr, "enumerate");
2221         short object = RNA_boolean_get(op->ptr, "object");
2222         int retval = 0;
2223
2224         view3d_operator_needs_opengl(C);
2225
2226         if (object) {
2227                 obedit = NULL;
2228                 obact = NULL;
2229
2230                 /* ack, this is incorrect but to do this correctly we would need an
2231                  * alternative editmode/objectmode keymap, this copies the functionality
2232                  * from 2.4x where Ctrl+Select in editmode does object select only */
2233                 center = FALSE;
2234         }
2235
2236         if (obedit && object == FALSE) {
2237                 if (obedit->type == OB_MESH)
2238                         retval = mouse_mesh(C, event->mval, extend);
2239                 else if (obedit->type == OB_ARMATURE)
2240                         retval = mouse_armature(C, event->mval, extend);
2241                 else if (obedit->type == OB_LATTICE)
2242                         retval = mouse_lattice(C, event->mval, extend);
2243                 else if (ELEM(obedit->type, OB_CURVE, OB_SURF))
2244                         retval = mouse_nurb(C, event->mval, extend);
2245                 else if (obedit->type == OB_MBALL)
2246                         retval = mouse_mball(C, event->mval, extend);
2247                         
2248         }
2249         else if (obact && obact->mode & OB_MODE_SCULPT)
2250                 return OPERATOR_CANCELLED;
2251         else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT)
2252                 return PE_mouse_particles(C, event->mval, extend);
2253         else if (obact && paint_facesel_test(obact))
2254                 retval = paintface_mouse_select(C, obact, event->mval, extend);
2255         else if (paint_vertsel_test(obact))
2256                 retval = mouse_weight_paint_vertex_select(C, event->mval, extend, obact);
2257         else
2258                 retval = mouse_select(C, event->mval, extend, center, enumerate);
2259
2260         /* passthrough allows tweaks
2261          * FINISHED to signal one operator worked
2262          * */
2263         if (retval)
2264                 return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
2265         else
2266                 return OPERATOR_PASS_THROUGH;  /* nothing selected, just passthrough */
2267 }
2268
2269 void VIEW3D_OT_select(wmOperatorType *ot)
2270 {
2271         /* identifiers */
2272         ot->name = "Activate/Select";
2273         ot->description = "Activate/select item(s)";
2274         ot->idname = "VIEW3D_OT_select";
2275         
2276         /* api callbacks */
2277         ot->invoke = view3d_select_invoke;
2278         ot->poll = ED_operator_view3d_active;
2279         
2280         /* flags */
2281         ot->flag = OPTYPE_UNDO;
2282         
2283         /* properties */
2284         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first");
2285         RNA_def_boolean(ot->srna, "center", 0, "Center", "Use the object center when selecting, in editmode used to extend object selection");
2286         RNA_def_boolean(ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only)");
2287         RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (editmode only)");
2288 }
2289
2290
2291 /* -------------------- circle select --------------------------------------------- */
2292
2293 typedef struct CircleSelectUserData {
2294         ViewContext *vc;
2295         short select;
2296         int mval[2];
2297         float radius;
2298 } CircleSelectUserData;
2299
2300 static void mesh_circle_doSelectVert(void *userData, BMVert *eve, int x, int y, int UNUSED(index))
2301 {
2302         CircleSelectUserData *data = userData;
2303         int mx = x - data->mval[0], my = y - data->mval[1];
2304         float r = sqrt(mx * mx + my * my);
2305
2306         if (r <= data->radius) {
2307                 BM_vert_select_set(data->vc->em->bm, eve, data->select);
2308         }
2309 }
2310 static void mesh_circle_doSelectEdge(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int UNUSED(index))
2311 {
2312         CircleSelectUserData *data = userData;
2313
2314         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
2315                 BM_edge_select_set(data->vc->em->bm, eed, data->select);
2316         }
2317 }
2318 static void mesh_circle_doSelectFace(void *userData, BMFace *efa, int x, int y, int UNUSED(index))
2319 {
2320         CircleSelectUserData *data = userData;
2321         int mx = x - data->mval[0], my = y - data->mval[1];
2322         float r = sqrt(mx * mx + my * my);
2323         
2324         if (r <= data->radius) {
2325                 BM_face_select_set(data->vc->em->bm, efa, data->select);
2326         }
2327 }
2328
2329 static void mesh_circle_select(ViewContext *vc, int select, const int mval[2], float rad)
2330 {
2331         ToolSettings *ts = vc->scene->toolsettings;
2332         int bbsel;
2333         CircleSelectUserData data;
2334         
2335         bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0));
2336         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
2337
2338         vc->em = BMEdit_FromObject(vc->obedit);
2339
2340         data.vc = vc;
2341         data.select = select;
2342         data.mval[0] = mval[0];
2343         data.mval[1] = mval[1];
2344         data.radius = rad;
2345
2346         if (ts->selectmode & SCE_SELECT_VERTEX) {
2347                 if (bbsel) {
2348                         edbm_backbuf_check_and_select_verts(vc->em, select == LEFTMOUSE);
2349                 }
2350                 else {
2351                         mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, V3D_CLIP_TEST_RV3D_CLIPPING);
2352                 }
2353         }
2354
2355         if (ts->selectmode & SCE_SELECT_EDGE) {
2356                 if (bbsel) {
2357                         edbm_backbuf_check_and_select_edges(vc->em, select == LEFTMOUSE);
2358                 }
2359                 else {
2360                         mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, V3D_CLIP_TEST_OFF);
2361                 }
2362         }
2363         
2364         if (ts->selectmode & SCE_SELECT_FACE) {
2365                 if (bbsel) {
2366                         edbm_backbuf_check_and_select_faces(vc->em, select == LEFTMOUSE);
2367                 }
2368                 else {
2369                         mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data);
2370                 }
2371         }
2372
2373         EDBM_backbuf_free();
2374         EDBM_selectmode_flush(vc->em);
2375 }
2376
2377 static void paint_facesel_circle_select(ViewContext *vc, int select, const int mval[2], float rad)
2378 {
2379         Object *ob = vc->obact;
2380         Mesh *me = ob ? ob->data : NULL;
2381         /* int bbsel; */ /* UNUSED */
2382
2383         if (me) {
2384                 bm_vertoffs = me->totpoly + 1; /* max index array */
2385
2386                 /* bbsel= */ /* UNUSED */ EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0));
2387                 edbm_backbuf_check_and_select_tfaces(me, select == LEFTMOUSE);
2388                 EDBM_backbuf_free();
2389         }
2390 }
2391
2392
2393 static void paint_vertsel_circle_select(ViewContext *vc, int select, const int mval[2], float rad)
2394 {
2395         Object *ob = vc->obact;
2396         Mesh *me = ob ? ob->data : NULL;
2397         /* int bbsel; */ /* UNUSED */
2398         /* CircleSelectUserData data = {NULL}; */ /* UNUSED */
2399         if (me) {
2400                 bm_vertoffs = me->totvert + 1; /* max index array */
2401
2402                 /* bbsel= */ /* UNUSED */ EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f));
2403                 edbm_backbuf_check_and_select_verts_obmode(me, select == LEFTMOUSE);
2404                 EDBM_backbuf_free();
2405
2406                 paintvert_flush_flags(ob);
2407         }
2408 }
2409
2410
2411 static void nurbscurve_circle_doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
2412 {
2413         CircleSelectUserData *data = userData;
2414         int mx = x - data->mval[0], my = y - data->mval[1];
2415         float r = sqrt(mx * mx + my * my);
2416         Object *obedit = data->vc->obedit;
2417         Curve *cu = (Curve *)obedit->data;
2418
2419         if (r <= data->radius) {
2420                 if (bp) {
2421                         bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
2422
2423                         if (bp == cu->lastsel && !(bp->f1 & 1)) cu->lastsel = NULL;
2424                 }
2425                 else {
2426                         if (cu->drawflag & CU_HIDE_HANDLES) {
2427                                 /* can only be beztindex==0 here since handles are hidden */
2428                                 bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
2429                         }
2430                         else {
2431                                 if (beztindex == 0) {
2432                                         bezt->f1 = data->select ? (bezt->f1 | SELECT) : (bezt->f1 & ~SELECT);
2433                                 }
2434                                 else if (beztindex == 1) {
2435                                         bezt->f2 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
2436                                 }
2437                                 else {
2438                                         bezt->f3 = data->select ? (bezt->f3 | SELECT) : (bezt->f3 & ~SELECT);
2439                                 }
2440                         }
2441
2442                         if (bezt == cu->lastsel && !(bezt->f2 & 1)) cu->lastsel = NULL;
2443                 }
2444         }
2445 }
2446 static void nurbscurve_circle_select(ViewContext *vc, int select, const int mval[2], float rad)
2447 {
2448         CircleSelectUserData data;
2449
2450         /* set vc-> edit data */
2451         
2452         data.select = select;
2453         data.mval[0] = mval[0];
2454         data.mval[1] = mval[1];
2455         data.radius = rad;
2456         data.vc = vc;
2457
2458         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
2459         nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data);
2460 }
2461
2462
2463 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, int x, int y)
2464 {
2465         CircleSelectUserData *data = userData;
2466         int mx = x - data->mval[0], my = y - data->mval[1];
2467         float r = sqrt(mx * mx + my * my);
2468
2469         if (r <= data->radius) {
2470                 bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
2471         }
2472 }
2473 static void lattice_circle_select(ViewContext *vc, int select, const int mval[2], float rad)
2474 {
2475         CircleSelectUserData data;
2476
2477         /* set vc-> edit data */
2478         
2479         data.select = select;
2480         data.mval[0] = mval[0];
2481         data.mval[1] = mval[1];
2482         data.radius = rad;
2483
2484         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
2485         lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data);
2486 }
2487
2488
2489 // NOTE: pose-bone case is copied from editbone case...
2490 static short pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, int x, int y)
2491 {
2492         CircleSelectUserData *data = userData;
2493         int mx = x - data->mval[0], my = y - data->mval[1];
2494         float r = sqrt(mx * mx + my * my);
2495         
2496         if (r <= data->radius) {
2497                 if (data->select)
2498                         pchan->bone->flag |= BONE_SELECTED;
2499                 else
2500                         pchan->bone->flag &= ~BONE_SELECTED;
2501                 return 1;
2502         }
2503         return 0;
2504 }
2505 static void pose_circle_select(ViewContext *vc, int select, const int mval[2], float rad)
2506 {
2507         CircleSelectUserData data;
2508         bArmature *arm = vc->obact->data;
2509         bPose *pose = vc->obact->pose;
2510         bPoseChannel *pchan;
2511         int change = FALSE;
2512         
2513         /* set vc->edit data */
2514         data.select = select;
2515         data.mval[0] = mval[0];
2516         data.mval[1] = mval[1];
2517         data.radius = rad;
2518
2519         ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */
2520         
2521         /* check each PoseChannel... */
2522         // TODO: could be optimized at some point
2523         for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
2524                 short sco1[2], sco2[2], didpoint = 0;
2525                 float vec[3];
2526                 
2527                 /* skip invisible bones */
2528                 if (PBONE_VISIBLE(arm, pchan->bone) == 0)
2529                         continue;
2530                 
2531                 /* project head location to screenspace */
2532                 mul_v3_m4v3(vec, vc->obact->obmat, pchan->pose_head);
2533                 project_short(vc->ar, vec, sco1);
2534                 
2535                 /* project tail location to screenspace */
2536                 mul_v3_m4v3(vec, vc->obact->obmat, pchan->pose_tail);
2537                 project_short(vc->ar, vec, sco2);
2538                 
2539                 /* check if the head and/or tail is in the circle 
2540                  *      - the call to check also does the selection already
2541                  */
2542                 if (pchan_circle_doSelectJoint(&data, pchan, sco1[0], sco1[1]))
2543                         didpoint = 1;
2544                 if (pchan_circle_doSelectJoint(&data, pchan, sco2[0], sco2[1]))
2545                         didpoint = 1;
2546                 
2547                 change |= didpoint;
2548         }
2549
2550         if (change) {
2551                 WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, vc->obact);
2552         }
2553 }
2554
2555 static short armature_circle_doSelectJoint(void *userData, EditBone *ebone, int x, int y, short head)
2556 {
2557         CircleSelectUserData *data = userData;
2558         int mx = x - data->mval[0], my = y - data->mval[1];
2559         float r = sqrt(mx * mx + my * my);
2560         
2561         if (r <= data->radius) {
2562                 if (head) {
2563                         if (data->select)
2564                                 ebone->flag |= BONE_ROOTSEL;
2565                         else 
2566                                 ebone->flag &= ~BONE_ROOTSEL;
2567                 }
2568                 else {
2569                         if (data->select)
2570                                 ebone->flag |= BONE_TIPSEL;
2571                         else 
2572                                 ebone->flag &= ~BONE_TIPSEL;
2573                 }
2574                 return 1;
2575         }
2576         return 0;
2577 }
2578 static void armature_circle_select(ViewContext *vc, int select, const int mval[2], float rad)
2579 {
2580         CircleSelectUserData data;
2581         bArmature *arm = vc->obedit->data;
2582         EditBone *ebone;
2583         int change = FALSE;
2584         
2585         /* set vc->edit data */
2586         data.select = select;
2587         data.mval[0] = mval[0];
2588         data.mval[1] = mval[1];
2589         data.radius = rad;
2590
2591         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
2592         
2593         /* check each EditBone... */
2594         // TODO: could be optimized at some point
2595         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
2596                 short sco1[2], sco2[2], didpoint = 0;
2597                 float vec[3];
2598                 
2599                 /* project head location to screenspace */
2600                 mul_v3_m4v3(vec, vc->obedit->obmat, ebone->head);
2601                 project_short(vc->ar, vec, sco1);
2602                 
2603                 /* project tail location to screenspace */
2604                 mul_v3_m4v3(vec, vc->obedit->obmat, ebone->tail);
2605                 project_short(vc->ar, vec, sco2);
2606                 
2607                 /* check if the head and/or tail is in the circle 
2608                  *      - the call to check also does the selection already
2609                  */
2610                 if (armature_circle_doSelectJoint(&data, ebone, sco1[0], sco1[1], 1))
2611                         didpoint = 1;
2612                 if (armature_circle_doSelectJoint(&data, ebone, sco2[0], sco2[1], 0))
2613                         didpoint = 1;
2614                         
2615                 /* only if the endpoints didn't get selected, deal with the middle of the bone too */
2616                 // XXX should we just do this always?
2617                 if ( (didpoint == 0) && edge_inside_circle(mval[0], mval[1], rad, sco1[0], sco1[1], sco2[0], sco2[1]) ) {
2618                         if (select) 
2619                                 ebone->flag |= BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED;
2620                         else 
2621                                 ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
2622                         change = TRUE;
2623                 }
2624                 
2625                 change |= didpoint;
2626         }
2627
2628         if (change) {
2629                 ED_armature_sync_selection(arm->edbo);
2630                 ED_armature_validate_active(arm);
2631                 WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, vc->obedit);
2632         }
2633 }
2634
2635 /** Callbacks for circle selection in Editmode */
2636
2637 static void obedit_circle_select(ViewContext *vc, short select, const int mval[2], float rad)
2638 {
2639         switch (vc->obedit->type) {
2640                 case OB_MESH:
2641                         mesh_circle_select(vc, select, mval, rad);
2642                         break;
2643                 case OB_CURVE:
2644                 case OB_SURF:
2645                         nurbscurve_circle_select(vc, select, mval, rad);
2646                         break;
2647                 case OB_LATTICE:
2648                         lattice_circle_select(vc, select, mval, rad);
2649                         break;
2650                 case OB_ARMATURE:
2651                         armature_circle_select(vc, select, mval, rad);
2652                         break;
2653                 default:
2654                         return;
2655         }
2656 }
2657
2658 /* not a real operator, only for circle test */
2659 static int view3d_circle_select_exec(bContext *C, wmOperator *op)
2660 {
2661         ScrArea *sa = CTX_wm_area(C);
2662         ARegion *ar = CTX_wm_region(C);
2663         Scene *scene = CTX_data_scene(C);
2664         Object *obact = CTX_data_active_object(C);
2665         View3D *v3d = sa->spacedata.first;
2666         int x = RNA_int_get(op->ptr, "x");
2667         int y = RNA_int_get(op->ptr, "y");
2668         int radius = RNA_int_get(op->ptr, "radius");
2669         int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
2670         int select;
2671         
2672         select = (gesture_mode == GESTURE_MODAL_SELECT);
2673
2674         if (CTX_data_edit_object(C) || paint_facesel_test(obact) || paint_vertsel_test(obact) ||
2675             (obact && (obact->mode & (OB_MODE_PARTICLE_EDIT | OB_MODE_POSE))) )
2676         {
2677                 ViewContext vc;
2678                 int mval[2];
2679                 
2680                 view3d_operator_needs_opengl(C);
2681                 
2682                 view3d_set_viewcontext(C, &vc);
2683                 mval[0] = x;
2684                 mval[1] = y;
2685
2686                 if (CTX_data_edit_object(C)) {
2687                         obedit_circle_select(&vc, select, mval, (float)radius);
2688                         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
2689                 }
2690                 else if (paint_facesel_test(obact)) {
2691                         paint_facesel_circle_select(&vc, select, mval, (float)radius);
2692                         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
2693                 }
2694                 else if (paint_vertsel_test(obact)) {
2695                         paint_vertsel_circle_select(&vc, select, mval, (float)radius);
2696                         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
2697                 }
2698                 else if (obact->mode & OB_MODE_POSE)
2699                         pose_circle_select(&vc, select, mval, (float)radius);
2700                 else
2701                         return PE_circle_select(C, select, mval, (float)radius);
2702         }
2703         else if (obact && obact->mode & OB_MODE_SCULPT) {
2704                 return OPERATOR_CANCELLED;
2705         }
2706         else {
2707                 Base *base;
2708                 select = select ? BA_SELECT : BA_DESELECT;
2709                 for (base = FIRSTBASE; base; base = base->next) {
2710                         if (BASE_SELECTABLE(v3d, base)) {
2711                                 project_short(ar, base->object->obmat[3], &base->sx);
2712                                 if (base->sx != IS_CLIPPED) {
2713                                         int dx = base->sx - x;
2714                                         int dy = base->sy - y;
2715                                         if (dx * dx + dy * dy < radius * radius)
2716                                                 ED_base_object_select(base, select);
2717                                 }
2718                         }
2719                 }
2720                 
2721                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
2722         }
2723         
2724         return OPERATOR_FINISHED;
2725 }
2726
2727 void VIEW3D_OT_select_circle(wmOperatorType *ot)
2728 {
2729         ot->name = "Circle Select";
2730         ot->description = "Select items using circle selection";
2731         ot->idname = "VIEW3D_OT_select_circle";
2732         
2733         ot->invoke = WM_gesture_circle_invoke;
2734         ot->modal = WM_gesture_circle_modal;
2735         ot->exec = view3d_circle_select_exec;
2736         ot->poll = view3d_selectable_data;
2737         ot->cancel = WM_gesture_circle_cancel;
2738         
2739         /* flags */
2740         ot->flag = OPTYPE_UNDO;
2741         
2742         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
2743         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
2744         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
2745         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2746 }