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