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