New feature; User definable Clipping Planes.
[blender-staging.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_IMAGE) transform_tface_uv(i, 0);
785                                 else if(curarea->spacetype==SPACE_OOPS) transform_oops('g', 0);
786                                 else {
787                                         if(i=='g') {
788                                                 initTransform(TFM_TRANSLATION, CTX_NONE);
789                                                 Transform();
790                                         }
791                                         else if(i=='r') {
792                                                 initTransform(TFM_ROTATION, CTX_NONE);
793                                                 Transform();
794                                         }
795                                         else {
796                                                 initTransform(TFM_RESIZE, CTX_NONE);
797                                                 Transform();
798                                         }
799                                 }
800                         }
801                 }
802                 return 1;
803         }
804         return 0;
805 }
806
807 void mouse_cursor(void)
808 {
809         extern float zfac;      /* view.c */
810         float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
811         short mval[2], mx, my, lr_click=0;
812         
813         if(gesture()) return;
814         
815         getmouseco_areawin(mval);
816
817         mx= mval[0];
818         my= mval[1];
819         
820         fp= give_cursor();
821         
822         if(G.obedit && ((G.qual & LR_CTRLKEY) || get_mbut()&R_MOUSE )) lr_click= 1;
823         VECCOPY(oldcurs, fp);
824         
825         project_short_noclip(fp, mval);
826
827         initgrabz(fp[0], fp[1], fp[2]);
828         
829         if(mval[0]!=IS_CLIPPED) {
830                 
831                 window_to_3d(dvec, mval[0]-mx, mval[1]-my);
832                 VecSubf(fp, fp, dvec);
833                 
834         }
835         else {
836
837                 dx= ((float)(mx-(curarea->winx/2)))*zfac/(curarea->winx/2);
838                 dy= ((float)(my-(curarea->winy/2)))*zfac/(curarea->winy/2);
839                 
840                 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];
841                 fz= fz/zfac;
842                 
843                 fp[0]= (G.vd->persinv[0][0]*dx + G.vd->persinv[1][0]*dy+ G.vd->persinv[2][0]*fz)-G.vd->ofs[0];
844                 fp[1]= (G.vd->persinv[0][1]*dx + G.vd->persinv[1][1]*dy+ G.vd->persinv[2][1]*fz)-G.vd->ofs[1];
845                 fp[2]= (G.vd->persinv[0][2]*dx + G.vd->persinv[1][2]*dy+ G.vd->persinv[2][2]*fz)-G.vd->ofs[2];
846         }
847         
848         allqueue(REDRAWVIEW3D, 1);
849         
850         if(lr_click) {
851                 if(G.obedit->type==OB_MESH) addvert_mesh();
852                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) addvert_Nurb(0);
853                 else if (G.obedit->type==OB_ARMATURE) addvert_armature();
854                 VECCOPY(fp, oldcurs);
855         }
856         
857 }
858
859 void deselectall(void)  /* is toggle */
860 {
861         Base *base;
862         int a=0;
863
864         base= FIRSTBASE;
865         while(base) {
866                 if TESTBASE(base) {
867                         a= 1;
868                         break;
869                 }
870                 base= base->next;
871         }
872         
873         base= FIRSTBASE;
874         while(base) {
875                 if(base->lay & G.vd->lay) {
876                         if(a) base->flag &= ~SELECT;
877                         else base->flag |= SELECT;
878                         base->object->flag= base->flag;
879                 }
880                 base= base->next;
881         }
882
883         allqueue(REDRAWVIEW3D, 0);
884         allqueue(REDRAWDATASELECT, 0);
885         allqueue(REDRAWNLA, 0);
886         
887         countall();
888         BIF_undo_push("(De)select all");
889 }
890
891 /* selects all objects of a particular type, on currently visible layers */
892 void selectall_type(short obtype) 
893 {
894         Base *base;
895         
896         base= FIRSTBASE;
897         while(base) {
898                 if((base->lay & G.vd->lay) && (base->object->type == obtype)) {
899                         base->flag |= SELECT;
900                         base->object->flag= base->flag;
901                 }
902                 base= base->next;
903         }
904
905         allqueue(REDRAWVIEW3D, 0);
906         allqueue(REDRAWDATASELECT, 0);
907         allqueue(REDRAWNLA, 0);
908         
909         countall();
910         BIF_undo_push("Select all per type");
911 }
912 /* selects all objects on a particular layer */
913 void selectall_layer(unsigned int layernum) 
914 {
915         Base *base;
916         
917         base= FIRSTBASE;
918         while(base) {
919                 if (base->lay == (1<< (layernum -1))) {
920                         base->flag |= SELECT;
921                         base->object->flag= base->flag;
922                 }
923                 base= base->next;
924         }
925
926         allqueue(REDRAWVIEW3D, 0);
927         allqueue(REDRAWDATASELECT, 0);
928         allqueue(REDRAWNLA, 0);
929         
930         countall();
931         BIF_undo_push("Select all per layer");
932 }
933
934 static void deselectall_except(Base *b)   /* deselect all except b */
935 {
936         Base *base;
937
938         base= FIRSTBASE;
939         while(base) {
940                 if (base->flag & SELECT) {
941                         if(b!=base) {
942                                 base->flag &= ~SELECT;
943                                 base->object->flag= base->flag;
944                         }
945                 }
946                 base= base->next;
947         }
948 }
949
950 #if 0
951 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
952 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
953 {
954         Base *base;
955         unsigned int *bufmin,*bufmax;
956         int a,b,rc,tel,aantal,dirvec[4][2],maxob;
957         unsigned int retval=0;
958         
959         base= LASTBASE;
960         if(base==0) return 0;
961         maxob= base->selcol;
962
963         aantal= (size-1)/2;
964         rc= 0;
965
966         dirvec[0][0]= 1;
967         dirvec[0][1]= 0;
968         dirvec[1][0]= 0;
969         dirvec[1][1]= -size;
970         dirvec[2][0]= -1;
971         dirvec[2][1]= 0;
972         dirvec[3][0]= 0;
973         dirvec[3][1]= size;
974
975         bufmin= buf;
976         bufmax= buf+ size*size;
977         buf+= aantal*size+ aantal;
978
979         for(tel=1;tel<=size;tel++) {
980
981                 for(a=0;a<2;a++) {
982                         for(b=0;b<tel;b++) {
983
984                                 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
985                                 if( *buf==dontdo ) retval= dontdo;      /* if only color dontdo is available, still return dontdo */
986                                 
987                                 buf+= (dirvec[rc][0]+dirvec[rc][1]);
988
989                                 if(buf<bufmin || buf>=bufmax) return retval;
990                         }
991                         rc++;
992                         rc &= 3;
993                 }
994         }
995         return retval;
996 }
997 #endif
998
999 #define SELECTSIZE      51
1000
1001 void set_active_base(Base *base)
1002 {
1003         
1004         BASACT= base;
1005         
1006         if(base) {
1007                 /* signals to buttons */
1008                 redraw_test_buttons(base->object);
1009
1010                 set_active_group();
1011                 
1012                 /* signal to ipo */
1013
1014                 if (base) {
1015                         allqueue(REDRAWIPO, base->object->ipowin);
1016                         allqueue(REDRAWACTION, 0);
1017                         allqueue(REDRAWNLA, 0);
1018                 }
1019         }
1020 }
1021
1022 void set_active_object(Object *ob)
1023 {
1024         Base *base;
1025         
1026         base= FIRSTBASE;
1027         while(base) {
1028                 if(base->object==ob) {
1029                         set_active_base(base);
1030                         return;
1031                 }
1032                 base= base->next;
1033         }
1034 }
1035
1036 /* The max number of menu items in an object select menu */
1037 #define SEL_MENU_SIZE 22
1038
1039 static Base *mouse_select_menu(unsigned int *buffer, int hits, short *mval)
1040 {
1041         Base *baseList[SEL_MENU_SIZE]={NULL}; /*baseList is used to store all possible bases to bring up a menu */
1042         Base *base;
1043         short baseCount = 0;
1044         char menuText[20 + SEL_MENU_SIZE*32] = "Select Object%t";       // max ob name = 22
1045         char str[32];
1046         
1047         for(base=FIRSTBASE; base; base= base->next) {
1048                 if(base->lay & G.vd->lay) {
1049                         baseList[baseCount] = NULL;
1050                         
1051                         /* two selection methods, the CTRL select uses max dist of 15 */
1052                         if(buffer) {
1053                                 int a;
1054                                 for(a=0; a<hits; a++) {
1055                                         /* index was converted */
1056                                         if(base->selcol==buffer[ (4 * a) + 3 ]) baseList[baseCount] = base;
1057                                 }
1058                         }
1059                         else {
1060                                 int temp, dist=15;
1061                                 
1062                                 project_short(base->object->obmat[3], &base->sx);
1063                                 
1064                                 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
1065                                 if(temp<dist ) baseList[baseCount] = base;
1066                         }
1067                         
1068                         if(baseList[baseCount]) {
1069                                 if (baseCount < SEL_MENU_SIZE) {
1070                                         baseList[baseCount] = base;
1071                                         sprintf(str, "|%s %%x%d", base->object->id.name+2, baseCount+1);        // max ob name == 22
1072                                         strcat(menuText, str);
1073                                         baseCount++;
1074                                 }
1075                         }
1076                 }
1077         }
1078         
1079         if(baseCount<=1) return baseList[0];
1080         else {
1081                 baseCount = pupmenu(menuText);
1082                 
1083                 if (baseCount != -1) { /* If nothing is selected then dont do anything */
1084                         return baseList[baseCount-1];
1085                 }
1086                 else return NULL;
1087         }
1088 }
1089
1090 /* we want a select buffer with bones, if there are... */
1091 /* so check three selection levels and compare */
1092 static short mixed_bones_object_selectbuffer(unsigned int *buffer, short *mval)
1093 {
1094         int offs;
1095         short a, hits15, hits9=0, hits5=0;
1096         short has_bones15=0, has_bones9=0, has_bones5=0;
1097         
1098         hits15= view3d_opengl_select(buffer, MAXPICKBUF, mval[0]-14, mval[1]-14, mval[0]+14, mval[1]+14);
1099         if(hits15) {
1100                 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
1101                 
1102                 offs= 4*hits15;
1103                 hits9= view3d_opengl_select(buffer+offs, MAXPICKBUF-offs, mval[0]-9, mval[1]-9, mval[0]+9, mval[1]+9);
1104                 if(hits9) {
1105                         for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
1106                         
1107                         offs+= 4*hits9;
1108                         hits5= view3d_opengl_select(buffer+offs, MAXPICKBUF-offs, mval[0]-5, mval[1]-5, mval[0]+5, mval[1]+5);
1109                         if(hits5) {
1110                                 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
1111                         }
1112                 }
1113                 
1114                 if(has_bones5) {
1115                         offs= 4*hits15 + 4*hits9;
1116                         memcpy(buffer, buffer+offs, 4*offs);
1117                         return hits5;
1118                 }
1119                 if(has_bones9) {
1120                         offs= 4*hits15;
1121                         memcpy(buffer, buffer+offs, 4*offs);
1122                         return hits9;
1123                 }
1124                 if(has_bones15) {
1125                         return hits15;
1126                 }
1127                 
1128                 if(hits5) {
1129                         offs= 4*hits15 + 4*hits9;
1130                         memcpy(buffer, buffer+offs, 4*offs);
1131                         return hits5;
1132                 }
1133                 if(hits9) {
1134                         offs= 4*hits15;
1135                         memcpy(buffer, buffer+offs, 4*offs);
1136                         return hits9;
1137                 }
1138                 return hits15;
1139         }
1140         
1141         return 0;
1142 }
1143
1144 void mouse_select(void)
1145 {
1146         Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
1147         unsigned int buffer[MAXPICKBUF];
1148         int temp, a, dist=100;
1149         short hits, mval[2];
1150
1151         /* always start list from basact in wire mode */
1152         startbase=  FIRSTBASE;
1153         if(BASACT && BASACT->next) startbase= BASACT->next;
1154
1155         getmouseco_areawin(mval);
1156         
1157         /* This block uses the control key to make the object selected by its centre point rather then its contents */
1158         if(G.obedit==0 && (G.qual & LR_CTRLKEY)) {
1159                 
1160                 if(G.qual & LR_ALTKEY) basact= mouse_select_menu(NULL, 0, mval);
1161                 else {
1162                         base= startbase;
1163                         while(base) {
1164                                 
1165                                 if(base->lay & G.vd->lay) {
1166                                         
1167                                         project_short(base->object->obmat[3], &base->sx);
1168                                         
1169                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
1170                                         if(base==BASACT) temp+=10;
1171                                         if(temp<dist ) {
1172                                                 
1173                                                 dist= temp;
1174                                                 basact= base;
1175                                         }
1176                                 }
1177                                 base= base->next;
1178                                 
1179                                 if(base==0) base= FIRSTBASE;
1180                                 if(base==startbase) break;
1181                         }
1182                 }
1183         }
1184         else {
1185                 /* if objects have posemode set, the bones are in the same selection buffer */
1186                 
1187                 hits= mixed_bones_object_selectbuffer(buffer, mval);
1188                 
1189                 if(hits>0) {
1190                         int has_bones= 0;
1191                         
1192                         for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1193
1194                         if(has_bones==0 && (G.qual & LR_ALTKEY)) 
1195                                 basact= mouse_select_menu(buffer, hits, mval);
1196                         else {
1197                                 static short lastmval[2]={-100, -100};
1198                                 int donearest= 0;
1199                                 
1200                                 /* define if we use solid nearest select or not */
1201                                 if(G.vd->drawtype>OB_WIRE) {
1202                                         donearest= 1;
1203                                         if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
1204                                                 if(!has_bones)  // hrms, if theres bones we always do nearest
1205                                                         donearest= 0;
1206                                         }
1207                                 }
1208                                 lastmval[0]= mval[0]; lastmval[1]= mval[1];
1209                                 
1210                                 if(donearest) {
1211                                         unsigned int min= 0xFFFFFFFF;
1212                                         int selcol= 0, notcol=0;
1213                                         
1214
1215                                         if(has_bones) {
1216                                                 /* we skip non-bone hits */
1217                                                 for(a=0; a<hits; a++) {
1218                                                         if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
1219                                                                 min= buffer[4*a+1];
1220                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1221                                                         }
1222                                                 }
1223                                         }
1224                                         else {
1225                                                 /* only exclude active object when it is selected... */
1226                                                 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol; 
1227                                         
1228                                                 for(a=0; a<hits; a++) {
1229                                                         if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1230                                                                 min= buffer[4*a+1];
1231                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1232                                                         }
1233                                                 }
1234                                         }
1235
1236                                         base= FIRSTBASE;
1237                                         while(base) {
1238                                                 if(base->lay & G.vd->lay) {
1239                                                         if(base->selcol==selcol) break;
1240                                                 }
1241                                                 base= base->next;
1242                                         }
1243                                         if(base) basact= base;
1244                                 }
1245                                 else {
1246                                         
1247                                         base= startbase;
1248                                         while(base) {
1249                                                 if(base->lay & G.vd->lay) {
1250                                                         for(a=0; a<hits; a++) {
1251                                                                 if(has_bones) {
1252                                                                         /* skip non-bone objects */
1253                                                                         if((buffer[4*a+3] & 0xFFFF0000)) {
1254                                                                                 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1255                                                                                         basact= base;
1256                                                                         }
1257                                                                 }
1258                                                                 else {
1259                                                                         if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1260                                                                                 basact= base;
1261                                                                 }
1262                                                         }
1263                                                 }
1264                                                 
1265                                                 if(basact) break;
1266                                                 
1267                                                 base= base->next;
1268                                                 if(base==NULL) base= FIRSTBASE;
1269                                                 if(base==startbase) break;
1270                                         }
1271                                 }
1272                         }
1273                         
1274                         if(has_bones && basact) {
1275                                 if( do_pose_selectbuffer(basact, buffer, hits) ) {      // then bone is found
1276                                 
1277                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1278                                         if(G.f & G_WEIGHTPAINT) {
1279                                                 /* we make the armature selected */
1280                                                 basact->flag|= SELECT;
1281                                                 basact->object->flag= basact->flag;
1282                                                 /* prevent activating */
1283                                                 basact= NULL;
1284                                         }
1285                                 }
1286                         }
1287                 }
1288         }
1289         
1290         /* so, do we have something selected? */
1291         if(basact) {
1292                 
1293                 if(G.obedit) {
1294                         /* only do select */
1295                         deselectall_except(basact);
1296                         basact->flag |= SELECT;
1297                         draw_object_ext(basact);
1298                 }
1299                 else {
1300                         oldbasact= BASACT;
1301                         BASACT= basact;
1302                         
1303                         if((G.qual & LR_SHIFTKEY)==0) {
1304                                 deselectall_except(basact);
1305                                 basact->flag |= SELECT;
1306                         }
1307                         else {
1308                                 if(basact->flag & SELECT) {
1309                                         if(basact==oldbasact)
1310                                                 basact->flag &= ~SELECT;
1311                                 }
1312                                 else basact->flag |= SELECT;
1313                         }
1314
1315                         // copy
1316                         basact->object->flag= basact->flag;
1317                         
1318                         if(oldbasact != basact) {
1319                                 set_active_base(basact);
1320                         }
1321
1322                         // for visual speed, only in wire mode
1323                         if(G.vd->drawtype==OB_WIRE) {
1324                                 /* however, not for posemodes */
1325                                 if(basact->object->flag & OB_POSEMODE);
1326                                 else if(oldbasact && (oldbasact->object->flag & OB_POSEMODE));
1327                                 else {
1328                                         if(oldbasact && oldbasact != basact && (oldbasact->lay & G.vd->lay)) 
1329                                                 draw_object_ext(oldbasact);
1330                                         draw_object_ext(basact);
1331                                 }
1332                         }
1333                         
1334                         /* selecting a non-mesh, should end a couple of modes... */
1335                         if(basact->object->type!=OB_MESH) {
1336                                 if(G.f & G_WEIGHTPAINT) {
1337                                         set_wpaint();   /* toggle */
1338                                 }
1339                                 if(G.f & G_VERTEXPAINT) {
1340                                         set_vpaint();   /* toggle */
1341                                 }
1342                                 if(G.f & G_FACESELECT) {
1343                                         set_faceselect();       /* toggle */
1344                                 }
1345                         }
1346                         
1347                         /* also because multiple 3d windows can be open */
1348                         allqueue(REDRAWVIEW3D, 0);
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                 }
1359         }
1360
1361         countall();
1362
1363         rightmouse_transform(); // does undo push!
1364 }
1365
1366 /* ------------------------------------------------------------------------- */
1367
1368 static int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1369 {
1370         int radsq= rad*rad;
1371         float v1[2], v2[2], v3[2];
1372         
1373         // check points in circle itself
1374         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1375         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1376         
1377         // pointdistline
1378         v3[0]= centx;
1379         v3[1]= centy;
1380         v1[0]= x1;
1381         v1[1]= y1;
1382         v2[0]= x2;
1383         v2[1]= y2;
1384         
1385         if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1386         
1387         return 0;
1388 }
1389
1390 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1391 {
1392         struct { rcti *rect; int select; } *data = userData;
1393
1394         if (BLI_in_rcti(data->rect, x, y)) {
1395                 if (bp) {
1396                         bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1397                 } else {
1398                         if (beztindex==0) {
1399                                 bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
1400                         } else if (beztindex==1) {
1401                                 bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
1402                         } else {
1403                                 bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
1404                         }
1405                 }
1406         }
1407 }
1408 static void do_nurbs_box_select(rcti *rect, int select)
1409 {
1410         struct { rcti *rect; int select; } data;
1411
1412         data.rect = rect;
1413         data.select = select;
1414
1415         nurbs_foreachScreenVert(do_nurbs_box_select__doSelect, &data);
1416 }
1417
1418 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1419 {
1420         struct { rcti *rect; int select; } *data = userData;
1421
1422         if (BLI_in_rcti(data->rect, x, y)) {
1423                 bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1424         }
1425 }
1426 static void do_lattice_box_select(rcti *rect, int select)
1427 {
1428         struct { rcti *rect; short select, pass, done; } data;
1429
1430         data.rect = rect;
1431         data.select = select;
1432
1433         lattice_foreachScreenVert(do_lattice_box_select__doSelect, &data);
1434 }
1435
1436 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1437 {
1438         struct { rcti *rect; short select, pass, done; } *data = userData;
1439
1440         if (BLI_in_rcti(data->rect, x, y)) {
1441                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1442         }
1443 }
1444 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1445 {
1446         struct { rcti *rect; short select, pass, done; } *data = userData;
1447
1448         if(EM_check_backbuf(em_solidoffs+index)) {
1449                 if (data->pass==0) {
1450                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1451                                 EM_select_edge(eed, data->select);
1452                                 data->done = 1;
1453                         }
1454                 } else {
1455                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1456                                 EM_select_edge(eed, data->select);
1457                         }
1458                 }
1459         }
1460 }
1461 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1462 {
1463         struct { rcti *rect; short select, pass, done; } *data = userData;
1464
1465         if (BLI_in_rcti(data->rect, x, y)) {
1466                 EM_select_face_fgon(efa, data->select);
1467         }
1468 }
1469 static void do_mesh_box_select(rcti *rect, int select)
1470 {
1471         struct { rcti *rect; short select, pass, done; } data;
1472         EditMesh *em = G.editMesh;
1473         int bbsel;
1474         
1475         data.rect = rect;
1476         data.select = select;
1477         data.pass = 0;
1478         data.done = 0;
1479
1480         bbsel= EM_init_backbuf_border(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1481
1482         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1483                 if (bbsel) {
1484                         EM_backbuf_checkAndSelectVerts(em, select);
1485                 } else {
1486                         mesh_foreachScreenVert(do_mesh_box_select__doSelectVert, &data, 1);
1487                 }
1488         }
1489         if(G.scene->selectmode & SCE_SELECT_EDGE) {
1490                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1491
1492                 data.pass = 0;
1493                 mesh_foreachScreenEdge(do_mesh_box_select__doSelectEdge, &data, 0);
1494
1495                 if (data.done==0) {
1496                         data.pass = 1;
1497                         mesh_foreachScreenEdge(do_mesh_box_select__doSelectEdge, &data, 0);
1498                 }
1499         }
1500         
1501         if(G.scene->selectmode & SCE_SELECT_FACE) {
1502                 if(bbsel) {
1503                         EM_backbuf_checkAndSelectFaces(em, select);
1504                 } else {
1505                         mesh_foreachScreenFace(do_mesh_box_select__doSelectFace, &data);
1506                 }
1507         }
1508         
1509         EM_free_backbuf();
1510                 
1511         EM_selectmode_flush();
1512 }
1513
1514 /**
1515  * Does the 'borderselect' command. (Select verts based on selecting with a 
1516  * border: key 'b'). All selecting seems to be done in the get_border part.
1517  */
1518 void borderselect(void)
1519 {
1520         rcti rect;
1521         Base *base;
1522         MetaElem *ml;
1523         unsigned int buffer[MAXPICKBUF];
1524         int a, index;
1525         short hits, val;
1526
1527         if(G.obedit==NULL && (G.f & G_FACESELECT)) {
1528                 face_borderselect();
1529                 return;
1530         }
1531         
1532         setlinestyle(2);
1533         val= get_border(&rect, 3);
1534         setlinestyle(0);
1535         
1536         if(val==0)
1537                 return;
1538         
1539         if(G.obedit) {
1540                 if(G.obedit->type==OB_MESH) {
1541                         do_mesh_box_select(&rect, (val==LEFTMOUSE));
1542                         allqueue(REDRAWVIEW3D, 0);
1543                 }
1544                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
1545                         do_nurbs_box_select(&rect, val==LEFTMOUSE);
1546                         allqueue(REDRAWVIEW3D, 0);
1547                 }
1548                 else if(G.obedit->type==OB_MBALL) {
1549                         hits= view3d_opengl_select(buffer, MAXPICKBUF, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1550                         
1551                         ml= editelems.first;
1552                         
1553                         while(ml) {
1554                                 for(a=0; a<hits; a++) {
1555                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1556                                                 ml->flag |= MB_SCALE_RAD;
1557                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1558                                                 else ml->flag &= ~SELECT;
1559                                                 break;
1560                                         }
1561                                         if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1562                                                 ml->flag &= ~MB_SCALE_RAD;
1563                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1564                                                 else ml->flag &= ~SELECT;
1565                                                 break;
1566                                         }
1567                                 }
1568                                 ml= ml->next;
1569                         }
1570                         allqueue(REDRAWVIEW3D, 0);
1571                 }
1572                 else if(G.obedit->type==OB_ARMATURE) {
1573                         EditBone *ebone;
1574
1575                         hits= view3d_opengl_select(buffer, MAXPICKBUF, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1576
1577                         base= FIRSTBASE;
1578                         for (a=0; a<hits; a++){
1579                                 index = buffer[(4*a)+3];
1580                                 if (val==LEFTMOUSE){
1581                                         if (index!=-1) {
1582                                                 ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1583                                                 if (index & (BONESEL_TIP|BONESEL_BONE))
1584                                                         ebone->flag |= BONE_TIPSEL;
1585                                                 if (index & (BONESEL_ROOT|BONESEL_BONE))
1586                                                         ebone->flag |= BONE_ROOTSEL;
1587                                         }
1588                                 }
1589                                 else{
1590                                         if (index!=-1){
1591                                                 ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1592                                                 if (index & (BONESEL_TIP|BONESEL_BONE))
1593                                                         ebone->flag &= ~BONE_TIPSEL;
1594                                                 if (index & (BONESEL_ROOT|BONESEL_BONE))
1595                                                         ebone->flag &= ~BONE_ROOTSEL;
1596                                         }
1597                                 }
1598                         }
1599                         
1600                         allqueue(REDRAWBUTSEDIT, 0);
1601                         allqueue(REDRAWBUTSOBJECT, 0);
1602                         allqueue(REDRAWACTION, 0);
1603                         allqueue(REDRAWVIEW3D, 0);
1604                 }
1605                 else if(G.obedit->type==OB_LATTICE) {
1606                         do_lattice_box_select(&rect, val==LEFTMOUSE);
1607                         allqueue(REDRAWVIEW3D, 0);
1608                 }
1609         }
1610         else {  // no editmode, unified for bones and objects
1611                 Bone *bone;
1612                 unsigned int *vbuffer=NULL; /* selection buffer */
1613                 unsigned int *col;                      /* color in buffer      */
1614                 short selecting = 0;
1615
1616                 if (val==LEFTMOUSE)
1617                         selecting = 1;
1618                 
1619                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1620                 vbuffer = MEM_mallocN(4 * (G.totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1621                 hits= view3d_opengl_select(vbuffer, 4*(G.totobj+MAXPICKBUF), rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1622                 /*
1623                 LOGIC NOTES (theeth):
1624                 The buffer and ListBase have the same relative order, which makes the selection
1625                 very simple. Loop through both data sets at the same time, if the color
1626                 is the same as the object, we have a hit and can move to the next color
1627                 and object pair, if not, just move to the next object,
1628                 keeping the same color until we have a hit.
1629
1630                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1631                 does it incorrectly.
1632                 */
1633
1634                 if (hits) { /* no need to loop if there's no hit */
1635                         base= FIRSTBASE;
1636                         col = vbuffer + 3;
1637                         while(base && hits) {
1638                                 Base *next = base->next;
1639                                 if(base->lay & G.vd->lay) {
1640                                         while (base->selcol == (*col & 0xFFFF)) {       // we got an object
1641                                                 
1642                                                 if(*col & 0xFFFF0000) {                                 // we got a bone
1643                                                         bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1644                                                         if(bone) {
1645                                                                 if(selecting) {
1646                                                                         bone->flag |= BONE_SELECTED;
1647                                                                         select_actionchannel_by_name(base->object->action, bone->name, 1);
1648                                                                 }
1649                                                                 else {
1650                                                                         bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1651                                                                         select_actionchannel_by_name(base->object->action, bone->name, 0);
1652                                                                 }
1653                                                         }
1654                                                 }
1655                                                 else {
1656                                                         if (selecting)
1657                                                                 base->flag |= SELECT;
1658                                                         else
1659                                                                 base->flag &= ~SELECT;
1660
1661                                                         base->object->flag= base->flag;
1662                                                 }
1663
1664                                                 col+=4; /* next color */
1665                                                 hits--;
1666                                                 if(hits==0) break;
1667                                         }
1668                                 }
1669                                 
1670                                 base= next;
1671                         }
1672                 }
1673                 /* frontbuffer flush */
1674                 glFlush();
1675
1676                 MEM_freeN(vbuffer);
1677                 
1678                 allqueue(REDRAWDATASELECT, 0);
1679                 allqueue(REDRAWBUTSLOGIC, 0);
1680                 allqueue(REDRAWNLA, 0);
1681         }
1682
1683         countall();
1684         
1685         allqueue(REDRAWBUTSOBJECT, 0);
1686         allqueue(REDRAWVIEW3D, 0);
1687         allqueue(REDRAWINFO, 0);
1688
1689         BIF_undo_push("Border select");
1690         
1691 } /* end of borderselect() */
1692
1693 /* ------------------------------------------------------------------------- */
1694
1695 /** The following functions are quick & dirty callback functions called
1696   * on the Circle select function (press B twice in Editmode)
1697   * They were torn out of the circle_select to make the latter more reusable
1698   * The callback version of circle_select (called circle_selectCB) was moved
1699   * to edit.c because of it's (wanted) generality.
1700
1701         XXX These callback functions are still dirty, because they call globals... 
1702   */
1703
1704 static void mesh_selectionCB__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1705 {
1706         struct { short select, mval[2]; float radius; } *data = userData;
1707         int mx = x - data->mval[0], my = y - data->mval[1];
1708         float r = sqrt(mx*mx + my*my);
1709
1710         if (r<=data->radius) {
1711                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1712         }
1713 }
1714 static void mesh_selectionCB__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1715 {
1716         struct { short select, mval[2]; float radius; } *data = userData;
1717
1718         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1719                 EM_select_edge(eed, data->select);
1720         }
1721 }
1722 static void mesh_selectionCB__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1723 {
1724         struct { short select, mval[2]; float radius; } *data = userData;
1725         int mx = x - data->mval[0], my = y - data->mval[1];
1726         float r = sqrt(mx*mx + my*my);
1727
1728         if (r<=data->radius) {
1729                 EM_select_face_fgon(efa, data->select);
1730         }
1731 }
1732 static void mesh_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1733 {
1734         struct { short select, mval[2]; float radius; } data;
1735         EditMesh *em = G.editMesh;
1736         int bbsel;
1737
1738         if(!G.obedit && (G.f&G_FACESELECT)) {
1739                 Mesh *me = get_mesh(OBACT);
1740
1741                 if (me) {
1742                         em_vertoffs= me->totface+1;     // max index array
1743
1744                         bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
1745                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1746                         EM_free_backbuf();
1747
1748                         object_tface_flags_changed(OBACT, 0);
1749                 }
1750
1751                 return;
1752         }
1753
1754         bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
1755         
1756         data.select = (selecting==LEFTMOUSE);
1757         data.mval[0] = mval[0];
1758         data.mval[1] = mval[1];
1759         data.radius = rad;
1760
1761         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1762                 if(bbsel) {
1763                         EM_backbuf_checkAndSelectVerts(em, selecting==LEFTMOUSE);
1764                 } else {
1765                         mesh_foreachScreenVert(mesh_selectionCB__doSelectVert, &data, 1);
1766                 }
1767         }
1768
1769         if(G.scene->selectmode & SCE_SELECT_EDGE) {
1770                 if (bbsel) {
1771                         EM_backbuf_checkAndSelectEdges(em, selecting==LEFTMOUSE);
1772                 } else {
1773                         mesh_foreachScreenEdge(mesh_selectionCB__doSelectEdge, &data, 0);
1774                 }
1775         }
1776         
1777         if(G.scene->selectmode & SCE_SELECT_FACE) {
1778                 if(bbsel) {
1779                         EM_backbuf_checkAndSelectFaces(em, selecting==LEFTMOUSE);
1780                 } else {
1781                         mesh_foreachScreenFace(mesh_selectionCB__doSelectFace, &data);
1782                 }
1783         }
1784
1785         EM_free_backbuf();
1786         EM_selectmode_flush();
1787 }
1788
1789
1790 static void nurbscurve_selectionCB__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1791 {
1792         struct { short select, mval[2]; float radius; } *data = userData;
1793         int mx = x - data->mval[0], my = y - data->mval[1];
1794         float r = sqrt(mx*mx + my*my);
1795
1796         if (r<=data->radius) {
1797                 if (bp) {
1798                         bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1799                 } else {
1800                         if (beztindex==0) {
1801                                 bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
1802                         } else if (beztindex==1) {
1803                                 bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
1804                         } else {
1805                                 bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
1806                         }
1807                 }
1808         }
1809 }
1810 static void nurbscurve_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1811 {
1812         struct { short select, mval[2]; float radius; } data;
1813
1814         data.select = (selecting==LEFTMOUSE);
1815         data.mval[0] = mval[0];
1816         data.mval[1] = mval[1];
1817         data.radius = rad;
1818
1819         nurbs_foreachScreenVert(nurbscurve_selectionCB__doSelect, &data);
1820 }
1821
1822
1823 static void latticecurve_selectionCB__doSelect(void *userData, BPoint *bp, int x, int y)
1824 {
1825         struct { short select, mval[2]; float radius; } *data = userData;
1826         int mx = x - data->mval[0], my = y - data->mval[1];
1827         float r = sqrt(mx*mx + my*my);
1828
1829         if (r<=data->radius) {
1830                 bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1831         }
1832 }
1833 static void lattice_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1834 {
1835         struct { short select, mval[2]; float radius; } data;
1836
1837         data.select = (selecting==LEFTMOUSE);
1838         data.mval[0] = mval[0];
1839         data.mval[1] = mval[1];
1840         data.radius = rad;
1841
1842         lattice_foreachScreenVert(latticecurve_selectionCB__doSelect, &data);
1843 }
1844
1845 /** Callbacks for selection in Editmode */
1846
1847 void obedit_selectionCB(short selecting, Object *editobj, short *mval, float rad) 
1848 {
1849         switch(editobj->type) {         
1850         case OB_MESH:
1851                 mesh_selectionCB(selecting, editobj, mval, rad);
1852                 break;
1853         case OB_CURVE:
1854         case OB_SURF:
1855                 nurbscurve_selectionCB(selecting, editobj, mval, rad);
1856                 break;
1857         case OB_LATTICE:
1858                 lattice_selectionCB(selecting, editobj, mval, rad);
1859                 break;
1860         default:
1861                 return;
1862         }
1863
1864         draw_sel_circle(0, 0, 0, 0, 0); /* signal */
1865         force_draw(0);
1866 }
1867
1868 void set_render_border(void)
1869 {
1870         rcti rect;
1871         short val;
1872
1873         if(G.vd->persp!=2) return;
1874         
1875         val= get_border(&rect, 2);
1876         if(val) {
1877                 rcti vb;
1878
1879                 calc_viewborder(G.vd, &vb);
1880
1881                 G.scene->r.border.xmin= (float) (rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
1882                 G.scene->r.border.ymin= (float) (rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
1883                 G.scene->r.border.xmax= (float) (rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
1884                 G.scene->r.border.ymax= (float) (rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
1885                 
1886                 CLAMP(G.scene->r.border.xmin, 0.0, 1.0);
1887                 CLAMP(G.scene->r.border.ymin, 0.0, 1.0);
1888                 CLAMP(G.scene->r.border.xmax, 0.0, 1.0);
1889                 CLAMP(G.scene->r.border.ymax, 0.0, 1.0);
1890                 
1891                 allqueue(REDRAWVIEWCAM, 1);
1892                 // if it was not set, we do this
1893                 G.scene->r.mode |= R_BORDER;
1894                 allqueue(REDRAWBUTSSCENE, 1);
1895         }
1896 }
1897
1898
1899
1900 void fly(void)
1901 {
1902         float speed=0.0, speedo=1.0, zspeed=0.0, dvec[3], *quat, mat[3][3];
1903         float oldvec[3], oldrot[3];
1904         int loop=1;
1905         unsigned short toets;
1906         short val, cent[2];
1907         short mval[2];
1908         
1909         if(curarea->spacetype!=SPACE_VIEW3D) return;
1910         if(G.vd->camera == 0) return;
1911         if(G.vd->persp<2) return;
1912         
1913         VECCOPY(oldvec, G.vd->camera->loc);
1914         VECCOPY(oldrot, G.vd->camera->rot);
1915         
1916         cent[0]= curarea->winrct.xmin+(curarea->winx)/2;
1917         cent[1]= curarea->winrct.ymin+(curarea->winy)/2;
1918         
1919         warp_pointer(cent[0], cent[1]);
1920         
1921         /* we have to rely on events to give proper mousecoords after a warp_pointer */
1922         mval[0]= cent[0]=  (curarea->winx)/2;
1923         mval[1]= cent[1]=  (curarea->winy)/2;
1924         
1925         headerprint("Fly");
1926         
1927         while(loop) {
1928                 
1929
1930                 while(qtest()) {
1931                         
1932                         toets= extern_qread(&val);
1933                         
1934                         if(val) {
1935                                 if(toets==MOUSEY) getmouseco_areawin(mval);
1936                                 else if(toets==ESCKEY) {
1937                                         VECCOPY(G.vd->camera->loc, oldvec);
1938                                         VECCOPY(G.vd->camera->rot, oldrot);
1939                                         loop= 0;
1940                                         break;
1941                                 }
1942                                 else if(toets==SPACEKEY) {
1943                                         loop= 0;
1944                                         BIF_undo_push("Fly camera");
1945                                         break;
1946                                 }
1947                                 else if(toets==LEFTMOUSE) {
1948                                         speed+= G.vd->grid/75.0;
1949                                         if(get_mbut()&M_MOUSE) speed= 0.0;
1950                                 }
1951                                 else if(toets==MIDDLEMOUSE) {
1952                                         speed-= G.vd->grid/75.0;
1953                                         if(get_mbut()&L_MOUSE) speed= 0.0;
1954                                 }
1955                         }
1956                 }
1957                 if(loop==0) break;
1958                 
1959                 /* define dvec */
1960                 val= mval[0]-cent[0];
1961                 if(val>20) val-= 20; else if(val< -20) val+= 20; else val= 0;
1962                 dvec[0]= 0.000001*val*val;
1963                 if(val>0) dvec[0]= -dvec[0];
1964                 
1965                 val= mval[1]-cent[1];
1966                 if(val>20) val-= 20; else if(val< -20) val+= 20; else val= 0;
1967                 dvec[1]= 0.000001*val*val;
1968                 if(val>0) dvec[1]= -dvec[1];
1969                 
1970                 dvec[2]= 1.0;
1971                 
1972                 zspeed= 0.0;
1973                 if(get_qual()&LR_CTRLKEY) zspeed= -G.vd->grid/25.0;
1974                 if(get_qual()&LR_ALTKEY) zspeed= G.vd->grid/25.0;
1975                 
1976                 if(speedo!=0.0 || zspeed!=0.0 || dvec[0]!=0.0 || dvec[1]!=0.0) {
1977                 
1978                         Normalise(dvec);
1979                         
1980                         Mat3CpyMat4(mat, G.vd->viewinv);
1981                         Mat3MulVecfl(mat, dvec);
1982                         quat= vectoquat(dvec, 5, 1);    /* track and upflag, not from the base: camera view calculation does not use that */
1983                         
1984                         QuatToEul(quat, G.vd->camera->rot);
1985                         
1986                         compatible_eul(G.vd->camera->rot, oldrot);
1987                         
1988                         VecMulf(dvec, speed);
1989                         G.vd->camera->loc[0]-= dvec[0];
1990                         G.vd->camera->loc[1]-= dvec[1];
1991                         G.vd->camera->loc[2]-= (dvec[2]-zspeed);
1992                         
1993                         scrarea_do_windraw(curarea);
1994                         screen_swapbuffers();
1995                 }
1996                 speedo= speed;
1997         }
1998         
1999         allqueue(REDRAWVIEW3D, 0);
2000         scrarea_queue_headredraw(curarea);
2001         
2002 }
2003
2004 void view3d_edit_clipping(View3D *v3d)
2005 {
2006         
2007         if(v3d->flag & V3D_CLIPPING) {
2008                 v3d->flag &= ~V3D_CLIPPING;
2009                 scrarea_queue_winredraw(curarea);
2010                 if(v3d->clipbb) MEM_freeN(v3d->clipbb);
2011                 v3d->clipbb= NULL;
2012         }
2013         else {
2014                 rcti rect;
2015                 double mvmatrix[16];
2016                 double projmatrix[16];
2017                 double xs, ys, p[3];
2018                 GLint viewport[4];
2019                 short val;
2020                 
2021                 /* get border in window coords */
2022                 setlinestyle(2);
2023                 val= get_border(&rect, 3);
2024                 setlinestyle(0);
2025                 if(val==0) return;
2026                 
2027                 v3d->flag |= V3D_CLIPPING;
2028                 v3d->clipbb= MEM_mallocN(sizeof(BoundBox), "clipbb");
2029                 
2030                 /* convert border to 3d coordinates */
2031                 
2032                 /* Get the matrices needed for gluUnProject */
2033                 glGetIntegerv(GL_VIEWPORT, viewport);
2034                 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
2035                 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
2036                 
2037                 /* Set up viewport so that gluUnProject will give correct values */
2038                 viewport[0] = 0;
2039                 viewport[1] = 0;
2040                 
2041                 /* four clipping planes and bounding volume */
2042                 for(val=0; val<4; val++) {
2043                         
2044                         xs= (val==0||val==3)?rect.xmin:rect.xmax;
2045                         ys= (val==0||val==1)?rect.ymin:rect.ymax;
2046                         gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
2047                         VECCOPY(v3d->clipbb->vec[val], p);
2048                         
2049                         VECCOPY(v3d->clip[val], G.vd->viewinv[val & 1]);
2050                         if(val>1) VecMulf(v3d->clip[val], -1.0f);
2051                         v3d->clip[val][3]= - v3d->clip[val][0]*p[0] - v3d->clip[val][1]*p[1] - v3d->clip[val][2]*p[2];
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         }
2058 }
2059