Orange branch: Revived hidden treasure, the Groups!
[blender.git] / source / blender / src / editview.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  * cursor/gestures/selecteren
32  */
33
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <math.h>
37 #include <string.h>
38
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42 #include "MEM_guardedalloc.h"
43
44 #include "IMB_imbuf.h"
45 #include "PIL_time.h"
46
47 #include "DNA_action_types.h"
48 #include "DNA_armature_types.h"
49 #include "DNA_curve_types.h"
50 #include "DNA_group_types.h"
51 #include "DNA_lattice_types.h"
52 #include "DNA_meta_types.h"
53 #include "DNA_mesh_types.h"
54 #include "DNA_object_types.h"
55 #include "DNA_scene_types.h"
56 #include "DNA_screen_types.h"
57 #include "DNA_view3d_types.h"
58 #include "DNA_userdef_types.h"
59
60 #include "BLI_blenlib.h"
61 #include "BLI_arithb.h"
62 #include "BLI_editVert.h"
63
64 #include "BKE_armature.h"
65 #include "BKE_depsgraph.h"
66 #include "BKE_global.h"
67 #include "BKE_group.h"
68 #include "BKE_lattice.h"
69 #include "BKE_main.h"
70 #include "BKE_mesh.h"
71 #include "BKE_utildefines.h"
72
73 #include "BIF_butspace.h"
74 #include "BIF_editaction.h"
75 #include "BIF_editarmature.h"
76 #include "BIF_editgroup.h"
77 #include "BIF_editmesh.h"
78 #include "BIF_editoops.h"
79 #include "BIF_editsima.h"
80 #include "BIF_editview.h"
81 #include "BIF_gl.h"
82 #include "BIF_glutil.h"
83 #include "BIF_interface.h"
84 #include "BIF_mywindow.h"
85 #include "BIF_space.h"
86 #include "BIF_screen.h"
87 #include "BIF_toolbox.h"
88
89 #include "BDR_editobject.h"     /* For headerprint */
90 #include "BDR_vpaint.h"
91 #include "BDR_editface.h"
92 #include "BDR_drawobject.h"
93 #include "BDR_editcurve.h"
94
95 #include "BSE_edit.h"
96 #include "BSE_view.h"           /* give_cursor() */
97 #include "BSE_editipo.h"
98 #include "BSE_drawview.h"
99
100 #include "editmesh.h"   // borderselect uses it...
101 #include "blendef.h"
102 #include "mydevice.h"
103
104 #include "BIF_transform.h"
105
106 extern ListBase editNurb; /* originally from exports.h, memory from editcurve.c*/
107 /* editmball.c */
108 extern ListBase editelems;
109
110 /* local prototypes */
111
112 void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select)
113 {
114         EditVert *eve;
115         int index= em_wireoffs;
116
117         for(eve= em->verts.first; eve; eve= eve->next, index++) {
118                 if(eve->h==0) {
119                         if(EM_check_backbuf(index)) {
120                                 eve->f = select?(eve->f|1):(eve->f&~1);
121                         }
122                 }
123         }
124 }
125
126 void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select)
127 {
128         EditEdge *eed;
129         int index= em_solidoffs;
130
131         for(eed= em->edges.first; eed; eed= eed->next, index++) {
132                 if(eed->h==0) {
133                         if(EM_check_backbuf(index)) {
134                                 EM_select_edge(eed, select);
135                         }
136                 }
137         }
138 }
139
140 void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select)
141 {
142         EditFace *efa;
143         int index= 1;
144
145         for(efa= em->faces.first; efa; efa= efa->next, index++) {
146                 if(efa->h==0) {
147                         if(EM_check_backbuf(index)) {
148                                 EM_select_face_fgon(efa, select);
149                         }
150                 }
151         }
152 }
153
154 void EM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
155 {
156         TFace *tface = me->tface;
157         int a;
158
159         if (tface) {
160                 for(a=1; a<=me->totface; a++, tface++) {
161                         if(EM_check_backbuf(a)) {
162                                 tface->flag = select?(tface->flag|TF_SELECT):(tface->flag&~TF_SELECT);
163                         }
164                 }
165         }
166 }
167
168 void arrows_move_cursor(unsigned short event)
169 {
170         short mval[2];
171
172         getmouseco_sc(mval);
173
174         if(event==UPARROWKEY) {
175                 warp_pointer(mval[0], mval[1]+1);
176         } else if(event==DOWNARROWKEY) {
177                 warp_pointer(mval[0], mval[1]-1);
178         } else if(event==LEFTARROWKEY) {
179                 warp_pointer(mval[0]-1, mval[1]);
180         } else if(event==RIGHTARROWKEY) {
181                 warp_pointer(mval[0]+1, mval[1]);
182         }
183 }
184
185 /* *********************** GESTURE AND LASSO ******************* */
186
187 /* helper also for borderselect */
188 static int edge_fully_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
189 {
190         return BLI_in_rcti(rect, x1, y1) && BLI_in_rcti(rect, x2, y2);
191 }
192
193 static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
194 {
195         int d1, d2, d3, d4;
196         
197         // check points in rect
198         if(edge_fully_inside_rect(rect, x1, y1, x2, y2)) return 1;
199         
200         // check points completely out rect
201         if(x1<rect->xmin && x2<rect->xmin) return 0;
202         if(x1>rect->xmax && x2>rect->xmax) return 0;
203         if(y1<rect->ymin && y2<rect->ymin) return 0;
204         if(y1>rect->ymax && y2>rect->ymax) return 0;
205         
206         // simple check lines intersecting. 
207         d1= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymin );
208         d2= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymax );
209         d3= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymax );
210         d4= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymin );
211         
212         if(d1<0 && d2<0 && d3<0 && d4<0) return 0;
213         if(d1>0 && d2>0 && d3>0 && d4>0) return 0;
214         
215         return 1;
216 }
217
218
219 #define MOVES_GESTURE 50
220 #define MOVES_LASSO 500
221
222 static int lasso_inside(short mcords[][2], short moves, short sx, short sy)
223 {
224         /* we do the angle rule, define that all added angles should be about zero or 2*PI */
225         float angletot=0.0, len, dot, ang, cross, fp1[2], fp2[2];
226         int a;
227         short *p1, *p2;
228         
229         p1= mcords[moves-1];
230         p2= mcords[0];
231         
232         /* first vector */
233         fp1[0]= (float)(p1[0]-sx);
234         fp1[1]= (float)(p1[1]-sy);
235         len= sqrt(fp1[0]*fp1[0] + fp1[1]*fp1[1]);
236         fp1[0]/= len;
237         fp1[1]/= len;
238         
239         for(a=0; a<moves; a++) {
240                 /* second vector */
241                 fp2[0]= (float)(p2[0]-sx);
242                 fp2[1]= (float)(p2[1]-sy);
243                 len= sqrt(fp2[0]*fp2[0] + fp2[1]*fp2[1]);
244                 fp2[0]/= len;
245                 fp2[1]/= len;
246                 
247                 /* dot and angle and cross */
248                 dot= fp1[0]*fp2[0] + fp1[1]*fp2[1];
249                 ang= fabs(saacos(dot));
250
251                 cross= (float)((p1[1]-p2[1])*(p1[0]-sx) + (p2[0]-p1[0])*(p1[1]-sy));
252                 
253                 if(cross<0.0) angletot-= ang;
254                 else angletot+= ang;
255                 
256                 /* circulate */
257                 fp1[0]= fp2[0]; fp1[1]= fp2[1];
258                 p1= p2;
259                 p2= mcords[a+1];
260         }
261         
262         if( fabs(angletot) > 4.0 ) return 1;
263         return 0;
264 }
265
266 /* edge version for lasso select. we assume boundbox check was done */
267 static int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1)
268 {
269         short v1[2], v2[2];
270         int a;
271
272         v1[0] = x0, v1[1] = y0;
273         v2[0] = x1, v2[1] = y1;
274
275         // check points in lasso
276         if(lasso_inside(mcords, moves, v1[0], v1[1])) return 1;
277         if(lasso_inside(mcords, moves, v2[0], v2[1])) return 1;
278         
279         /* no points in lasso, so we have to intersect with lasso edge */
280         
281         if( IsectLL2Ds(mcords[0], mcords[moves-1], v1, v2) > 0) return 1;
282         for(a=0; a<moves-1; a++) {
283                 if( IsectLL2Ds(mcords[a], mcords[a+1], v1, v2) > 0) return 1;
284         }
285         
286         return 0;
287 }
288
289
290 /* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN) 
291    and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK
292 */
293 static void do_lasso_select_pose(Object *ob, short mcords[][2], short moves, short select)
294 {
295         bPoseChannel *pchan;
296         float vec[3];
297         short sco1[2], sco2[2];
298         
299         if(ob->type!=OB_ARMATURE || ob->pose==NULL) return;
300         
301         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
302                 VECCOPY(vec, pchan->pose_head);
303                 Mat4MulVecfl(ob->obmat, vec);
304                 project_short(vec, sco1);
305                 VECCOPY(vec, pchan->pose_tail);
306                 Mat4MulVecfl(ob->obmat, vec);
307                 project_short(vec, sco2);
308                 
309                 if(lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
310                         if(select) pchan->bone->flag |= BONE_SELECTED;
311                         else pchan->bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
312                 }
313         }
314 }
315
316
317 static void do_lasso_select_objects(short mcords[][2], short moves, short select)
318 {
319         Base *base;
320         
321         for(base= G.scene->base.first; base; base= base->next) {
322                 if(base->lay & G.vd->lay) {
323                         project_short(base->object->obmat[3], &base->sx);
324                         if(lasso_inside(mcords, moves, base->sx, base->sy)) {
325                                 
326                                 if(select) base->flag |= SELECT;
327                                 else base->flag &= ~SELECT;
328                                 base->object->flag= base->flag;
329                         }
330                         if(base->object->flag & OB_POSEMODE) {
331                                 do_lasso_select_pose(base->object, mcords, moves, select);
332                         }
333                 }
334         }
335 }
336
337 static void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
338 {
339         short a;
340         
341         rect->xmin= rect->xmax= mcords[0][0];
342         rect->ymin= rect->ymax= mcords[0][1];
343         
344         for(a=1; a<moves; a++) {
345                 if(mcords[a][0]<rect->xmin) rect->xmin= mcords[a][0];
346                 else if(mcords[a][0]>rect->xmax) rect->xmax= mcords[a][0];
347                 if(mcords[a][1]<rect->ymin) rect->ymin= mcords[a][1];
348                 else if(mcords[a][1]>rect->ymax) rect->ymax= mcords[a][1];
349         }
350 }
351
352 static void do_lasso_select_mesh__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
353 {
354         struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
355
356         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
357                 eve->f = data->select?(eve->f|1):(eve->f&~1);
358         }
359 }
360 static void do_lasso_select_mesh__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
361 {
362         struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
363
364         if (EM_check_backbuf(em_solidoffs+index)) {
365                 if (data->pass==0) {
366                         if (    edge_fully_inside_rect(data->rect, x0, y0, x1, y1)  &&
367                                         lasso_inside(data->mcords, data->moves, x0, y0) &&
368                                         lasso_inside(data->mcords, data->moves, x1, y1)) {
369                                 EM_select_edge(eed, data->select);
370                                 data->done = 1;
371                         }
372                 } else {
373                         if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) {
374                                 EM_select_edge(eed, data->select);
375                         }
376                 }
377         }
378 }
379 static void do_lasso_select_mesh__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
380 {
381         struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
382
383         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
384                 EM_select_face_fgon(efa, data->select);
385         }
386 }
387
388 static void do_lasso_select_mesh(short mcords[][2], short moves, short select)
389 {
390         struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } data;
391         EditMesh *em = G.editMesh;
392         rcti rect;
393         int bbsel;
394         
395         lasso_select_boundbox(&rect, mcords, moves);
396         
397         data.rect = &rect;
398         data.mcords = mcords;
399         data.moves = moves;
400         data.select = select;
401         data.done = 0;
402         data.pass = 0;
403
404         bbsel= EM_mask_init_backbuf_border(mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
405         
406         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
407                 if (bbsel) {
408                         EM_backbuf_checkAndSelectVerts(em, select);
409                 } else {
410                         mesh_foreachScreenVert(do_lasso_select_mesh__doSelectVert, &data, 1);
411                 }
412         }
413         if(G.scene->selectmode & SCE_SELECT_EDGE) {
414                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
415
416                 data.pass = 0;
417                 mesh_foreachScreenEdge(do_lasso_select_mesh__doSelectEdge, &data, 0);
418
419                 if (data.done==0) {
420                         data.pass = 1;
421                         mesh_foreachScreenEdge(do_lasso_select_mesh__doSelectEdge, &data, 0);
422                 }
423         }
424         
425         if(G.scene->selectmode & SCE_SELECT_FACE) {
426                 if (bbsel) {
427                         EM_backbuf_checkAndSelectFaces(em, select);
428                 } else {
429                         mesh_foreachScreenFace(do_lasso_select_mesh__doSelectFace, &data);
430                 }
431         }
432         
433         EM_free_backbuf();
434         EM_selectmode_flush();  
435 }
436
437 static void do_lasso_select_curve__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
438 {
439         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
440
441         if (lasso_inside(data->mcords, data->moves, x, y)) {
442                 if (bp) {
443                         bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
444                 } else {
445                         if (beztindex==0) {
446                                 bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
447                         } else if (beztindex==1) {
448                                 bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
449                         } else {
450                                 bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
451                         }
452                 }
453         }
454 }
455 static void do_lasso_select_curve(short mcords[][2], short moves, short select)
456 {
457         struct { short (*mcords)[2]; short moves; short select; } data;
458
459         data.mcords = mcords;
460         data.moves = moves;
461         data.select = select;
462
463         nurbs_foreachScreenVert(do_lasso_select_curve__doSelect, &data);
464 }
465
466 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, int y)
467 {
468         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
469
470         if (lasso_inside(data->mcords, data->moves, x, y)) {
471                 bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
472         }
473 }
474 static void do_lasso_select_lattice(short mcords[][2], short moves, short select)
475 {
476         struct { short (*mcords)[2]; short moves; short select; } data;
477
478         data.mcords = mcords;
479         data.moves = moves;
480         data.select = select;
481
482         lattice_foreachScreenVert(do_lasso_select_lattice__doSelect, &data);
483 }
484
485 static void do_lasso_select_armature(short mcords[][2], short moves, short select)
486 {
487         EditBone *ebone;
488         float vec[3];
489         short sco1[2], sco2[2], didpoint;
490         
491         for (ebone=G.edbo.first; ebone; ebone=ebone->next) {
492
493                 VECCOPY(vec, ebone->head);
494                 Mat4MulVecfl(G.obedit->obmat, vec);
495                 project_short(vec, sco1);
496                 VECCOPY(vec, ebone->tail);
497                 Mat4MulVecfl(G.obedit->obmat, vec);
498                 project_short(vec, sco2);
499                 
500                 didpoint= 0;
501                 if(lasso_inside(mcords, moves, sco1[0], sco1[1])) {
502                         if(select) ebone->flag |= BONE_ROOTSEL;
503                         else ebone->flag &= ~BONE_ROOTSEL;
504                         didpoint= 1;
505                 }
506                 if(lasso_inside(mcords, moves, sco2[0], sco2[1])) {
507                    if(select) ebone->flag |= BONE_TIPSEL;
508                    else ebone->flag &= ~BONE_TIPSEL;
509                    didpoint= 1;
510                 }
511                 /* if one of points selected, we skip the bone itself */
512                 if(didpoint==0 && lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
513                         if(select) ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
514                         else ebone->flag &= ~(BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
515                 }
516         }
517         countall();     // abused for flushing selection
518 }
519
520 static void do_lasso_select_facemode(short mcords[][2], short moves, short select)
521 {
522         Mesh *me;
523         rcti rect;
524         
525         me= get_mesh(OBACT);
526         if(me==NULL || me->tface==NULL) return;
527         if(me->totface==0) return;
528         
529         em_vertoffs= me->totface+1;     // max index array
530         
531         lasso_select_boundbox(&rect, mcords, moves);
532         EM_mask_init_backbuf_border(mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
533         
534         EM_backbuf_checkAndSelectTFaces(me, select);
535         
536         EM_free_backbuf();
537         
538         object_tface_flags_changed(OBACT, 0);
539 }
540
541 static void do_lasso_select(short mcords[][2], short moves, short select)
542 {
543         if(G.obedit==NULL) {
544                 if(G.f & G_FACESELECT)
545                         do_lasso_select_facemode(mcords, moves, select);
546                 else if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))
547                         ;
548                 else  
549                         do_lasso_select_objects(mcords, moves, select);
550         }
551         else if(G.obedit->type==OB_MESH) 
552                 do_lasso_select_mesh(mcords, moves, select);
553         else if(G.obedit->type==OB_CURVE || G.obedit->type==OB_SURF) 
554                 do_lasso_select_curve(mcords, moves, select);
555         else if(G.obedit->type==OB_LATTICE) 
556                 do_lasso_select_lattice(mcords, moves, select);
557         else if(G.obedit->type==OB_ARMATURE)
558                 do_lasso_select_armature(mcords, moves, select);
559         
560         BIF_undo_push("Lasso select");
561
562         allqueue(REDRAWVIEW3D, 0);
563         countall();
564 }
565
566 /* un-draws and draws again */
567 static void draw_lasso_select(short mcords[][2], short moves, short end)
568 {
569         int a;
570         
571         setlinestyle(2);
572         /* clear draw */
573         if(moves>1) {
574                 for(a=1; a<=moves-1; a++) {
575                         sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
576                 }
577                 sdrawXORline(mcords[moves-1][0], mcords[moves-1][1], mcords[0][0], mcords[0][1]);
578         }
579         if(!end) {
580                 /* new draw */
581                 for(a=1; a<=moves; a++) {
582                         sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
583                 }
584                 sdrawXORline(mcords[moves][0], mcords[moves][1], mcords[0][0], mcords[0][1]);
585         }
586         setlinestyle(0);
587 }
588
589
590 static char interpret_move(short mcord[][2], int count)
591 {
592         float x1, x2, y1, y2, d1, d2, inp, sq, mouse[MOVES_GESTURE][2];
593         int i, j, dir = 0;
594         
595         if (count <= 10) return ('g');
596
597         /* from short to float (drawing is with shorts) */
598         for(j=0; j<count; j++) {
599                 mouse[j][0]= mcord[j][0];
600                 mouse[j][1]= mcord[j][1];
601         }
602         
603         /* new method:
604          * 
605          * starting from end points, calculate centre with maximum distance
606          * dependant at the angle s / g / r is defined
607          */
608         
609
610         /* filter */
611         
612         for( j = 3 ; j > 0; j--){
613                 x1 = mouse[1][0];
614                 y1 = mouse[1][1];
615                 for (i = 2; i < count; i++){
616                         x2 = mouse[i-1][0];
617                         y2 = mouse[i-1][1];
618                         mouse[i-1][0] = ((x1 + mouse[i][0]) /4.0) + (x2 / 2.0);
619                         mouse[i-1][1] = ((y1 + mouse[i][1]) /4.0) + (y2 / 2.0);
620                         x1 = x2;
621                         y1 = y2;
622                 }
623         }
624
625         /* make overview of directions */
626         for (i = 0; i <= count - 2; i++){
627                 x1 = mouse[i][0] - mouse[i + 1][0];
628                 y1 = mouse[i][1] - mouse[i + 1][1];
629
630                 if (x1 < -0.5){
631                         if (y1 < -0.5) dir |= 32;
632                         else if (y1 > 0.5) dir |= 128;
633                         else dir |= 64;
634                 } else if (x1 > 0.5){
635                         if (y1 < -0.5) dir |= 8;
636                         else if (y1 > 0.5) dir |= 2;
637                         else dir |= 4;
638                 } else{
639                         if (y1 < -0.5) dir |= 16;
640                         else if (y1 > 0.5) dir |= 1;
641                         else dir |= 0;
642                 }
643         }
644         
645         /* move all crosses to the right */
646         for (i = 7; i>=0 ; i--){
647                 if (dir & 128) dir = (dir << 1) + 1;
648                 else break;
649         }
650         dir &= 255;
651         for (i = 7; i>=0 ; i--){
652                 if ((dir & 1) == 0) dir >>= 1;
653                 else break;
654         }
655         
656         /* in theory: 1 direction: straight line
657      * multiple sequential directions: circle
658      * non-sequential, and 1 bit set in upper 4 bits: size
659      */
660         switch(dir){
661         case 1:
662                 return ('g');
663                 break;
664         case 3:
665         case 7:
666                 x1 = mouse[0][0] - mouse[count >> 1][0];
667                 y1 = mouse[0][1] - mouse[count >> 1][1];
668                 x2 = mouse[count >> 1][0] - mouse[count - 1][0];
669                 y2 = mouse[count >> 1][1] - mouse[count - 1][1];
670                 d1 = (x1 * x1) + (y1 * y1);
671                 d2 = (x2 * x2) + (y2 * y2);
672                 sq = sqrt(d1);
673                 x1 /= sq; 
674                 y1 /= sq;
675                 sq = sqrt(d2);
676                 x2 /= sq; 
677                 y2 /= sq;
678                 inp = (x1 * x2) + (y1 * y2);
679                 /*printf("%f\n", inp);*/
680                 if (inp > 0.9) return ('g');
681                 else return ('r');
682                 break;
683         case 15:
684         case 31:
685         case 63:
686         case 127:
687         case 255:
688                 return ('r');
689                 break;
690         default:
691                 /* for size at least one of the higher bits has to be set */
692                 if (dir < 16) return ('r');
693                 else return ('s');
694         }
695
696         return (0);
697 }
698
699
700 /* return 1 to denote gesture did something, also does lasso */
701 int gesture(void)
702 {
703         unsigned short event=0;
704         int i= 1, end= 0, a;
705         short mcords[MOVES_LASSO][2]; // the larger size
706         short mval[2], val, timer=0, mousebut, lasso=0, maxmoves;
707         
708         if (U.flag & USER_LMOUSESELECT) mousebut = R_MOUSE;
709         else mousebut = L_MOUSE;
710         
711         /* check for lasso */
712         if(G.qual & LR_CTRLKEY) {
713                 if(curarea->spacetype==SPACE_VIEW3D) {
714                         if(G.obedit==NULL) {
715                                 if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT)) return 0;
716                         }
717                         lasso= 1;
718                 }
719         }
720         
721         glDrawBuffer(GL_FRONT);
722         persp(PERSP_WIN);       /*  ortho at pixel level */
723         
724         getmouseco_areawin(mval);
725         
726         mcords[0][0] = mval[0];
727         mcords[0][1] = mval[1];
728         
729         if(lasso) maxmoves= MOVES_LASSO;
730         else maxmoves= MOVES_GESTURE;
731         
732         while(get_mbut() & mousebut) {
733                 
734                 if(qtest()) event= extern_qread(&val);
735                 else if(i==1) {
736                         /* not drawing yet... check for toolbox */
737                         PIL_sleep_ms(10);
738                         timer++;
739                         if(timer>=10*U.tb_leftmouse) {
740                                 glDrawBuffer(GL_BACK); /* !! */
741                                 toolbox_n();
742                                 return 1;
743                         }
744                 }
745                 
746                 switch (event) {
747                 case MOUSEY:
748                         getmouseco_areawin(mval);
749                         if( abs(mval[0]-mcords[i-1][0])>3 || abs(mval[1]-mcords[i-1][1])>3 ) {
750                                 mcords[i][0] = mval[0];
751                                 mcords[i][1] = mval[1];
752                                 
753                                 if(i) {
754                                         if(lasso) draw_lasso_select(mcords, i, 0);
755                                         else sdrawXORline(mcords[i-1][0], mcords[i-1][1], mcords[i][0], mcords[i][1]);
756                                         glFlush();
757                                 }
758                                 i++;
759                         }
760                         break;
761                 case MOUSEX:
762                         break;
763                 case LEFTMOUSE:
764                         break;
765                 default:
766                         if(event) end= 1;       /* blender returns 0 */
767                         break;
768                 }
769                 if (i == maxmoves || end == 1) break;
770         }
771         
772         /* clear */
773         if(lasso) draw_lasso_select(mcords, i, 1);
774         else for(a=1; a<i; a++) {
775                 sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
776         }
777         
778         persp(PERSP_VIEW);
779         glDrawBuffer(GL_BACK);
780         
781         if (i > 2) {
782                 if(lasso) do_lasso_select(mcords, i, (G.qual & LR_SHIFTKEY)==0);
783                 else {
784                         i = interpret_move(mcords, i);
785                         
786                         if(i) {
787                                 if(curarea->spacetype==SPACE_IPO) transform_ipo(i);
788                                 else if(curarea->spacetype==SPACE_OOPS) transform_oops('g', 0);
789                                 else {
790                                         int context;
791
792                                         if(curarea->spacetype==SPACE_IMAGE) context= CTX_NONE;
793                                         else context= CTX_NONE;
794
795                                         if(i=='g') {
796                                                 initTransform(TFM_TRANSLATION, context);
797                                                 Transform();
798                                         }
799                                         else if(i=='r') {
800                                                 initTransform(TFM_ROTATION, context);
801                                                 Transform();
802                                         }
803                                         else {
804                                                 initTransform(TFM_RESIZE, context);
805                                                 Transform();
806                                         }
807                                 }
808                         }
809                 }
810                 return 1;
811         }
812         return 0;
813 }
814
815 void mouse_cursor(void)
816 {
817         extern float zfac;      /* view.c */
818         float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
819         short mval[2], mx, my, lr_click=0;
820         
821         if(gesture()) return;
822         
823         getmouseco_areawin(mval);
824
825         mx= mval[0];
826         my= mval[1];
827         
828         fp= give_cursor();
829         
830         if(G.obedit && ((G.qual & LR_CTRLKEY) || get_mbut()&R_MOUSE )) lr_click= 1;
831         VECCOPY(oldcurs, fp);
832         
833         project_short_noclip(fp, mval);
834
835         initgrabz(fp[0], fp[1], fp[2]);
836         
837         if(mval[0]!=IS_CLIPPED) {
838                 
839                 window_to_3d(dvec, mval[0]-mx, mval[1]-my);
840                 VecSubf(fp, fp, dvec);
841                 
842         }
843         else {
844
845                 dx= ((float)(mx-(curarea->winx/2)))*zfac/(curarea->winx/2);
846                 dy= ((float)(my-(curarea->winy/2)))*zfac/(curarea->winy/2);
847                 
848                 fz= G.vd->persmat[0][3]*fp[0]+ G.vd->persmat[1][3]*fp[1]+ G.vd->persmat[2][3]*fp[2]+ G.vd->persmat[3][3];
849                 fz= fz/zfac;
850                 
851                 fp[0]= (G.vd->persinv[0][0]*dx + G.vd->persinv[1][0]*dy+ G.vd->persinv[2][0]*fz)-G.vd->ofs[0];
852                 fp[1]= (G.vd->persinv[0][1]*dx + G.vd->persinv[1][1]*dy+ G.vd->persinv[2][1]*fz)-G.vd->ofs[1];
853                 fp[2]= (G.vd->persinv[0][2]*dx + G.vd->persinv[1][2]*dy+ G.vd->persinv[2][2]*fz)-G.vd->ofs[2];
854         }
855         
856         allqueue(REDRAWVIEW3D, 1);
857         
858         if(lr_click) {
859                 if(G.obedit->type==OB_MESH) add_click_mesh();
860                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) addvert_Nurb(0);
861                 else if (G.obedit->type==OB_ARMATURE) addvert_armature();
862                 VECCOPY(fp, oldcurs);
863         }
864         
865 }
866
867 void deselectall(void)  /* is toggle */
868 {
869         Base *base;
870         int a=0;
871
872         base= FIRSTBASE;
873         while(base) {
874                 if TESTBASE(base) {
875                         a= 1;
876                         break;
877                 }
878                 base= base->next;
879         }
880         
881         base= FIRSTBASE;
882         while(base) {
883                 if(base->lay & G.vd->lay) {
884                         if(a) base->flag &= ~SELECT;
885                         else base->flag |= SELECT;
886                         base->object->flag= base->flag;
887                 }
888                 base= base->next;
889         }
890
891         allqueue(REDRAWVIEW3D, 0);
892         allqueue(REDRAWDATASELECT, 0);
893         allqueue(REDRAWNLA, 0);
894         
895         countall();
896         BIF_undo_push("(De)select all");
897 }
898
899 /* inverts object selection */
900 void selectswap(void)
901 {
902         Base *base;
903
904         for(base= FIRSTBASE; base; base= base->next) {
905                 if(base->lay & G.vd->lay) {
906                         if TESTBASE(base) base->flag &= ~SELECT;
907                         else base->flag |= SELECT;
908                         base->object->flag= base->flag;
909                 }
910         }
911
912         allqueue(REDRAWVIEW3D, 0);
913         allqueue(REDRAWDATASELECT, 0);
914         allqueue(REDRAWNLA, 0);
915         
916         countall();
917         BIF_undo_push("Select Inverse");
918 }
919
920
921 /* selects all objects of a particular type, on currently visible layers */
922 void selectall_type(short obtype) 
923 {
924         Base *base;
925         
926         base= FIRSTBASE;
927         while(base) {
928                 if((base->lay & G.vd->lay) && (base->object->type == obtype)) {
929                         base->flag |= SELECT;
930                         base->object->flag= base->flag;
931                 }
932                 base= base->next;
933         }
934
935         allqueue(REDRAWVIEW3D, 0);
936         allqueue(REDRAWDATASELECT, 0);
937         allqueue(REDRAWNLA, 0);
938         
939         countall();
940         BIF_undo_push("Select all per type");
941 }
942 /* selects all objects on a particular layer */
943 void selectall_layer(unsigned int layernum) 
944 {
945         Base *base;
946         
947         base= FIRSTBASE;
948         while(base) {
949                 if (base->lay == (1<< (layernum -1))) {
950                         base->flag |= SELECT;
951                         base->object->flag= base->flag;
952                 }
953                 base= base->next;
954         }
955
956         allqueue(REDRAWVIEW3D, 0);
957         allqueue(REDRAWDATASELECT, 0);
958         allqueue(REDRAWNLA, 0);
959         
960         countall();
961         BIF_undo_push("Select all per layer");
962 }
963
964 static void deselectall_except(Base *b)   /* deselect all except b */
965 {
966         Base *base;
967
968         base= FIRSTBASE;
969         while(base) {
970                 if (base->flag & SELECT) {
971                         if(b!=base) {
972                                 base->flag &= ~SELECT;
973                                 base->object->flag= base->flag;
974                         }
975                 }
976                 base= base->next;
977         }
978 }
979
980 #if 0
981 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
982 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
983 {
984         Base *base;
985         unsigned int *bufmin,*bufmax;
986         int a,b,rc,tel,aantal,dirvec[4][2],maxob;
987         unsigned int retval=0;
988         
989         base= LASTBASE;
990         if(base==0) return 0;
991         maxob= base->selcol;
992
993         aantal= (size-1)/2;
994         rc= 0;
995
996         dirvec[0][0]= 1;
997         dirvec[0][1]= 0;
998         dirvec[1][0]= 0;
999         dirvec[1][1]= -size;
1000         dirvec[2][0]= -1;
1001         dirvec[2][1]= 0;
1002         dirvec[3][0]= 0;
1003         dirvec[3][1]= size;
1004
1005         bufmin= buf;
1006         bufmax= buf+ size*size;
1007         buf+= aantal*size+ aantal;
1008
1009         for(tel=1;tel<=size;tel++) {
1010
1011                 for(a=0;a<2;a++) {
1012                         for(b=0;b<tel;b++) {
1013
1014                                 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
1015                                 if( *buf==dontdo ) retval= dontdo;      /* if only color dontdo is available, still return dontdo */
1016                                 
1017                                 buf+= (dirvec[rc][0]+dirvec[rc][1]);
1018
1019                                 if(buf<bufmin || buf>=bufmax) return retval;
1020                         }
1021                         rc++;
1022                         rc &= 3;
1023                 }
1024         }
1025         return retval;
1026 }
1027 #endif
1028
1029 #define SELECTSIZE      51
1030
1031 void set_active_base(Base *base)
1032 {
1033         Base *tbase;
1034         
1035         BASACT= base;
1036         
1037         if(base) {
1038                 /* signals to buttons */
1039                 redraw_test_buttons(base->object);
1040                 
1041                 /* signal to ipo */
1042                 allqueue(REDRAWIPO, base->object->ipowin);
1043                 allqueue(REDRAWACTION, 0);
1044                 allqueue(REDRAWNLA, 0);
1045                 
1046                 /* signal to action */
1047                 select_actionchannel_by_name(base->object->action, "Object", 1);
1048                 
1049                 /* disable temporal locks */
1050                 for(tbase=FIRSTBASE; tbase; tbase= tbase->next) {
1051                         if(base!=tbase && (tbase->object->shapeflag & OB_SHAPE_TEMPLOCK)) {
1052                                 tbase->object->shapeflag &= ~OB_SHAPE_TEMPLOCK;
1053                                 DAG_object_flush_update(G.scene, tbase->object, OB_RECALC_DATA);
1054                         }
1055                 }
1056         }
1057 }
1058
1059 void set_active_object(Object *ob)
1060 {
1061         Base *base;
1062         
1063         base= FIRSTBASE;
1064         while(base) {
1065                 if(base->object==ob) {
1066                         set_active_base(base);
1067                         return;
1068                 }
1069                 base= base->next;
1070         }
1071 }
1072
1073 static void select_all_from_groups(Base *basact)
1074 {
1075         Group *group;
1076         GroupObject *go;
1077         int deselect= basact->flag & SELECT;
1078         
1079         for(group= G.main->group.first; group; group= group->id.next) {
1080                 if(object_in_group(basact->object, group)) {
1081                         for(go= group->gobject.first; go; go= go->next) {
1082                                 if(deselect) go->ob->flag &= ~SELECT;
1083                                 else go->ob->flag |= SELECT;
1084                         }
1085                 }
1086         }
1087         /* sync bases */
1088         for(basact= G.scene->base.first; basact; basact= basact->next) {
1089                 if(basact->object->flag & SELECT)
1090                         basact->flag |= SELECT;
1091                 else
1092                         basact->flag &= ~SELECT;
1093         }
1094 }
1095
1096 /* The max number of menu items in an object select menu */
1097 #define SEL_MENU_SIZE 22
1098
1099 static Base *mouse_select_menu(unsigned int *buffer, int hits, short *mval)
1100 {
1101         Base *baseList[SEL_MENU_SIZE]={NULL}; /*baseList is used to store all possible bases to bring up a menu */
1102         Base *base;
1103         short baseCount = 0;
1104         char menuText[20 + SEL_MENU_SIZE*32] = "Select Object%t";       // max ob name = 22
1105         char str[32];
1106         
1107         for(base=FIRSTBASE; base; base= base->next) {
1108                 if(base->lay & G.vd->lay) {
1109                         baseList[baseCount] = NULL;
1110                         
1111                         /* two selection methods, the CTRL select uses max dist of 15 */
1112                         if(buffer) {
1113                                 int a;
1114                                 for(a=0; a<hits; a++) {
1115                                         /* index was converted */
1116                                         if(base->selcol==buffer[ (4 * a) + 3 ]) baseList[baseCount] = base;
1117                                 }
1118                         }
1119                         else {
1120                                 int temp, dist=15;
1121                                 
1122                                 project_short(base->object->obmat[3], &base->sx);
1123                                 
1124                                 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
1125                                 if(temp<dist ) baseList[baseCount] = base;
1126                         }
1127                         
1128                         if(baseList[baseCount]) {
1129                                 if (baseCount < SEL_MENU_SIZE) {
1130                                         baseList[baseCount] = base;
1131                                         sprintf(str, "|%s %%x%d", base->object->id.name+2, baseCount+1);        // max ob name == 22
1132                                         strcat(menuText, str);
1133                                         baseCount++;
1134                                 }
1135                         }
1136                 }
1137         }
1138         
1139         if(baseCount<=1) return baseList[0];
1140         else {
1141                 baseCount = pupmenu(menuText);
1142                 
1143                 if (baseCount != -1) { /* If nothing is selected then dont do anything */
1144                         return baseList[baseCount-1];
1145                 }
1146                 else return NULL;
1147         }
1148 }
1149
1150 /* we want a select buffer with bones, if there are... */
1151 /* so check three selection levels and compare */
1152 static short mixed_bones_object_selectbuffer(unsigned int *buffer, short *mval)
1153 {
1154         int offs;
1155         short a, hits15, hits9=0, hits5=0;
1156         short has_bones15=0, has_bones9=0, has_bones5=0;
1157         
1158         hits15= view3d_opengl_select(buffer, MAXPICKBUF, mval[0]-14, mval[1]-14, mval[0]+14, mval[1]+14);
1159         if(hits15) {
1160                 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
1161                 
1162                 offs= 4*hits15;
1163                 hits9= view3d_opengl_select(buffer+offs, MAXPICKBUF-offs, mval[0]-9, mval[1]-9, mval[0]+9, mval[1]+9);
1164                 if(hits9) {
1165                         for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
1166                         
1167                         offs+= 4*hits9;
1168                         hits5= view3d_opengl_select(buffer+offs, MAXPICKBUF-offs, mval[0]-5, mval[1]-5, mval[0]+5, mval[1]+5);
1169                         if(hits5) {
1170                                 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
1171                         }
1172                 }
1173                 
1174                 if(has_bones5) {
1175                         offs= 4*hits15 + 4*hits9;
1176                         memcpy(buffer, buffer+offs, 4*offs);
1177                         return hits5;
1178                 }
1179                 if(has_bones9) {
1180                         offs= 4*hits15;
1181                         memcpy(buffer, buffer+offs, 4*offs);
1182                         return hits9;
1183                 }
1184                 if(has_bones15) {
1185                         return hits15;
1186                 }
1187                 
1188                 if(hits5) {
1189                         offs= 4*hits15 + 4*hits9;
1190                         memcpy(buffer, buffer+offs, 4*offs);
1191                         return hits5;
1192                 }
1193                 if(hits9) {
1194                         offs= 4*hits15;
1195                         memcpy(buffer, buffer+offs, 4*offs);
1196                         return hits9;
1197                 }
1198                 return hits15;
1199         }
1200         
1201         return 0;
1202 }
1203
1204 void mouse_select(void)
1205 {
1206         Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
1207         unsigned int buffer[MAXPICKBUF];
1208         int temp, a, dist=100;
1209         short hits, mval[2];
1210
1211         /* always start list from basact in wire mode */
1212         startbase=  FIRSTBASE;
1213         if(BASACT && BASACT->next) startbase= BASACT->next;
1214
1215         getmouseco_areawin(mval);
1216         
1217         /* This block uses the control key to make the object selected by its centre point rather then its contents */
1218         if(G.obedit==0 && (G.qual & LR_CTRLKEY)) {
1219                 
1220                 if(G.qual & LR_ALTKEY) basact= mouse_select_menu(NULL, 0, mval);
1221                 else {
1222                         base= startbase;
1223                         while(base) {
1224                                 
1225                                 if(base->lay & G.vd->lay) {
1226                                         
1227                                         project_short(base->object->obmat[3], &base->sx);
1228                                         
1229                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
1230                                         if(base==BASACT) temp+=10;
1231                                         if(temp<dist ) {
1232                                                 
1233                                                 dist= temp;
1234                                                 basact= base;
1235                                         }
1236                                 }
1237                                 base= base->next;
1238                                 
1239                                 if(base==0) base= FIRSTBASE;
1240                                 if(base==startbase) break;
1241                         }
1242                 }
1243         }
1244         else {
1245                 /* if objects have posemode set, the bones are in the same selection buffer */
1246                 
1247                 hits= mixed_bones_object_selectbuffer(buffer, mval);
1248                 
1249                 if(hits>0) {
1250                         int has_bones= 0;
1251                         
1252                         for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1253
1254                         if(has_bones==0 && (G.qual & LR_ALTKEY)) 
1255                                 basact= mouse_select_menu(buffer, hits, mval);
1256                         else {
1257                                 static short lastmval[2]={-100, -100};
1258                                 int donearest= 0;
1259                                 
1260                                 /* define if we use solid nearest select or not */
1261                                 if(G.vd->drawtype>OB_WIRE) {
1262                                         donearest= 1;
1263                                         if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
1264                                                 if(!has_bones)  // hrms, if theres bones we always do nearest
1265                                                         donearest= 0;
1266                                         }
1267                                 }
1268                                 lastmval[0]= mval[0]; lastmval[1]= mval[1];
1269                                 
1270                                 if(donearest) {
1271                                         unsigned int min= 0xFFFFFFFF;
1272                                         int selcol= 0, notcol=0;
1273                                         
1274
1275                                         if(has_bones) {
1276                                                 /* we skip non-bone hits */
1277                                                 for(a=0; a<hits; a++) {
1278                                                         if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
1279                                                                 min= buffer[4*a+1];
1280                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1281                                                         }
1282                                                 }
1283                                         }
1284                                         else {
1285                                                 /* only exclude active object when it is selected... */
1286                                                 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol; 
1287                                         
1288                                                 for(a=0; a<hits; a++) {
1289                                                         if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1290                                                                 min= buffer[4*a+1];
1291                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1292                                                         }
1293                                                 }
1294                                         }
1295
1296                                         base= FIRSTBASE;
1297                                         while(base) {
1298                                                 if(base->lay & G.vd->lay) {
1299                                                         if(base->selcol==selcol) break;
1300                                                 }
1301                                                 base= base->next;
1302                                         }
1303                                         if(base) basact= base;
1304                                 }
1305                                 else {
1306                                         
1307                                         base= startbase;
1308                                         while(base) {
1309                                                 if(base->lay & G.vd->lay) {
1310                                                         for(a=0; a<hits; a++) {
1311                                                                 if(has_bones) {
1312                                                                         /* skip non-bone objects */
1313                                                                         if((buffer[4*a+3] & 0xFFFF0000)) {
1314                                                                                 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1315                                                                                         basact= base;
1316                                                                         }
1317                                                                 }
1318                                                                 else {
1319                                                                         if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1320                                                                                 basact= base;
1321                                                                 }
1322                                                         }
1323                                                 }
1324                                                 
1325                                                 if(basact) break;
1326                                                 
1327                                                 base= base->next;
1328                                                 if(base==NULL) base= FIRSTBASE;
1329                                                 if(base==startbase) break;
1330                                         }
1331                                 }
1332                         }
1333                         
1334                         if(has_bones && basact) {
1335                                 if( do_pose_selectbuffer(basact, buffer, hits) ) {      // then bone is found
1336                                 
1337                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1338                                         if(G.f & G_WEIGHTPAINT) {
1339                                                 /* we make the armature selected */
1340                                                 basact->flag|= SELECT;
1341                                                 basact->object->flag= basact->flag;
1342                                                 /* prevent activating */
1343                                                 basact= NULL;
1344                                         }
1345                                 }
1346                                 /* prevent bone selecting to pass on to object selecting */
1347                                 if(basact==BASACT)
1348                                         basact= NULL;
1349                         }
1350                 }
1351         }
1352         
1353         /* so, do we have something selected? */
1354         if(basact) {
1355                 
1356                 if(G.obedit) {
1357                         /* only do select */
1358                         deselectall_except(basact);
1359                         basact->flag |= SELECT;
1360                 }
1361                 else {
1362                         oldbasact= BASACT;
1363                         BASACT= basact;
1364                         
1365                         if((G.qual & LR_SHIFTKEY)==0) {
1366                                 deselectall_except(basact);
1367                                 basact->flag |= SELECT;
1368                         }
1369                         else if(G.qual==(LR_SHIFTKEY|LR_ALTKEY)) {
1370                                 select_all_from_groups(basact);
1371                         }
1372                         else {
1373                                 if(basact->flag & SELECT) {
1374                                         if(basact==oldbasact)
1375                                                 basact->flag &= ~SELECT;
1376                                 }
1377                                 else basact->flag |= SELECT;
1378                         }
1379
1380                         // copy
1381                         basact->object->flag= basact->flag;
1382                         
1383                         if(oldbasact != basact) {
1384                                 set_active_base(basact);
1385                         }
1386
1387                         // for visual speed, only in wire mode
1388                         if(G.vd->drawtype==OB_WIRE) {
1389                                 /* however, not for posemodes */
1390                                 if(basact->object->flag & OB_POSEMODE);
1391                                 else if(oldbasact && (oldbasact->object->flag & OB_POSEMODE));
1392                                 else {
1393                                         if(oldbasact && oldbasact != basact && (oldbasact->lay & G.vd->lay)) 
1394                                                 draw_object_ext(oldbasact);
1395                                         draw_object_ext(basact);
1396                                 }
1397                         }
1398                         
1399                         /* selecting a non-mesh, should end a couple of modes... */
1400                         if(basact->object->type!=OB_MESH) {
1401                                 if(G.f & G_WEIGHTPAINT) {
1402                                         set_wpaint();   /* toggle */
1403                                 }
1404                                 if(G.f & G_VERTEXPAINT) {
1405                                         set_vpaint();   /* toggle */
1406                                 }
1407                                 if(G.f & G_FACESELECT) {
1408                                         set_faceselect();       /* toggle */
1409                                 }
1410                         }
1411                         
1412                         allqueue(REDRAWBUTSLOGIC, 0);
1413                         allqueue(REDRAWDATASELECT, 0);
1414                         allqueue(REDRAWBUTSOBJECT, 0);
1415                         allqueue(REDRAWACTION, 0);
1416                         allqueue(REDRAWNLA, 0);
1417                         allqueue(REDRAWTIME, 0);
1418                         allqueue(REDRAWHEADERS, 0);     /* To force display update for the posebutton */
1419                 }
1420                 /* also because multiple 3d windows can be open */
1421                 allqueue(REDRAWVIEW3D, 0);
1422                 
1423         }
1424
1425         countall();
1426
1427         rightmouse_transform(); // does undo push!
1428 }
1429
1430 /* ------------------------------------------------------------------------- */
1431
1432 static int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1433 {
1434         int radsq= rad*rad;
1435         float v1[2], v2[2], v3[2];
1436         
1437         // check points in circle itself
1438         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1439         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1440         
1441         // pointdistline
1442         v3[0]= centx;
1443         v3[1]= centy;
1444         v1[0]= x1;
1445         v1[1]= y1;
1446         v2[0]= x2;
1447         v2[1]= y2;
1448         
1449         if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1450         
1451         return 0;
1452 }
1453
1454 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1455 {
1456         struct { rcti *rect; int select; } *data = userData;
1457
1458         if (BLI_in_rcti(data->rect, x, y)) {
1459                 if (bp) {
1460                         bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1461                 } else {
1462                         if (beztindex==0) {
1463                                 bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
1464                         } else if (beztindex==1) {
1465                                 bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
1466                         } else {
1467                                 bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
1468                         }
1469                 }
1470         }
1471 }
1472 static void do_nurbs_box_select(rcti *rect, int select)
1473 {
1474         struct { rcti *rect; int select; } data;
1475
1476         data.rect = rect;
1477         data.select = select;
1478
1479         nurbs_foreachScreenVert(do_nurbs_box_select__doSelect, &data);
1480 }
1481
1482 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1483 {
1484         struct { rcti *rect; int select; } *data = userData;
1485
1486         if (BLI_in_rcti(data->rect, x, y)) {
1487                 bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1488         }
1489 }
1490 static void do_lattice_box_select(rcti *rect, int select)
1491 {
1492         struct { rcti *rect; int select, pass, done; } data;
1493
1494         data.rect = rect;
1495         data.select = select;
1496
1497         lattice_foreachScreenVert(do_lattice_box_select__doSelect, &data);
1498 }
1499
1500 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1501 {
1502         struct { rcti *rect; short select, pass, done; } *data = userData;
1503
1504         if (BLI_in_rcti(data->rect, x, y)) {
1505                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1506         }
1507 }
1508 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1509 {
1510         struct { rcti *rect; short select, pass, done; } *data = userData;
1511
1512         if(EM_check_backbuf(em_solidoffs+index)) {
1513                 if (data->pass==0) {
1514                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1515                                 EM_select_edge(eed, data->select);
1516                                 data->done = 1;
1517                         }
1518                 } else {
1519                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1520                                 EM_select_edge(eed, data->select);
1521                         }
1522                 }
1523         }
1524 }
1525 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1526 {
1527         struct { rcti *rect; short select, pass, done; } *data = userData;
1528
1529         if (BLI_in_rcti(data->rect, x, y)) {
1530                 EM_select_face_fgon(efa, data->select);
1531         }
1532 }
1533 static void do_mesh_box_select(rcti *rect, int select)
1534 {
1535         struct { rcti *rect; short select, pass, done; } data;
1536         EditMesh *em = G.editMesh;
1537         int bbsel;
1538         
1539         data.rect = rect;
1540         data.select = select;
1541         data.pass = 0;
1542         data.done = 0;
1543
1544         bbsel= EM_init_backbuf_border(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1545
1546         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1547                 if (bbsel) {
1548                         EM_backbuf_checkAndSelectVerts(em, select);
1549                 } else {
1550                         mesh_foreachScreenVert(do_mesh_box_select__doSelectVert, &data, 1);
1551                 }
1552         }
1553         if(G.scene->selectmode & SCE_SELECT_EDGE) {
1554                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1555
1556                 data.pass = 0;
1557                 mesh_foreachScreenEdge(do_mesh_box_select__doSelectEdge, &data, 0);
1558
1559                 if (data.done==0) {
1560                         data.pass = 1;
1561                         mesh_foreachScreenEdge(do_mesh_box_select__doSelectEdge, &data, 0);
1562                 }
1563         }
1564         
1565         if(G.scene->selectmode & SCE_SELECT_FACE) {
1566                 if(bbsel) {
1567                         EM_backbuf_checkAndSelectFaces(em, select);
1568                 } else {
1569                         mesh_foreachScreenFace(do_mesh_box_select__doSelectFace, &data);
1570                 }
1571         }
1572         
1573         EM_free_backbuf();
1574                 
1575         EM_selectmode_flush();
1576 }
1577
1578 /**
1579  * Does the 'borderselect' command. (Select verts based on selecting with a 
1580  * border: key 'b'). All selecting seems to be done in the get_border part.
1581  */
1582 void borderselect(void)
1583 {
1584         rcti rect;
1585         Base *base;
1586         MetaElem *ml;
1587         unsigned int buffer[MAXPICKBUF];
1588         int a, index;
1589         short hits, val;
1590
1591         if(G.obedit==NULL && (G.f & G_FACESELECT)) {
1592                 face_borderselect();
1593                 return;
1594         }
1595         
1596         setlinestyle(2);
1597         val= get_border(&rect, 3);
1598         setlinestyle(0);
1599         
1600         if(val==0)
1601                 return;
1602         
1603         if(G.obedit) {
1604                 if(G.obedit->type==OB_MESH) {
1605                         do_mesh_box_select(&rect, (val==LEFTMOUSE));
1606                         allqueue(REDRAWVIEW3D, 0);
1607                 }
1608                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
1609                         do_nurbs_box_select(&rect, val==LEFTMOUSE);
1610                         allqueue(REDRAWVIEW3D, 0);
1611                 }
1612                 else if(G.obedit->type==OB_MBALL) {
1613                         hits= view3d_opengl_select(buffer, MAXPICKBUF, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1614                         
1615                         ml= editelems.first;
1616                         
1617                         while(ml) {
1618                                 for(a=0; a<hits; a++) {
1619                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1620                                                 ml->flag |= MB_SCALE_RAD;
1621                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1622                                                 else ml->flag &= ~SELECT;
1623                                                 break;
1624                                         }
1625                                         if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1626                                                 ml->flag &= ~MB_SCALE_RAD;
1627                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1628                                                 else ml->flag &= ~SELECT;
1629                                                 break;
1630                                         }
1631                                 }
1632                                 ml= ml->next;
1633                         }
1634                         allqueue(REDRAWVIEW3D, 0);
1635                 }
1636                 else if(G.obedit->type==OB_ARMATURE) {
1637                         EditBone *ebone;
1638                         
1639                         /* clear flag we use to detect point was affected */
1640                         for(ebone= G.edbo.first; ebone; ebone= ebone->next)
1641                                 ebone->flag &= ~BONE_DONE;
1642                         
1643                         hits= view3d_opengl_select(buffer, MAXPICKBUF, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1644                         
1645                         /* first we only check points inside the border */
1646                         for (a=0; a<hits; a++){
1647                                 index = buffer[(4*a)+3];
1648                                 if (index!=-1) {
1649                                         ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1650                                         if (index & BONESEL_TIP) {
1651                                                 ebone->flag |= BONE_DONE;
1652                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
1653                                                 else ebone->flag &= ~BONE_TIPSEL;
1654                                         }
1655                                         
1656                                         if (index & BONESEL_ROOT) {
1657                                                 ebone->flag |= BONE_DONE;
1658                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
1659                                                 else ebone->flag &= ~BONE_ROOTSEL;
1660                                         }
1661                                 }
1662                         }
1663                         
1664                         /* now we have to flush tag from parents... */
1665                         for(ebone= G.edbo.first; ebone; ebone= ebone->next) {
1666                                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1667                                         if(ebone->parent->flag & BONE_DONE)
1668                                                 ebone->flag |= BONE_DONE;
1669                                 }
1670                         }
1671                         
1672                         /* only select/deselect entire bones when no points where in the rect */
1673                         for (a=0; a<hits; a++){
1674                                 index = buffer[(4*a)+3];
1675                                 if (index!=-1) {
1676                                         ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1677                                         if (index & BONESEL_BONE) {
1678                                                 if(!(ebone->flag & BONE_DONE)) {
1679                                                         if (val==LEFTMOUSE)
1680                                                                 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1681                                                         else
1682                                                                 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1683                                                 }
1684                                         }
1685                                 }
1686                         }
1687                         
1688                         allqueue(REDRAWBUTSEDIT, 0);
1689                         allqueue(REDRAWBUTSOBJECT, 0);
1690                         allqueue(REDRAWACTION, 0);
1691                         allqueue(REDRAWVIEW3D, 0);
1692                 }
1693                 else if(G.obedit->type==OB_LATTICE) {
1694                         do_lattice_box_select(&rect, val==LEFTMOUSE);
1695                         allqueue(REDRAWVIEW3D, 0);
1696                 }
1697         }
1698         else {  // no editmode, unified for bones and objects
1699                 Bone *bone;
1700                 unsigned int *vbuffer=NULL; /* selection buffer */
1701                 unsigned int *col;                      /* color in buffer      */
1702                 short selecting = 0;
1703
1704                 if (val==LEFTMOUSE)
1705                         selecting = 1;
1706                 
1707                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1708                 vbuffer = MEM_mallocN(4 * (G.totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1709                 hits= view3d_opengl_select(vbuffer, 4*(G.totobj+MAXPICKBUF), rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1710                 /*
1711                 LOGIC NOTES (theeth):
1712                 The buffer and ListBase have the same relative order, which makes the selection
1713                 very simple. Loop through both data sets at the same time, if the color
1714                 is the same as the object, we have a hit and can move to the next color
1715                 and object pair, if not, just move to the next object,
1716                 keeping the same color until we have a hit.
1717
1718                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1719                 does it incorrectly.
1720                 */
1721
1722                 if (hits) { /* no need to loop if there's no hit */
1723                         base= FIRSTBASE;
1724                         col = vbuffer + 3;
1725                         while(base && hits) {
1726                                 Base *next = base->next;
1727                                 if(base->lay & G.vd->lay) {
1728                                         while (base->selcol == (*col & 0xFFFF)) {       // we got an object
1729                                                 
1730                                                 if(*col & 0xFFFF0000) {                                 // we got a bone
1731                                                         bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1732                                                         if(bone) {
1733                                                                 if(selecting) {
1734                                                                         bone->flag |= BONE_SELECTED;
1735                                                                         select_actionchannel_by_name(base->object->action, bone->name, 1);
1736                                                                 }
1737                                                                 else {
1738                                                                         bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1739                                                                         select_actionchannel_by_name(base->object->action, bone->name, 0);
1740                                                                 }
1741                                                         }
1742                                                 }
1743                                                 else {
1744                                                         if (selecting)
1745                                                                 base->flag |= SELECT;
1746                                                         else
1747                                                                 base->flag &= ~SELECT;
1748
1749                                                         base->object->flag= base->flag;
1750                                                 }
1751
1752                                                 col+=4; /* next color */
1753                                                 hits--;
1754                                                 if(hits==0) break;
1755                                         }
1756                                 }
1757                                 
1758                                 base= next;
1759                         }
1760                 }
1761                 /* frontbuffer flush */
1762                 glFlush();
1763
1764                 MEM_freeN(vbuffer);
1765                 
1766                 allqueue(REDRAWDATASELECT, 0);
1767                 allqueue(REDRAWBUTSLOGIC, 0);
1768                 allqueue(REDRAWNLA, 0);
1769         }
1770
1771         countall();
1772         
1773         allqueue(REDRAWBUTSOBJECT, 0);
1774         allqueue(REDRAWVIEW3D, 0);
1775         allqueue(REDRAWINFO, 0);
1776
1777         BIF_undo_push("Border select");
1778         
1779 } /* end of borderselect() */
1780
1781 /* ------------------------------------------------------------------------- */
1782
1783 /** The following functions are quick & dirty callback functions called
1784   * on the Circle select function (press B twice in Editmode)
1785   * They were torn out of the circle_select to make the latter more reusable
1786   * The callback version of circle_select (called circle_selectCB) was moved
1787   * to edit.c because of it's (wanted) generality.
1788
1789         XXX These callback functions are still dirty, because they call globals... 
1790   */
1791
1792 static void mesh_selectionCB__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1793 {
1794         struct { short select, mval[2]; float radius; } *data = userData;
1795         int mx = x - data->mval[0], my = y - data->mval[1];
1796         float r = sqrt(mx*mx + my*my);
1797
1798         if (r<=data->radius) {
1799                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1800         }
1801 }
1802 static void mesh_selectionCB__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1803 {
1804         struct { short select, mval[2]; float radius; } *data = userData;
1805
1806         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1807                 EM_select_edge(eed, data->select);
1808         }
1809 }
1810 static void mesh_selectionCB__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1811 {
1812         struct { short select, mval[2]; float radius; } *data = userData;
1813         int mx = x - data->mval[0], my = y - data->mval[1];
1814         float r = sqrt(mx*mx + my*my);
1815
1816         if (r<=data->radius) {
1817                 EM_select_face_fgon(efa, data->select);
1818         }
1819 }
1820 static void mesh_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1821 {
1822         struct { short select, mval[2]; float radius; } data;
1823         EditMesh *em = G.editMesh;
1824         int bbsel;
1825
1826         if(!G.obedit && (G.f&G_FACESELECT)) {
1827                 Mesh *me = get_mesh(OBACT);
1828
1829                 if (me) {
1830                         em_vertoffs= me->totface+1;     // max index array
1831
1832                         bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
1833                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1834                         EM_free_backbuf();
1835
1836                         object_tface_flags_changed(OBACT, 0);
1837                 }
1838
1839                 return;
1840         }
1841
1842         bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
1843         
1844         data.select = (selecting==LEFTMOUSE);
1845         data.mval[0] = mval[0];
1846         data.mval[1] = mval[1];
1847         data.radius = rad;
1848
1849         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1850                 if(bbsel) {
1851                         EM_backbuf_checkAndSelectVerts(em, selecting==LEFTMOUSE);
1852                 } else {
1853                         mesh_foreachScreenVert(mesh_selectionCB__doSelectVert, &data, 1);
1854                 }
1855         }
1856
1857         if(G.scene->selectmode & SCE_SELECT_EDGE) {
1858                 if (bbsel) {
1859                         EM_backbuf_checkAndSelectEdges(em, selecting==LEFTMOUSE);
1860                 } else {
1861                         mesh_foreachScreenEdge(mesh_selectionCB__doSelectEdge, &data, 0);
1862                 }
1863         }
1864         
1865         if(G.scene->selectmode & SCE_SELECT_FACE) {
1866                 if(bbsel) {
1867                         EM_backbuf_checkAndSelectFaces(em, selecting==LEFTMOUSE);
1868                 } else {
1869                         mesh_foreachScreenFace(mesh_selectionCB__doSelectFace, &data);
1870                 }
1871         }
1872
1873         EM_free_backbuf();
1874         EM_selectmode_flush();
1875 }
1876
1877
1878 static void nurbscurve_selectionCB__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1879 {
1880         struct { short select, mval[2]; float radius; } *data = userData;
1881         int mx = x - data->mval[0], my = y - data->mval[1];
1882         float r = sqrt(mx*mx + my*my);
1883
1884         if (r<=data->radius) {
1885                 if (bp) {
1886                         bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1887                 } else {
1888                         if (beztindex==0) {
1889                                 bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
1890                         } else if (beztindex==1) {
1891                                 bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
1892                         } else {
1893                                 bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
1894                         }
1895                 }
1896         }
1897 }
1898 static void nurbscurve_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1899 {
1900         struct { short select, mval[2]; float radius; } data;
1901
1902         data.select = (selecting==LEFTMOUSE);
1903         data.mval[0] = mval[0];
1904         data.mval[1] = mval[1];
1905         data.radius = rad;
1906
1907         nurbs_foreachScreenVert(nurbscurve_selectionCB__doSelect, &data);
1908 }
1909
1910
1911 static void latticecurve_selectionCB__doSelect(void *userData, BPoint *bp, int x, int y)
1912 {
1913         struct { short select, mval[2]; float radius; } *data = userData;
1914         int mx = x - data->mval[0], my = y - data->mval[1];
1915         float r = sqrt(mx*mx + my*my);
1916
1917         if (r<=data->radius) {
1918                 bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1919         }
1920 }
1921 static void lattice_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1922 {
1923         struct { short select, mval[2]; float radius; } data;
1924
1925         data.select = (selecting==LEFTMOUSE);
1926         data.mval[0] = mval[0];
1927         data.mval[1] = mval[1];
1928         data.radius = rad;
1929
1930         lattice_foreachScreenVert(latticecurve_selectionCB__doSelect, &data);
1931 }
1932
1933 /** Callbacks for selection in Editmode */
1934
1935 void obedit_selectionCB(short selecting, Object *editobj, short *mval, float rad) 
1936 {
1937         switch(editobj->type) {         
1938         case OB_MESH:
1939                 mesh_selectionCB(selecting, editobj, mval, rad);
1940                 break;
1941         case OB_CURVE:
1942         case OB_SURF:
1943                 nurbscurve_selectionCB(selecting, editobj, mval, rad);
1944                 break;
1945         case OB_LATTICE:
1946                 lattice_selectionCB(selecting, editobj, mval, rad);
1947                 break;
1948         default:
1949                 return;
1950         }
1951
1952         draw_sel_circle(0, 0, 0, 0, 0); /* signal */
1953         force_draw(0);
1954 }
1955
1956 void set_render_border(void)
1957 {
1958         rcti rect;
1959         short val;
1960
1961         if(G.vd->persp!=2) return;
1962         
1963         val= get_border(&rect, 2);
1964         if(val) {
1965                 rcti vb;
1966
1967                 calc_viewborder(G.vd, &vb);
1968
1969                 G.scene->r.border.xmin= (float) (rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
1970                 G.scene->r.border.ymin= (float) (rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
1971                 G.scene->r.border.xmax= (float) (rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
1972                 G.scene->r.border.ymax= (float) (rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
1973                 
1974                 CLAMP(G.scene->r.border.xmin, 0.0, 1.0);
1975                 CLAMP(G.scene->r.border.ymin, 0.0, 1.0);
1976                 CLAMP(G.scene->r.border.xmax, 0.0, 1.0);
1977                 CLAMP(G.scene->r.border.ymax, 0.0, 1.0);
1978                 
1979                 allqueue(REDRAWVIEWCAM, 1);
1980                 // if it was not set, we do this
1981                 G.scene->r.mode |= R_BORDER;
1982                 allqueue(REDRAWBUTSSCENE, 1);
1983         }
1984 }
1985
1986
1987
1988 void fly(void)
1989 {
1990         float speed=0.0, speedo=1.0, zspeed=0.0, dvec[3], *quat, mat[3][3];
1991         float oldvec[3], oldrot[3];
1992         int loop=1;
1993         unsigned short toets;
1994         short val, cent[2];
1995         short mval[2];
1996         
1997         if(curarea->spacetype!=SPACE_VIEW3D) return;
1998         if(G.vd->camera == 0) return;
1999         if(G.vd->persp<2) return;
2000         
2001         VECCOPY(oldvec, G.vd->camera->loc);
2002         VECCOPY(oldrot, G.vd->camera->rot);
2003         
2004         cent[0]= curarea->winrct.xmin+(curarea->winx)/2;
2005         cent[1]= curarea->winrct.ymin+(curarea->winy)/2;
2006         
2007         warp_pointer(cent[0], cent[1]);
2008         
2009         /* we have to rely on events to give proper mousecoords after a warp_pointer */
2010         mval[0]= cent[0]=  (curarea->winx)/2;
2011         mval[1]= cent[1]=  (curarea->winy)/2;
2012         
2013         headerprint("Fly");
2014         
2015         while(loop) {
2016                 
2017
2018                 while(qtest()) {
2019                         
2020                         toets= extern_qread(&val);
2021                         
2022                         if(val) {
2023                                 if(toets==MOUSEY) getmouseco_areawin(mval);
2024                                 else if(toets==ESCKEY) {
2025                                         VECCOPY(G.vd->camera->loc, oldvec);
2026                                         VECCOPY(G.vd->camera->rot, oldrot);
2027                                         loop= 0;
2028                                         break;
2029                                 }
2030                                 else if(toets==SPACEKEY) {
2031                                         loop= 0;
2032                                         BIF_undo_push("Fly camera");
2033                                         break;
2034                                 }
2035                                 else if(toets==LEFTMOUSE) {
2036                                         speed+= G.vd->grid/75.0;
2037                                         if(get_mbut()&M_MOUSE) speed= 0.0;
2038                                 }
2039                                 else if(toets==MIDDLEMOUSE) {
2040                                         speed-= G.vd->grid/75.0;
2041                                         if(get_mbut()&L_MOUSE) speed= 0.0;
2042                                 }
2043                         }
2044                 }
2045                 if(loop==0) break;
2046                 
2047                 /* define dvec */
2048                 val= mval[0]-cent[0];
2049                 if(val>20) val-= 20; else if(val< -20) val+= 20; else val= 0;
2050                 dvec[0]= 0.000001*val*val;
2051                 if(val>0) dvec[0]= -dvec[0];
2052                 
2053                 val= mval[1]-cent[1];
2054                 if(val>20) val-= 20; else if(val< -20) val+= 20; else val= 0;
2055                 dvec[1]= 0.000001*val*val;
2056                 if(val>0) dvec[1]= -dvec[1];
2057                 
2058                 dvec[2]= 1.0;
2059                 
2060                 zspeed= 0.0;
2061                 if(get_qual()&LR_CTRLKEY) zspeed= -G.vd->grid/25.0;
2062                 if(get_qual()&LR_ALTKEY) zspeed= G.vd->grid/25.0;
2063                 
2064                 if(speedo!=0.0 || zspeed!=0.0 || dvec[0]!=0.0 || dvec[1]!=0.0) {
2065                 
2066                         Normalise(dvec);
2067                         
2068                         Mat3CpyMat4(mat, G.vd->viewinv);
2069                         Mat3MulVecfl(mat, dvec);
2070                         quat= vectoquat(dvec, 5, 1);    /* track and upflag, not from the base: camera view calculation does not use that */
2071                         
2072                         QuatToEul(quat, G.vd->camera->rot);
2073                         
2074                         compatible_eul(G.vd->camera->rot, oldrot);
2075                         
2076                         VecMulf(dvec, speed);
2077                         G.vd->camera->loc[0]-= dvec[0];
2078                         G.vd->camera->loc[1]-= dvec[1];
2079                         G.vd->camera->loc[2]-= (dvec[2]-zspeed);
2080                         
2081                         scrarea_do_windraw(curarea);
2082                         screen_swapbuffers();
2083                 }
2084                 speedo= speed;
2085         }
2086         
2087         allqueue(REDRAWVIEW3D, 0);
2088         scrarea_queue_headredraw(curarea);
2089         
2090 }
2091
2092 void view3d_edit_clipping(View3D *v3d)
2093 {
2094         
2095         if(v3d->flag & V3D_CLIPPING) {
2096                 v3d->flag &= ~V3D_CLIPPING;
2097                 scrarea_queue_winredraw(curarea);
2098                 if(v3d->clipbb) MEM_freeN(v3d->clipbb);
2099                 v3d->clipbb= NULL;
2100         }
2101         else {
2102                 rcti rect;
2103                 double mvmatrix[16];
2104                 double projmatrix[16];
2105                 double xs, ys, p[3];
2106                 GLint viewport[4];
2107                 short val;
2108                 
2109                 /* get border in window coords */
2110                 setlinestyle(2);
2111                 val= get_border(&rect, 3);
2112                 setlinestyle(0);
2113                 if(val==0) return;
2114                 
2115                 v3d->flag |= V3D_CLIPPING;
2116                 v3d->clipbb= MEM_mallocN(sizeof(BoundBox), "clipbb");
2117                 
2118                 /* convert border to 3d coordinates */
2119                 
2120                 /* Get the matrices needed for gluUnProject */
2121                 glGetIntegerv(GL_VIEWPORT, viewport);
2122                 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
2123                 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
2124                 
2125                 /* Set up viewport so that gluUnProject will give correct values */
2126                 viewport[0] = 0;
2127                 viewport[1] = 0;
2128                 
2129                 /* four clipping planes and bounding volume */
2130                 /* first do the bounding volume */
2131                 for(val=0; val<4; val++) {
2132                         
2133                         xs= (val==0||val==3)?rect.xmin:rect.xmax;
2134                         ys= (val==0||val==1)?rect.ymin:rect.ymax;
2135                         
2136                         gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
2137                         VECCOPY(v3d->clipbb->vec[val], p);
2138                         
2139                         gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
2140                         VECCOPY(v3d->clipbb->vec[4+val], p);
2141                 }
2142                 
2143                 /* then plane equations */
2144                 for(val=0; val<4; val++) {
2145                         
2146                         CalcNormFloat(v3d->clipbb->vec[val], v3d->clipbb->vec[val==3?0:val+1], v3d->clipbb->vec[val+4],
2147                                                   v3d->clip[val]); 
2148                         
2149                         v3d->clip[val][3]= - v3d->clip[val][0]*v3d->clipbb->vec[val][0] 
2150                                                            - v3d->clip[val][1]*v3d->clipbb->vec[val][1] 
2151                                                            - v3d->clip[val][2]*v3d->clipbb->vec[val][2];
2152                 }
2153         }
2154 }
2155