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