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