f30324ff7ac60523a815d70a73f1ae819c6680a5
[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_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                 }
1298                 else {
1299                         oldbasact= BASACT;
1300                         BASACT= basact;
1301                         
1302                         if((G.qual & LR_SHIFTKEY)==0) {
1303                                 deselectall_except(basact);
1304                                 basact->flag |= SELECT;
1305                         }
1306                         else {
1307                                 if(basact->flag & SELECT) {
1308                                         if(basact==oldbasact)
1309                                                 basact->flag &= ~SELECT;
1310                                 }
1311                                 else basact->flag |= SELECT;
1312                         }
1313
1314                         // copy
1315                         basact->object->flag= basact->flag;
1316                         
1317                         if(oldbasact != basact) {
1318                                 set_active_base(basact);
1319                         }
1320
1321                         // for visual speed, only in wire mode
1322                         if(G.vd->drawtype==OB_WIRE) {
1323                                 /* however, not for posemodes */
1324                                 if(basact->object->flag & OB_POSEMODE);
1325                                 else if(oldbasact && (oldbasact->object->flag & OB_POSEMODE));
1326                                 else {
1327                                         if(oldbasact && oldbasact != basact && (oldbasact->lay & G.vd->lay)) 
1328                                                 draw_object_ext(oldbasact);
1329                                         draw_object_ext(basact);
1330                                 }
1331                         }
1332                         
1333                         /* selecting a non-mesh, should end a couple of modes... */
1334                         if(basact->object->type!=OB_MESH) {
1335                                 if(G.f & G_WEIGHTPAINT) {
1336                                         set_wpaint();   /* toggle */
1337                                 }
1338                                 if(G.f & G_VERTEXPAINT) {
1339                                         set_vpaint();   /* toggle */
1340                                 }
1341                                 if(G.f & G_FACESELECT) {
1342                                         set_faceselect();       /* toggle */
1343                                 }
1344                         }
1345                         
1346                         allqueue(REDRAWBUTSLOGIC, 0);
1347                         allqueue(REDRAWDATASELECT, 0);
1348                         allqueue(REDRAWBUTSOBJECT, 0);
1349                         allqueue(REDRAWACTION, 0);
1350                         allqueue(REDRAWNLA, 0);
1351                         allqueue(REDRAWTIME, 0);
1352                         allqueue(REDRAWHEADERS, 0);     /* To force display update for the posebutton */
1353                 }
1354                 /* also because multiple 3d windows can be open */
1355                 allqueue(REDRAWVIEW3D, 0);
1356                 
1357         }
1358
1359         countall();
1360
1361         rightmouse_transform(); // does undo push!
1362 }
1363
1364 /* ------------------------------------------------------------------------- */
1365
1366 static int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1367 {
1368         int radsq= rad*rad;
1369         float v1[2], v2[2], v3[2];
1370         
1371         // check points in circle itself
1372         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1373         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1374         
1375         // pointdistline
1376         v3[0]= centx;
1377         v3[1]= centy;
1378         v1[0]= x1;
1379         v1[1]= y1;
1380         v2[0]= x2;
1381         v2[1]= y2;
1382         
1383         if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1384         
1385         return 0;
1386 }
1387
1388 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1389 {
1390         struct { rcti *rect; int select; } *data = userData;
1391
1392         if (BLI_in_rcti(data->rect, x, y)) {
1393                 if (bp) {
1394                         bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1395                 } else {
1396                         if (beztindex==0) {
1397                                 bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
1398                         } else if (beztindex==1) {
1399                                 bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
1400                         } else {
1401                                 bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
1402                         }
1403                 }
1404         }
1405 }
1406 static void do_nurbs_box_select(rcti *rect, int select)
1407 {
1408         struct { rcti *rect; int select; } data;
1409
1410         data.rect = rect;
1411         data.select = select;
1412
1413         nurbs_foreachScreenVert(do_nurbs_box_select__doSelect, &data);
1414 }
1415
1416 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1417 {
1418         struct { rcti *rect; int select; } *data = userData;
1419
1420         if (BLI_in_rcti(data->rect, x, y)) {
1421                 bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1422         }
1423 }
1424 static void do_lattice_box_select(rcti *rect, int select)
1425 {
1426         struct { rcti *rect; short select, pass, done; } data;
1427
1428         data.rect = rect;
1429         data.select = select;
1430
1431         lattice_foreachScreenVert(do_lattice_box_select__doSelect, &data);
1432 }
1433
1434 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1435 {
1436         struct { rcti *rect; short select, pass, done; } *data = userData;
1437
1438         if (BLI_in_rcti(data->rect, x, y)) {
1439                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1440         }
1441 }
1442 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1443 {
1444         struct { rcti *rect; short select, pass, done; } *data = userData;
1445
1446         if(EM_check_backbuf(em_solidoffs+index)) {
1447                 if (data->pass==0) {
1448                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1449                                 EM_select_edge(eed, data->select);
1450                                 data->done = 1;
1451                         }
1452                 } else {
1453                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1454                                 EM_select_edge(eed, data->select);
1455                         }
1456                 }
1457         }
1458 }
1459 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1460 {
1461         struct { rcti *rect; short select, pass, done; } *data = userData;
1462
1463         if (BLI_in_rcti(data->rect, x, y)) {
1464                 EM_select_face_fgon(efa, data->select);
1465         }
1466 }
1467 static void do_mesh_box_select(rcti *rect, int select)
1468 {
1469         struct { rcti *rect; short select, pass, done; } data;
1470         EditMesh *em = G.editMesh;
1471         int bbsel;
1472         
1473         data.rect = rect;
1474         data.select = select;
1475         data.pass = 0;
1476         data.done = 0;
1477
1478         bbsel= EM_init_backbuf_border(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1479
1480         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1481                 if (bbsel) {
1482                         EM_backbuf_checkAndSelectVerts(em, select);
1483                 } else {
1484                         mesh_foreachScreenVert(do_mesh_box_select__doSelectVert, &data, 1);
1485                 }
1486         }
1487         if(G.scene->selectmode & SCE_SELECT_EDGE) {
1488                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1489
1490                 data.pass = 0;
1491                 mesh_foreachScreenEdge(do_mesh_box_select__doSelectEdge, &data, 0);
1492
1493                 if (data.done==0) {
1494                         data.pass = 1;
1495                         mesh_foreachScreenEdge(do_mesh_box_select__doSelectEdge, &data, 0);
1496                 }
1497         }
1498         
1499         if(G.scene->selectmode & SCE_SELECT_FACE) {
1500                 if(bbsel) {
1501                         EM_backbuf_checkAndSelectFaces(em, select);
1502                 } else {
1503                         mesh_foreachScreenFace(do_mesh_box_select__doSelectFace, &data);
1504                 }
1505         }
1506         
1507         EM_free_backbuf();
1508                 
1509         EM_selectmode_flush();
1510 }
1511
1512 /**
1513  * Does the 'borderselect' command. (Select verts based on selecting with a 
1514  * border: key 'b'). All selecting seems to be done in the get_border part.
1515  */
1516 void borderselect(void)
1517 {
1518         rcti rect;
1519         Base *base;
1520         MetaElem *ml;
1521         unsigned int buffer[MAXPICKBUF];
1522         int a, index;
1523         short hits, val;
1524
1525         if(G.obedit==NULL && (G.f & G_FACESELECT)) {
1526                 face_borderselect();
1527                 return;
1528         }
1529         
1530         setlinestyle(2);
1531         val= get_border(&rect, 3);
1532         setlinestyle(0);
1533         
1534         if(val==0)
1535                 return;
1536         
1537         if(G.obedit) {
1538                 if(G.obedit->type==OB_MESH) {
1539                         do_mesh_box_select(&rect, (val==LEFTMOUSE));
1540                         allqueue(REDRAWVIEW3D, 0);
1541                 }
1542                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
1543                         do_nurbs_box_select(&rect, val==LEFTMOUSE);
1544                         allqueue(REDRAWVIEW3D, 0);
1545                 }
1546                 else if(G.obedit->type==OB_MBALL) {
1547                         hits= view3d_opengl_select(buffer, MAXPICKBUF, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1548                         
1549                         ml= editelems.first;
1550                         
1551                         while(ml) {
1552                                 for(a=0; a<hits; a++) {
1553                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1554                                                 ml->flag |= MB_SCALE_RAD;
1555                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1556                                                 else ml->flag &= ~SELECT;
1557                                                 break;
1558                                         }
1559                                         if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1560                                                 ml->flag &= ~MB_SCALE_RAD;
1561                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1562                                                 else ml->flag &= ~SELECT;
1563                                                 break;
1564                                         }
1565                                 }
1566                                 ml= ml->next;
1567                         }
1568                         allqueue(REDRAWVIEW3D, 0);
1569                 }
1570                 else if(G.obedit->type==OB_ARMATURE) {
1571                         EditBone *ebone;
1572
1573                         hits= view3d_opengl_select(buffer, MAXPICKBUF, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1574
1575                         base= FIRSTBASE;
1576                         for (a=0; a<hits; a++){
1577                                 index = buffer[(4*a)+3];
1578                                 if (val==LEFTMOUSE){
1579                                         if (index!=-1) {
1580                                                 ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1581                                                 if (index & (BONESEL_TIP|BONESEL_BONE))
1582                                                         ebone->flag |= BONE_TIPSEL;
1583                                                 if (index & (BONESEL_ROOT|BONESEL_BONE))
1584                                                         ebone->flag |= BONE_ROOTSEL;
1585                                         }
1586                                 }
1587                                 else{
1588                                         if (index!=-1){
1589                                                 ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1590                                                 if (index & (BONESEL_TIP|BONESEL_BONE))
1591                                                         ebone->flag &= ~BONE_TIPSEL;
1592                                                 if (index & (BONESEL_ROOT|BONESEL_BONE))
1593                                                         ebone->flag &= ~BONE_ROOTSEL;
1594                                         }
1595                                 }
1596                         }
1597                         
1598                         allqueue(REDRAWBUTSEDIT, 0);
1599                         allqueue(REDRAWBUTSOBJECT, 0);
1600                         allqueue(REDRAWACTION, 0);
1601                         allqueue(REDRAWVIEW3D, 0);
1602                 }
1603                 else if(G.obedit->type==OB_LATTICE) {
1604                         do_lattice_box_select(&rect, val==LEFTMOUSE);
1605                         allqueue(REDRAWVIEW3D, 0);
1606                 }
1607         }
1608         else {  // no editmode, unified for bones and objects
1609                 Bone *bone;
1610                 unsigned int *vbuffer=NULL; /* selection buffer */
1611                 unsigned int *col;                      /* color in buffer      */
1612                 short selecting = 0;
1613
1614                 if (val==LEFTMOUSE)
1615                         selecting = 1;
1616                 
1617                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1618                 vbuffer = MEM_mallocN(4 * (G.totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1619                 hits= view3d_opengl_select(vbuffer, 4*(G.totobj+MAXPICKBUF), rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1620                 /*
1621                 LOGIC NOTES (theeth):
1622                 The buffer and ListBase have the same relative order, which makes the selection
1623                 very simple. Loop through both data sets at the same time, if the color
1624                 is the same as the object, we have a hit and can move to the next color
1625                 and object pair, if not, just move to the next object,
1626                 keeping the same color until we have a hit.
1627
1628                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1629                 does it incorrectly.
1630                 */
1631
1632                 if (hits) { /* no need to loop if there's no hit */
1633                         base= FIRSTBASE;
1634                         col = vbuffer + 3;
1635                         while(base && hits) {
1636                                 Base *next = base->next;
1637                                 if(base->lay & G.vd->lay) {
1638                                         while (base->selcol == (*col & 0xFFFF)) {       // we got an object
1639                                                 
1640                                                 if(*col & 0xFFFF0000) {                                 // we got a bone
1641                                                         bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1642                                                         if(bone) {
1643                                                                 if(selecting) {
1644                                                                         bone->flag |= BONE_SELECTED;
1645                                                                         select_actionchannel_by_name(base->object->action, bone->name, 1);
1646                                                                 }
1647                                                                 else {
1648                                                                         bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1649                                                                         select_actionchannel_by_name(base->object->action, bone->name, 0);
1650                                                                 }
1651                                                         }
1652                                                 }
1653                                                 else {
1654                                                         if (selecting)
1655                                                                 base->flag |= SELECT;
1656                                                         else
1657                                                                 base->flag &= ~SELECT;
1658
1659                                                         base->object->flag= base->flag;
1660                                                 }
1661
1662                                                 col+=4; /* next color */
1663                                                 hits--;
1664                                                 if(hits==0) break;
1665                                         }
1666                                 }
1667                                 
1668                                 base= next;
1669                         }
1670                 }
1671                 /* frontbuffer flush */
1672                 glFlush();
1673
1674                 MEM_freeN(vbuffer);
1675                 
1676                 allqueue(REDRAWDATASELECT, 0);
1677                 allqueue(REDRAWBUTSLOGIC, 0);
1678                 allqueue(REDRAWNLA, 0);
1679         }
1680
1681         countall();
1682         
1683         allqueue(REDRAWBUTSOBJECT, 0);
1684         allqueue(REDRAWVIEW3D, 0);
1685         allqueue(REDRAWINFO, 0);
1686
1687         BIF_undo_push("Border select");
1688         
1689 } /* end of borderselect() */
1690
1691 /* ------------------------------------------------------------------------- */
1692
1693 /** The following functions are quick & dirty callback functions called
1694   * on the Circle select function (press B twice in Editmode)
1695   * They were torn out of the circle_select to make the latter more reusable
1696   * The callback version of circle_select (called circle_selectCB) was moved
1697   * to edit.c because of it's (wanted) generality.
1698
1699         XXX These callback functions are still dirty, because they call globals... 
1700   */
1701
1702 static void mesh_selectionCB__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1703 {
1704         struct { short select, mval[2]; float radius; } *data = userData;
1705         int mx = x - data->mval[0], my = y - data->mval[1];
1706         float r = sqrt(mx*mx + my*my);
1707
1708         if (r<=data->radius) {
1709                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1710         }
1711 }
1712 static void mesh_selectionCB__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1713 {
1714         struct { short select, mval[2]; float radius; } *data = userData;
1715
1716         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1717                 EM_select_edge(eed, data->select);
1718         }
1719 }
1720 static void mesh_selectionCB__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1721 {
1722         struct { short select, mval[2]; float radius; } *data = userData;
1723         int mx = x - data->mval[0], my = y - data->mval[1];
1724         float r = sqrt(mx*mx + my*my);
1725
1726         if (r<=data->radius) {
1727                 EM_select_face_fgon(efa, data->select);
1728         }
1729 }
1730 static void mesh_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1731 {
1732         struct { short select, mval[2]; float radius; } data;
1733         EditMesh *em = G.editMesh;
1734         int bbsel;
1735
1736         if(!G.obedit && (G.f&G_FACESELECT)) {
1737                 Mesh *me = get_mesh(OBACT);
1738
1739                 if (me) {
1740                         em_vertoffs= me->totface+1;     // max index array
1741
1742                         bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
1743                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1744                         EM_free_backbuf();
1745
1746                         object_tface_flags_changed(OBACT, 0);
1747                 }
1748
1749                 return;
1750         }
1751
1752         bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
1753         
1754         data.select = (selecting==LEFTMOUSE);
1755         data.mval[0] = mval[0];
1756         data.mval[1] = mval[1];
1757         data.radius = rad;
1758
1759         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1760                 if(bbsel) {
1761                         EM_backbuf_checkAndSelectVerts(em, selecting==LEFTMOUSE);
1762                 } else {
1763                         mesh_foreachScreenVert(mesh_selectionCB__doSelectVert, &data, 1);
1764                 }
1765         }
1766
1767         if(G.scene->selectmode & SCE_SELECT_EDGE) {
1768                 if (bbsel) {
1769                         EM_backbuf_checkAndSelectEdges(em, selecting==LEFTMOUSE);
1770                 } else {
1771                         mesh_foreachScreenEdge(mesh_selectionCB__doSelectEdge, &data, 0);
1772                 }
1773         }
1774         
1775         if(G.scene->selectmode & SCE_SELECT_FACE) {
1776                 if(bbsel) {
1777                         EM_backbuf_checkAndSelectFaces(em, selecting==LEFTMOUSE);
1778                 } else {
1779                         mesh_foreachScreenFace(mesh_selectionCB__doSelectFace, &data);
1780                 }
1781         }
1782
1783         EM_free_backbuf();
1784         EM_selectmode_flush();
1785 }
1786
1787
1788 static void nurbscurve_selectionCB__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1789 {
1790         struct { short select, mval[2]; float radius; } *data = userData;
1791         int mx = x - data->mval[0], my = y - data->mval[1];
1792         float r = sqrt(mx*mx + my*my);
1793
1794         if (r<=data->radius) {
1795                 if (bp) {
1796                         bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1797                 } else {
1798                         if (beztindex==0) {
1799                                 bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
1800                         } else if (beztindex==1) {
1801                                 bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
1802                         } else {
1803                                 bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
1804                         }
1805                 }
1806         }
1807 }
1808 static void nurbscurve_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1809 {
1810         struct { short select, mval[2]; float radius; } data;
1811
1812         data.select = (selecting==LEFTMOUSE);
1813         data.mval[0] = mval[0];
1814         data.mval[1] = mval[1];
1815         data.radius = rad;
1816
1817         nurbs_foreachScreenVert(nurbscurve_selectionCB__doSelect, &data);
1818 }
1819
1820
1821 static void latticecurve_selectionCB__doSelect(void *userData, BPoint *bp, int x, int y)
1822 {
1823         struct { short select, mval[2]; float radius; } *data = userData;
1824         int mx = x - data->mval[0], my = y - data->mval[1];
1825         float r = sqrt(mx*mx + my*my);
1826
1827         if (r<=data->radius) {
1828                 bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1829         }
1830 }
1831 static void lattice_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1832 {
1833         struct { short select, mval[2]; float radius; } data;
1834
1835         data.select = (selecting==LEFTMOUSE);
1836         data.mval[0] = mval[0];
1837         data.mval[1] = mval[1];
1838         data.radius = rad;
1839
1840         lattice_foreachScreenVert(latticecurve_selectionCB__doSelect, &data);
1841 }
1842
1843 /** Callbacks for selection in Editmode */
1844
1845 void obedit_selectionCB(short selecting, Object *editobj, short *mval, float rad) 
1846 {
1847         switch(editobj->type) {         
1848         case OB_MESH:
1849                 mesh_selectionCB(selecting, editobj, mval, rad);
1850                 break;
1851         case OB_CURVE:
1852         case OB_SURF:
1853                 nurbscurve_selectionCB(selecting, editobj, mval, rad);
1854                 break;
1855         case OB_LATTICE:
1856                 lattice_selectionCB(selecting, editobj, mval, rad);
1857                 break;
1858         default:
1859                 return;
1860         }
1861
1862         draw_sel_circle(0, 0, 0, 0, 0); /* signal */
1863         force_draw(0);
1864 }
1865
1866 void set_render_border(void)
1867 {
1868         rcti rect;
1869         short val;
1870
1871         if(G.vd->persp!=2) return;
1872         
1873         val= get_border(&rect, 2);
1874         if(val) {
1875                 rcti vb;
1876
1877                 calc_viewborder(G.vd, &vb);
1878
1879                 G.scene->r.border.xmin= (float) (rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
1880                 G.scene->r.border.ymin= (float) (rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
1881                 G.scene->r.border.xmax= (float) (rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
1882                 G.scene->r.border.ymax= (float) (rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
1883                 
1884                 CLAMP(G.scene->r.border.xmin, 0.0, 1.0);
1885                 CLAMP(G.scene->r.border.ymin, 0.0, 1.0);
1886                 CLAMP(G.scene->r.border.xmax, 0.0, 1.0);
1887                 CLAMP(G.scene->r.border.ymax, 0.0, 1.0);
1888                 
1889                 allqueue(REDRAWVIEWCAM, 1);
1890                 // if it was not set, we do this
1891                 G.scene->r.mode |= R_BORDER;
1892                 allqueue(REDRAWBUTSSCENE, 1);
1893         }
1894 }
1895
1896
1897
1898 void fly(void)
1899 {
1900         float speed=0.0, speedo=1.0, zspeed=0.0, dvec[3], *quat, mat[3][3];
1901         float oldvec[3], oldrot[3];
1902         int loop=1;
1903         unsigned short toets;
1904         short val, cent[2];
1905         short mval[2];
1906         
1907         if(curarea->spacetype!=SPACE_VIEW3D) return;
1908         if(G.vd->camera == 0) return;
1909         if(G.vd->persp<2) return;
1910         
1911         VECCOPY(oldvec, G.vd->camera->loc);
1912         VECCOPY(oldrot, G.vd->camera->rot);
1913         
1914         cent[0]= curarea->winrct.xmin+(curarea->winx)/2;
1915         cent[1]= curarea->winrct.ymin+(curarea->winy)/2;
1916         
1917         warp_pointer(cent[0], cent[1]);
1918         
1919         /* we have to rely on events to give proper mousecoords after a warp_pointer */
1920         mval[0]= cent[0]=  (curarea->winx)/2;
1921         mval[1]= cent[1]=  (curarea->winy)/2;
1922         
1923         headerprint("Fly");
1924         
1925         while(loop) {
1926                 
1927
1928                 while(qtest()) {
1929                         
1930                         toets= extern_qread(&val);
1931                         
1932                         if(val) {
1933                                 if(toets==MOUSEY) getmouseco_areawin(mval);
1934                                 else if(toets==ESCKEY) {
1935                                         VECCOPY(G.vd->camera->loc, oldvec);
1936                                         VECCOPY(G.vd->camera->rot, oldrot);
1937                                         loop= 0;
1938                                         break;
1939                                 }
1940                                 else if(toets==SPACEKEY) {
1941                                         loop= 0;
1942                                         BIF_undo_push("Fly camera");
1943                                         break;
1944                                 }
1945                                 else if(toets==LEFTMOUSE) {
1946                                         speed+= G.vd->grid/75.0;
1947                                         if(get_mbut()&M_MOUSE) speed= 0.0;
1948                                 }
1949                                 else if(toets==MIDDLEMOUSE) {
1950                                         speed-= G.vd->grid/75.0;
1951                                         if(get_mbut()&L_MOUSE) speed= 0.0;
1952                                 }
1953                         }
1954                 }
1955                 if(loop==0) break;
1956                 
1957                 /* define dvec */
1958                 val= mval[0]-cent[0];
1959                 if(val>20) val-= 20; else if(val< -20) val+= 20; else val= 0;
1960                 dvec[0]= 0.000001*val*val;
1961                 if(val>0) dvec[0]= -dvec[0];
1962                 
1963                 val= mval[1]-cent[1];
1964                 if(val>20) val-= 20; else if(val< -20) val+= 20; else val= 0;
1965                 dvec[1]= 0.000001*val*val;
1966                 if(val>0) dvec[1]= -dvec[1];
1967                 
1968                 dvec[2]= 1.0;
1969                 
1970                 zspeed= 0.0;
1971                 if(get_qual()&LR_CTRLKEY) zspeed= -G.vd->grid/25.0;
1972                 if(get_qual()&LR_ALTKEY) zspeed= G.vd->grid/25.0;
1973                 
1974                 if(speedo!=0.0 || zspeed!=0.0 || dvec[0]!=0.0 || dvec[1]!=0.0) {
1975                 
1976                         Normalise(dvec);
1977                         
1978                         Mat3CpyMat4(mat, G.vd->viewinv);
1979                         Mat3MulVecfl(mat, dvec);
1980                         quat= vectoquat(dvec, 5, 1);    /* track and upflag, not from the base: camera view calculation does not use that */
1981                         
1982                         QuatToEul(quat, G.vd->camera->rot);
1983                         
1984                         compatible_eul(G.vd->camera->rot, oldrot);
1985                         
1986                         VecMulf(dvec, speed);
1987                         G.vd->camera->loc[0]-= dvec[0];
1988                         G.vd->camera->loc[1]-= dvec[1];
1989                         G.vd->camera->loc[2]-= (dvec[2]-zspeed);
1990                         
1991                         scrarea_do_windraw(curarea);
1992                         screen_swapbuffers();
1993                 }
1994                 speedo= speed;
1995         }
1996         
1997         allqueue(REDRAWVIEW3D, 0);
1998         scrarea_queue_headredraw(curarea);
1999         
2000 }
2001
2002 void view3d_edit_clipping(View3D *v3d)
2003 {
2004         
2005         if(v3d->flag & V3D_CLIPPING) {
2006                 v3d->flag &= ~V3D_CLIPPING;
2007                 scrarea_queue_winredraw(curarea);
2008                 if(v3d->clipbb) MEM_freeN(v3d->clipbb);
2009                 v3d->clipbb= NULL;
2010         }
2011         else {
2012                 rcti rect;
2013                 double mvmatrix[16];
2014                 double projmatrix[16];
2015                 double xs, ys, p[3];
2016                 GLint viewport[4];
2017                 short val;
2018                 
2019                 /* get border in window coords */
2020                 setlinestyle(2);
2021                 val= get_border(&rect, 3);
2022                 setlinestyle(0);
2023                 if(val==0) return;
2024                 
2025                 v3d->flag |= V3D_CLIPPING;
2026                 v3d->clipbb= MEM_mallocN(sizeof(BoundBox), "clipbb");
2027                 
2028                 /* convert border to 3d coordinates */
2029                 
2030                 /* Get the matrices needed for gluUnProject */
2031                 glGetIntegerv(GL_VIEWPORT, viewport);
2032                 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
2033                 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
2034                 
2035                 /* Set up viewport so that gluUnProject will give correct values */
2036                 viewport[0] = 0;
2037                 viewport[1] = 0;
2038                 
2039                 /* four clipping planes and bounding volume */
2040                 /* first do the bounding volume */
2041                 for(val=0; val<4; val++) {
2042                         
2043                         xs= (val==0||val==3)?rect.xmin:rect.xmax;
2044                         ys= (val==0||val==1)?rect.ymin:rect.ymax;
2045                         
2046                         gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
2047                         VECCOPY(v3d->clipbb->vec[val], p);
2048                         
2049                         gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
2050                         VECCOPY(v3d->clipbb->vec[4+val], p);
2051                 }
2052                 
2053                 /* then plane equations */
2054                 for(val=0; val<4; val++) {
2055                         
2056                         CalcNormFloat(v3d->clipbb->vec[val], v3d->clipbb->vec[val==3?0:val+1], v3d->clipbb->vec[val+4],
2057                                                   v3d->clip[val]); 
2058                         
2059                         v3d->clip[val][3]= - v3d->clip[val][0]*v3d->clipbb->vec[val][0] 
2060                                                            - v3d->clip[val][1]*v3d->clipbb->vec[val][1] 
2061                                                            - v3d->clip[val][2]*v3d->clipbb->vec[val][2];
2062                 }
2063         }
2064 }
2065