Changes to "Face Select" mode
[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_curve_types.h"
50 #include "DNA_camera_types.h"
51 #include "DNA_group_types.h"
52 #include "DNA_lattice_types.h"
53 #include "DNA_meta_types.h"
54 #include "DNA_mesh_types.h"
55 #include "DNA_meshdata_types.h"
56 #include "DNA_object_types.h"
57 #include "DNA_scene_types.h"
58 #include "DNA_screen_types.h"
59 #include "DNA_space_types.h"
60 #include "DNA_view3d_types.h"
61 #include "DNA_userdef_types.h"
62 #include "DNA_ipo_types.h" /* for fly mode recording */
63
64 #include "BLI_blenlib.h"
65 #include "BLI_arithb.h"
66 #include "BLI_editVert.h"
67
68 #include "BKE_armature.h"
69 #include "BKE_depsgraph.h"
70 #include "BKE_global.h"
71 #include "BKE_group.h"
72 #include "BKE_lattice.h"
73 #include "BKE_main.h"
74 #include "BKE_mesh.h"
75 #include "BKE_object.h" /* fly mode where_is_object to get camera location */
76 #include "BKE_utildefines.h"
77 #include "BKE_customdata.h"
78
79 #include "BIF_butspace.h"
80 #include "BIF_editaction.h"
81 #include "BIF_editarmature.h"
82 #include "BIF_editgroup.h"
83 #include "BIF_editmesh.h"
84 #include "BIF_editoops.h"
85 #include "BIF_editsima.h"
86 #include "BIF_editview.h"
87 #include "BIF_gl.h"
88 #include "BIF_glutil.h"
89 #include "BIF_interface.h"
90 #include "BIF_mywindow.h"
91 #include "BIF_previewrender.h" /* use only so fly mode can preview when its done */
92 #include "BIF_space.h"
93 #include "BIF_screen.h"
94 #include "BIF_toolbox.h"
95
96 #include "BDR_editobject.h"     /* For headerprint */
97 #include "BDR_sculptmode.h"
98 #include "BDR_vpaint.h"
99 #include "BDR_editface.h"
100 #include "BDR_drawobject.h"
101 #include "BDR_editcurve.h"
102
103 #include "BSE_edit.h"
104 #include "BSE_view.h"           /* give_cursor() */
105 #include "BSE_editipo.h"
106 #include "BSE_drawview.h"
107
108 #include "editmesh.h"   /* borderselect uses it... */
109 #include "blendef.h"
110 #include "mydevice.h"
111
112 #include "BIF_transform.h"
113 #include "BIF_toets.h"                      /* persptoetsen                 */
114
115 extern ListBase editNurb; /* originally from exports.h, memory from editcurve.c*/
116 /* editmball.c */
117 extern ListBase editelems;
118
119 /* fly mode uses this */
120 extern void setcameratoview3d(void);
121
122 /* local prototypes */
123
124 void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select)
125 {
126         EditVert *eve;
127         int index= em_wireoffs;
128
129         for(eve= em->verts.first; eve; eve= eve->next, index++) {
130                 if(eve->h==0) {
131                         if(EM_check_backbuf(index)) {
132                                 eve->f = select?(eve->f|1):(eve->f&~1);
133                         }
134                 }
135         }
136 }
137
138 void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select)
139 {
140         EditEdge *eed;
141         int index= em_solidoffs;
142
143         for(eed= em->edges.first; eed; eed= eed->next, index++) {
144                 if(eed->h==0) {
145                         if(EM_check_backbuf(index)) {
146                                 EM_select_edge(eed, select);
147                         }
148                 }
149         }
150 }
151
152 void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select)
153 {
154         EditFace *efa;
155         int index= 1;
156
157         for(efa= em->faces.first; efa; efa= efa->next, index++) {
158                 if(efa->h==0) {
159                         if(EM_check_backbuf(index)) {
160                                 EM_select_face_fgon(efa, select);
161                         }
162                 }
163         }
164 }
165
166 void EM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
167 {
168         MFace *mface = me->mface;
169         int a;
170
171         if (mface) {
172                 for(a=1; a<=me->totface; a++, mface++) {
173                         if(EM_check_backbuf(a)) {
174                                 mface->flag = select?(mface->flag|ME_FACE_SEL):(mface->flag&~ME_FACE_SEL);
175                         }
176                 }
177         }
178 }
179
180 void arrows_move_cursor(unsigned short event)
181 {
182         short mval[2];
183
184         getmouseco_sc(mval);
185
186         if(event==UPARROWKEY) {
187                 warp_pointer(mval[0], mval[1]+1);
188         } else if(event==DOWNARROWKEY) {
189                 warp_pointer(mval[0], mval[1]-1);
190         } else if(event==LEFTARROWKEY) {
191                 warp_pointer(mval[0]-1, mval[1]);
192         } else if(event==RIGHTARROWKEY) {
193                 warp_pointer(mval[0]+1, mval[1]);
194         }
195 }
196
197 /* simple API for object selection, rather than just using the flag
198  * this takes into account the 'restrict selection in 3d view' flag.
199  * deselect works always, the restriction just prevents selection */
200 void select_base_v3d(Base *base, short mode)
201 {
202         if (base) {
203                 if (mode==BA_SELECT) {
204                         if (!(base->object->restrictflag & OB_RESTRICT_SELECT))
205                                 if (mode==BA_SELECT) base->flag |= SELECT;
206                 }
207                 else if (mode==BA_DESELECT) {
208                         base->flag &= ~SELECT;
209                 }
210         }
211 }
212
213 /* *********************** GESTURE AND LASSO ******************* */
214
215 /* helper also for borderselect */
216 static int edge_fully_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
217 {
218         return BLI_in_rcti(rect, x1, y1) && BLI_in_rcti(rect, x2, y2);
219 }
220
221 static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
222 {
223         int d1, d2, d3, d4;
224         
225         /* check points in rect */
226         if(edge_fully_inside_rect(rect, x1, y1, x2, y2)) return 1;
227         
228         /* check points completely out rect */
229         if(x1<rect->xmin && x2<rect->xmin) return 0;
230         if(x1>rect->xmax && x2>rect->xmax) return 0;
231         if(y1<rect->ymin && y2<rect->ymin) return 0;
232         if(y1>rect->ymax && y2>rect->ymax) return 0;
233         
234         /* simple check lines intersecting. */
235         d1= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymin );
236         d2= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymax );
237         d3= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymax );
238         d4= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymin );
239         
240         if(d1<0 && d2<0 && d3<0 && d4<0) return 0;
241         if(d1>0 && d2>0 && d3>0 && d4>0) return 0;
242         
243         return 1;
244 }
245
246
247 #define MOVES_GESTURE 50
248 #define MOVES_LASSO 500
249
250 static int lasso_inside(short mcords[][2], short moves, short sx, short sy)
251 {
252         /* we do the angle rule, define that all added angles should be about zero or 2*PI */
253         float angletot=0.0, len, dot, ang, cross, fp1[2], fp2[2];
254         int a;
255         short *p1, *p2;
256         
257         if(sx==IS_CLIPPED)
258                 return 0;
259         
260         p1= mcords[moves-1];
261         p2= mcords[0];
262         
263         /* first vector */
264         fp1[0]= (float)(p1[0]-sx);
265         fp1[1]= (float)(p1[1]-sy);
266         len= sqrt(fp1[0]*fp1[0] + fp1[1]*fp1[1]);
267         fp1[0]/= len;
268         fp1[1]/= len;
269         
270         for(a=0; a<moves; a++) {
271                 /* second vector */
272                 fp2[0]= (float)(p2[0]-sx);
273                 fp2[1]= (float)(p2[1]-sy);
274                 len= sqrt(fp2[0]*fp2[0] + fp2[1]*fp2[1]);
275                 fp2[0]/= len;
276                 fp2[1]/= len;
277                 
278                 /* dot and angle and cross */
279                 dot= fp1[0]*fp2[0] + fp1[1]*fp2[1];
280                 ang= fabs(saacos(dot));
281
282                 cross= (float)((p1[1]-p2[1])*(p1[0]-sx) + (p2[0]-p1[0])*(p1[1]-sy));
283                 
284                 if(cross<0.0) angletot-= ang;
285                 else angletot+= ang;
286                 
287                 /* circulate */
288                 fp1[0]= fp2[0]; fp1[1]= fp2[1];
289                 p1= p2;
290                 p2= mcords[a+1];
291         }
292         
293         if( fabs(angletot) > 4.0 ) return 1;
294         return 0;
295 }
296
297 /* edge version for lasso select. we assume boundbox check was done */
298 static int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1)
299 {
300         short v1[2], v2[2];
301         int a;
302
303         if(x0==IS_CLIPPED || x1==IS_CLIPPED)
304                 return 0;
305         
306         v1[0] = x0, v1[1] = y0;
307         v2[0] = x1, v2[1] = y1;
308
309         /* check points in lasso */
310         if(lasso_inside(mcords, moves, v1[0], v1[1])) return 1;
311         if(lasso_inside(mcords, moves, v2[0], v2[1])) return 1;
312         
313         /* no points in lasso, so we have to intersect with lasso edge */
314         
315         if( IsectLL2Ds(mcords[0], mcords[moves-1], v1, v2) > 0) return 1;
316         for(a=0; a<moves-1; a++) {
317                 if( IsectLL2Ds(mcords[a], mcords[a+1], v1, v2) > 0) return 1;
318         }
319         
320         return 0;
321 }
322
323
324 /* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN) 
325    and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK
326 */
327 static void do_lasso_select_pose(Object *ob, short mcords[][2], short moves, short select)
328 {
329         bPoseChannel *pchan;
330         float vec[3];
331         short sco1[2], sco2[2];
332         
333         if(ob->type!=OB_ARMATURE || ob->pose==NULL) return;
334         
335         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
336                 VECCOPY(vec, pchan->pose_head);
337                 Mat4MulVecfl(ob->obmat, vec);
338                 project_short(vec, sco1);
339                 VECCOPY(vec, pchan->pose_tail);
340                 Mat4MulVecfl(ob->obmat, vec);
341                 project_short(vec, sco2);
342                 
343                 if(lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
344                         if(select) pchan->bone->flag |= BONE_SELECTED;
345                         else pchan->bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
346                 }
347         }
348 }
349
350
351 static void do_lasso_select_objects(short mcords[][2], short moves, short select)
352 {
353         Base *base;
354         
355         for(base= G.scene->base.first; base; base= base->next) {
356                 if(base->lay & G.vd->lay) {
357                         project_short(base->object->obmat[3], &base->sx);
358                         if(lasso_inside(mcords, moves, base->sx, base->sy)) {
359                                 
360                                 if(select) select_base_v3d(base, BA_SELECT);
361                                 else select_base_v3d(base, BA_DESELECT);
362                                 base->object->flag= base->flag;
363                         }
364                         if(base->object->flag & OB_POSEMODE) {
365                                 do_lasso_select_pose(base->object, mcords, moves, select);
366                         }
367                 }
368         }
369 }
370
371 static void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
372 {
373         short a;
374         
375         rect->xmin= rect->xmax= mcords[0][0];
376         rect->ymin= rect->ymax= mcords[0][1];
377         
378         for(a=1; a<moves; a++) {
379                 if(mcords[a][0]<rect->xmin) rect->xmin= mcords[a][0];
380                 else if(mcords[a][0]>rect->xmax) rect->xmax= mcords[a][0];
381                 if(mcords[a][1]<rect->ymin) rect->ymin= mcords[a][1];
382                 else if(mcords[a][1]>rect->ymax) rect->ymax= mcords[a][1];
383         }
384 }
385
386 static void do_lasso_select_mesh__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
387 {
388         struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
389
390         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
391                 eve->f = data->select?(eve->f|1):(eve->f&~1);
392         }
393 }
394 static void do_lasso_select_mesh__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
395 {
396         struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
397
398         if (EM_check_backbuf(em_solidoffs+index)) {
399                 if (data->pass==0) {
400                         if (    edge_fully_inside_rect(data->rect, x0, y0, x1, y1)  &&
401                                         lasso_inside(data->mcords, data->moves, x0, y0) &&
402                                         lasso_inside(data->mcords, data->moves, x1, y1)) {
403                                 EM_select_edge(eed, data->select);
404                                 data->done = 1;
405                         }
406                 } else {
407                         if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) {
408                                 EM_select_edge(eed, data->select);
409                         }
410                 }
411         }
412 }
413 static void do_lasso_select_mesh__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
414 {
415         struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
416
417         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
418                 EM_select_face_fgon(efa, data->select);
419         }
420 }
421
422 static void do_lasso_select_mesh(short mcords[][2], short moves, short select)
423 {
424         struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } data;
425         EditMesh *em = G.editMesh;
426         rcti rect;
427         int bbsel;
428         
429         lasso_select_boundbox(&rect, mcords, moves);
430         
431         data.rect = &rect;
432         data.mcords = mcords;
433         data.moves = moves;
434         data.select = select;
435         data.done = 0;
436         data.pass = 0;
437
438         bbsel= EM_mask_init_backbuf_border(mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
439         
440         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
441                 if (bbsel) {
442                         EM_backbuf_checkAndSelectVerts(em, select);
443                 } else {
444                         mesh_foreachScreenVert(do_lasso_select_mesh__doSelectVert, &data, 1);
445                 }
446         }
447         if(G.scene->selectmode & SCE_SELECT_EDGE) {
448                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
449
450                 data.pass = 0;
451                 mesh_foreachScreenEdge(do_lasso_select_mesh__doSelectEdge, &data, 0);
452
453                 if (data.done==0) {
454                         data.pass = 1;
455                         mesh_foreachScreenEdge(do_lasso_select_mesh__doSelectEdge, &data, 0);
456                 }
457         }
458         
459         if(G.scene->selectmode & SCE_SELECT_FACE) {
460                 if (bbsel) {
461                         EM_backbuf_checkAndSelectFaces(em, select);
462                 } else {
463                         mesh_foreachScreenFace(do_lasso_select_mesh__doSelectFace, &data);
464                 }
465         }
466         
467         EM_free_backbuf();
468         EM_selectmode_flush();  
469 }
470
471 static void do_lasso_select_curve__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
472 {
473         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
474
475         if (lasso_inside(data->mcords, data->moves, x, y)) {
476                 if (bp) {
477                         bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
478                 } else {
479                         if (beztindex==0) {
480                                 bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
481                         } else if (beztindex==1) {
482                                 bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
483                         } else {
484                                 bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
485                         }
486                 }
487         }
488 }
489 static void do_lasso_select_curve(short mcords[][2], short moves, short select)
490 {
491         struct { short (*mcords)[2]; short moves; short select; } data;
492
493         data.mcords = mcords;
494         data.moves = moves;
495         data.select = select;
496
497         nurbs_foreachScreenVert(do_lasso_select_curve__doSelect, &data);
498 }
499
500 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, int y)
501 {
502         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
503
504         if (lasso_inside(data->mcords, data->moves, x, y)) {
505                 bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
506         }
507 }
508 static void do_lasso_select_lattice(short mcords[][2], short moves, short select)
509 {
510         struct { short (*mcords)[2]; short moves; short select; } data;
511
512         data.mcords = mcords;
513         data.moves = moves;
514         data.select = select;
515
516         lattice_foreachScreenVert(do_lasso_select_lattice__doSelect, &data);
517 }
518
519 static void do_lasso_select_armature(short mcords[][2], short moves, short select)
520 {
521         EditBone *ebone;
522         float vec[3];
523         short sco1[2], sco2[2], didpoint;
524         
525         for (ebone=G.edbo.first; ebone; ebone=ebone->next) {
526
527                 VECCOPY(vec, ebone->head);
528                 Mat4MulVecfl(G.obedit->obmat, vec);
529                 project_short(vec, sco1);
530                 VECCOPY(vec, ebone->tail);
531                 Mat4MulVecfl(G.obedit->obmat, vec);
532                 project_short(vec, sco2);
533                 
534                 didpoint= 0;
535                 if(lasso_inside(mcords, moves, sco1[0], sco1[1])) {
536                         if(select) ebone->flag |= BONE_ROOTSEL;
537                         else ebone->flag &= ~BONE_ROOTSEL;
538                         didpoint= 1;
539                 }
540                 if(lasso_inside(mcords, moves, sco2[0], sco2[1])) {
541                    if(select) ebone->flag |= BONE_TIPSEL;
542                    else ebone->flag &= ~BONE_TIPSEL;
543                    didpoint= 1;
544                 }
545                 /* if one of points selected, we skip the bone itself */
546                 if(didpoint==0 && lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
547                         if(select) ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
548                         else ebone->flag &= ~(BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
549                 }
550         }
551         countall();     /* abused for flushing selection */
552 }
553
554 static void do_lasso_select_facemode(short mcords[][2], short moves, short select)
555 {
556         Mesh *me;
557         rcti rect;
558         
559         me= get_mesh(OBACT);
560         if(me==NULL || me->mtface==NULL) return;
561         if(me->totface==0) return;
562         
563         em_vertoffs= me->totface+1;     /* max index array */
564         
565         lasso_select_boundbox(&rect, mcords, moves);
566         EM_mask_init_backbuf_border(mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
567         
568         EM_backbuf_checkAndSelectTFaces(me, select);
569         
570         EM_free_backbuf();
571         
572         object_tface_flags_changed(OBACT, 0);
573 }
574
575 static void do_lasso_select(short mcords[][2], short moves, short select)
576 {
577         if(G.obedit==NULL) {
578                 if(FACESEL_PAINT_TEST)
579                         do_lasso_select_facemode(mcords, moves, select);
580                 else if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))
581                         ;
582                 else  
583                         do_lasso_select_objects(mcords, moves, select);
584         }
585         else if(G.obedit->type==OB_MESH) 
586                 do_lasso_select_mesh(mcords, moves, select);
587         else if(G.obedit->type==OB_CURVE || G.obedit->type==OB_SURF) 
588                 do_lasso_select_curve(mcords, moves, select);
589         else if(G.obedit->type==OB_LATTICE) 
590                 do_lasso_select_lattice(mcords, moves, select);
591         else if(G.obedit->type==OB_ARMATURE)
592                 do_lasso_select_armature(mcords, moves, select);
593         
594         BIF_undo_push("Lasso select");
595         
596         if (EM_texFaceCheck())
597                 allqueue(REDRAWIMAGE, 0);
598         
599         allqueue(REDRAWVIEW3D, 0);
600         countall();
601 }
602
603 /* un-draws and draws again */
604 static void draw_lasso_select(short mcords[][2], short moves, short end)
605 {
606         int a;
607         
608         setlinestyle(2);
609         /* clear draw */
610         if(moves>1) {
611                 for(a=1; a<=moves-1; a++) {
612                         sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
613                 }
614                 sdrawXORline(mcords[moves-1][0], mcords[moves-1][1], mcords[0][0], mcords[0][1]);
615         }
616         if(!end) {
617                 /* new draw */
618                 for(a=1; a<=moves; a++) {
619                         sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
620                 }
621                 sdrawXORline(mcords[moves][0], mcords[moves][1], mcords[0][0], mcords[0][1]);
622         }
623         setlinestyle(0);
624 }
625
626
627 static char interpret_move(short mcord[][2], int count)
628 {
629         float x1, x2, y1, y2, d1, d2, inp, sq, mouse[MOVES_GESTURE][2];
630         int i, j, dir = 0;
631         
632         if (count <= 10) return ('g');
633
634         /* from short to float (drawing is with shorts) */
635         for(j=0; j<count; j++) {
636                 mouse[j][0]= mcord[j][0];
637                 mouse[j][1]= mcord[j][1];
638         }
639         
640         /* new method:
641          * 
642          * starting from end points, calculate center with maximum distance
643          * dependant at the angle s / g / r is defined
644          */
645         
646
647         /* filter */
648         
649         for( j = 3 ; j > 0; j--){
650                 x1 = mouse[1][0];
651                 y1 = mouse[1][1];
652                 for (i = 2; i < count; i++){
653                         x2 = mouse[i-1][0];
654                         y2 = mouse[i-1][1];
655                         mouse[i-1][0] = ((x1 + mouse[i][0]) /4.0) + (x2 / 2.0);
656                         mouse[i-1][1] = ((y1 + mouse[i][1]) /4.0) + (y2 / 2.0);
657                         x1 = x2;
658                         y1 = y2;
659                 }
660         }
661
662         /* make overview of directions */
663         for (i = 0; i <= count - 2; i++){
664                 x1 = mouse[i][0] - mouse[i + 1][0];
665                 y1 = mouse[i][1] - mouse[i + 1][1];
666
667                 if (x1 < -0.5){
668                         if (y1 < -0.5) dir |= 32;
669                         else if (y1 > 0.5) dir |= 128;
670                         else dir |= 64;
671                 } else if (x1 > 0.5){
672                         if (y1 < -0.5) dir |= 8;
673                         else if (y1 > 0.5) dir |= 2;
674                         else dir |= 4;
675                 } else{
676                         if (y1 < -0.5) dir |= 16;
677                         else if (y1 > 0.5) dir |= 1;
678                         else dir |= 0;
679                 }
680         }
681         
682         /* move all crosses to the right */
683         for (i = 7; i>=0 ; i--){
684                 if (dir & 128) dir = (dir << 1) + 1;
685                 else break;
686         }
687         dir &= 255;
688         for (i = 7; i>=0 ; i--){
689                 if ((dir & 1) == 0) dir >>= 1;
690                 else break;
691         }
692         
693         /* in theory: 1 direction: straight line
694      * multiple sequential directions: circle
695      * non-sequential, and 1 bit set in upper 4 bits: size
696      */
697         switch(dir){
698         case 1:
699                 return ('g');
700                 break;
701         case 3:
702         case 7:
703                 x1 = mouse[0][0] - mouse[count >> 1][0];
704                 y1 = mouse[0][1] - mouse[count >> 1][1];
705                 x2 = mouse[count >> 1][0] - mouse[count - 1][0];
706                 y2 = mouse[count >> 1][1] - mouse[count - 1][1];
707                 d1 = (x1 * x1) + (y1 * y1);
708                 d2 = (x2 * x2) + (y2 * y2);
709                 sq = sqrt(d1);
710                 x1 /= sq; 
711                 y1 /= sq;
712                 sq = sqrt(d2);
713                 x2 /= sq; 
714                 y2 /= sq;
715                 inp = (x1 * x2) + (y1 * y2);
716                 /*printf("%f\n", inp);*/
717                 if (inp > 0.9) return ('g');
718                 else return ('r');
719                 break;
720         case 15:
721         case 31:
722         case 63:
723         case 127:
724         case 255:
725                 return ('r');
726                 break;
727         default:
728                 /* for size at least one of the higher bits has to be set */
729                 if (dir < 16) return ('r');
730                 else return ('s');
731         }
732
733         return (0);
734 }
735
736
737 /* return 1 to denote gesture did something, also does lasso */
738 int gesture(void)
739 {
740         unsigned short event=0;
741         int i= 1, end= 0, a;
742         short mcords[MOVES_LASSO][2]; /* the larger size */
743         short mval[2], val, timer=0, mousebut, lasso=0, maxmoves;
744         
745         if (U.flag & USER_LMOUSESELECT) mousebut = R_MOUSE;
746         else mousebut = L_MOUSE;
747         
748         /* check for lasso */
749         if(G.qual & LR_CTRLKEY) {
750                 if(curarea->spacetype==SPACE_VIEW3D) {
751                         if(G.obedit==NULL) {
752                                 if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT)) return 0;
753                         }
754                         lasso= 1;
755                 }
756         }
757         
758         glDrawBuffer(GL_FRONT);
759         persp(PERSP_WIN);       /*  ortho at pixel level */
760         
761         getmouseco_areawin(mval);
762         
763         mcords[0][0] = mval[0];
764         mcords[0][1] = mval[1];
765         
766         if(lasso) maxmoves= MOVES_LASSO;
767         else maxmoves= MOVES_GESTURE;
768         
769         while(get_mbut() & mousebut) {
770                 
771                 if(qtest()) event= extern_qread(&val);
772                 else if(i==1) {
773                         /* not drawing yet... check for toolbox */
774                         PIL_sleep_ms(10);
775                         timer++;
776                         if(timer>=10*U.tb_leftmouse) {
777                                 glDrawBuffer(GL_BACK); /* !! */
778                                 toolbox_n();
779                                 return 1;
780                         }
781                 }
782                 
783                 switch (event) {
784                 case MOUSEY:
785                         getmouseco_areawin(mval);
786                         if( abs(mval[0]-mcords[i-1][0])>3 || abs(mval[1]-mcords[i-1][1])>3 ) {
787                                 mcords[i][0] = mval[0];
788                                 mcords[i][1] = mval[1];
789                                 
790                                 if(i) {
791                                         if(lasso) draw_lasso_select(mcords, i, 0);
792                                         else sdrawXORline(mcords[i-1][0], mcords[i-1][1], mcords[i][0], mcords[i][1]);
793                                         bglFlush();
794                                 }
795                                 i++;
796                         }
797                         break;
798                 case MOUSEX:
799                         break;
800                 case LEFTMOUSE:
801                         break;
802                 default:
803                         if(event) end= 1;       /* blender returns 0 */
804                         break;
805                 }
806                 if (i == maxmoves || end == 1) break;
807         }
808         
809         /* clear */
810         if(lasso) draw_lasso_select(mcords, i, 1);
811         else for(a=1; a<i; a++) {
812                 sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
813         }
814         
815         persp(PERSP_VIEW);
816         glDrawBuffer(GL_BACK);
817         
818         if (i > 2) {
819                 if(lasso) do_lasso_select(mcords, i, (G.qual & LR_SHIFTKEY)==0);
820                 else {
821                         i = interpret_move(mcords, i);
822                         
823                         if(i) {
824                                 if(curarea->spacetype==SPACE_IPO) transform_ipo(i);
825                                 else if(curarea->spacetype==SPACE_OOPS) transform_oops('g', 0);
826                                 else {
827                                         int context;
828
829                                         if(curarea->spacetype==SPACE_IMAGE) context= CTX_NONE;
830                                         else context= CTX_NONE;
831
832                                         if(i=='g') {
833                                                 initTransform(TFM_TRANSLATION, context);
834                                                 Transform();
835                                         }
836                                         else if(i=='r') {
837                                                 initTransform(TFM_ROTATION, context);
838                                                 Transform();
839                                         }
840                                         else {
841                                                 initTransform(TFM_RESIZE, context);
842                                                 Transform();
843                                         }
844                                 }
845                         }
846                 }
847                 return 1;
848         }
849         return 0;
850 }
851
852 void mouse_cursor(void)
853 {
854         float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
855         short mval[2], mx, my, lr_click=0;
856         
857         if(gesture()) return;
858         
859         getmouseco_areawin(mval);
860
861         mx= mval[0];
862         my= mval[1];
863         
864         fp= give_cursor();
865         
866         if(G.obedit && ((G.qual & LR_CTRLKEY) || get_mbut()&R_MOUSE )) lr_click= 1;
867         VECCOPY(oldcurs, fp);
868         
869         project_short_noclip(fp, mval);
870
871         initgrabz(fp[0], fp[1], fp[2]);
872         
873         if(mval[0]!=IS_CLIPPED) {
874                 
875                 window_to_3d(dvec, mval[0]-mx, mval[1]-my);
876                 VecSubf(fp, fp, dvec);
877                 
878         }
879         else {
880
881                 dx= ((float)(mx-(curarea->winx/2)))*G.vd->zfac/(curarea->winx/2);
882                 dy= ((float)(my-(curarea->winy/2)))*G.vd->zfac/(curarea->winy/2);
883                 
884                 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];
885                 fz= fz/G.vd->zfac;
886                 
887                 fp[0]= (G.vd->persinv[0][0]*dx + G.vd->persinv[1][0]*dy+ G.vd->persinv[2][0]*fz)-G.vd->ofs[0];
888                 fp[1]= (G.vd->persinv[0][1]*dx + G.vd->persinv[1][1]*dy+ G.vd->persinv[2][1]*fz)-G.vd->ofs[1];
889                 fp[2]= (G.vd->persinv[0][2]*dx + G.vd->persinv[1][2]*dy+ G.vd->persinv[2][2]*fz)-G.vd->ofs[2];
890         }
891         
892         allqueue(REDRAWVIEW3D, 1);
893         
894         if(lr_click) {
895                 if(G.obedit->type==OB_MESH) add_click_mesh();
896                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) addvert_Nurb(0);
897                 else if (G.obedit->type==OB_ARMATURE) addvert_armature();
898                 VECCOPY(fp, oldcurs);
899         }
900         
901 }
902
903 void deselectall(void)  /* is toggle */
904 {
905         Base *base;
906         int a=0, ok=0; 
907
908         base= FIRSTBASE;
909         while(base) {
910                 /* is there a visible selected object */
911                 if(base->lay & G.vd->lay &&
912                   (base->object->restrictflag & OB_RESTRICT_VIEW)==0 &&
913                   (base->object->restrictflag & OB_RESTRICT_SELECT)==0
914                 ) {
915                         if (base->flag & SELECT) {
916                                 ok= a= 1;
917                                 break;
918                         } else {
919                                 ok=1;
920                         }
921                 }
922                 base= base->next;
923         }
924         
925         if (!ok) return;
926         
927         base= FIRSTBASE;
928         while(base) {
929                 if(base->lay & G.vd->lay &&
930                   (base->object->restrictflag & OB_RESTRICT_VIEW)==0 &&
931                   (base->object->restrictflag & OB_RESTRICT_SELECT)==0
932                 ) {
933                         if(a) 
934                                 select_base_v3d(base, BA_DESELECT);
935                         else 
936                                 select_base_v3d(base, BA_SELECT);
937                         base->object->flag= base->flag;
938                 }
939                 base= base->next;
940         }
941
942         allqueue(REDRAWVIEW3D, 0);
943         allqueue(REDRAWDATASELECT, 0);
944         allqueue(REDRAWNLA, 0);
945         
946         countall();
947         BIF_undo_push("(De)select all");
948 }
949
950 /* inverts object selection */
951 void selectswap(void)
952 {
953         Base *base;
954
955         for(base= FIRSTBASE; base; base= base->next) {
956                 if(base->lay & G.vd->lay &&
957                   (base->object->restrictflag & OB_RESTRICT_VIEW)==0
958                 ) {
959                         if TESTBASE(base)
960                                 select_base_v3d(base, BA_DESELECT);
961                         else
962                                 select_base_v3d(base, BA_SELECT);
963                         base->object->flag= base->flag;
964                 }
965         }
966
967         allqueue(REDRAWVIEW3D, 0);
968         allqueue(REDRAWDATASELECT, 0);
969         allqueue(REDRAWNLA, 0);
970         
971         countall();
972         BIF_undo_push("Select Inverse");
973 }
974
975
976 /* selects all objects of a particular type, on currently visible layers */
977 void selectall_type(short obtype) 
978 {
979         Base *base;
980         
981         base= FIRSTBASE;
982         while(base) {
983                 if((base->lay & G.vd->lay) &&
984                   (base->object->type == obtype) &&
985                   (base->object->restrictflag & OB_RESTRICT_VIEW)==0
986                 ) {
987                         select_base_v3d(base, BA_SELECT);
988                         base->object->flag= base->flag;
989                 }
990                 base= base->next;
991         }
992
993         allqueue(REDRAWVIEW3D, 0);
994         allqueue(REDRAWDATASELECT, 0);
995         allqueue(REDRAWNLA, 0);
996         
997         countall();
998         BIF_undo_push("Select all per type");
999 }
1000 /* selects all objects on a particular layer */
1001 void selectall_layer(unsigned int layernum) 
1002 {
1003         Base *base;
1004         
1005         base= FIRSTBASE;
1006         while(base) {
1007                 if(base->lay == (1<< (layernum -1)) &&
1008                   (base->object->restrictflag & OB_RESTRICT_VIEW)==0
1009                 ) {
1010                         select_base_v3d(base, BA_SELECT);
1011                         base->object->flag= base->flag;
1012                 }
1013                 base= base->next;
1014         }
1015
1016         allqueue(REDRAWVIEW3D, 0);
1017         allqueue(REDRAWDATASELECT, 0);
1018         allqueue(REDRAWNLA, 0);
1019         
1020         countall();
1021         BIF_undo_push("Select all per layer");
1022 }
1023
1024 static void deselectall_except(Base *b)   /* deselect all except b */
1025 {
1026         Base *base;
1027
1028         base= FIRSTBASE;
1029         while(base) {
1030                 if (base->flag & SELECT) {
1031                         if(b!=base) {
1032                                 select_base_v3d(base, BA_DESELECT);
1033                                 base->object->flag= base->flag;
1034                         }
1035                 }
1036                 base= base->next;
1037         }
1038 }
1039
1040 #if 0
1041 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
1042 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
1043 {
1044         Base *base;
1045         unsigned int *bufmin,*bufmax;
1046         int a,b,rc,tel,aantal,dirvec[4][2],maxob;
1047         unsigned int retval=0;
1048         
1049         base= LASTBASE;
1050         if(base==0) return 0;
1051         maxob= base->selcol;
1052
1053         aantal= (size-1)/2;
1054         rc= 0;
1055
1056         dirvec[0][0]= 1;
1057         dirvec[0][1]= 0;
1058         dirvec[1][0]= 0;
1059         dirvec[1][1]= -size;
1060         dirvec[2][0]= -1;
1061         dirvec[2][1]= 0;
1062         dirvec[3][0]= 0;
1063         dirvec[3][1]= size;
1064
1065         bufmin= buf;
1066         bufmax= buf+ size*size;
1067         buf+= aantal*size+ aantal;
1068
1069         for(tel=1;tel<=size;tel++) {
1070
1071                 for(a=0;a<2;a++) {
1072                         for(b=0;b<tel;b++) {
1073
1074                                 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
1075                                 if( *buf==dontdo ) retval= dontdo;      /* if only color dontdo is available, still return dontdo */
1076                                 
1077                                 buf+= (dirvec[rc][0]+dirvec[rc][1]);
1078
1079                                 if(buf<bufmin || buf>=bufmax) return retval;
1080                         }
1081                         rc++;
1082                         rc &= 3;
1083                 }
1084         }
1085         return retval;
1086 }
1087 #endif
1088
1089 void set_active_base(Base *base)
1090 {
1091         Base *tbase;
1092         
1093         /* activating a non-mesh, should end a couple of modes... */
1094         if(base) {
1095                 if(base->object->type!=OB_MESH) {
1096                         if(G.f & G_SCULPTMODE)
1097                                 set_sculptmode(); /* toggle */
1098                         if(G.f & G_WEIGHTPAINT)
1099                                 set_wpaint();   /* toggle */
1100                         if(G.f & G_VERTEXPAINT)
1101                                 set_vpaint();   /* toggle */
1102                         if(G.f & G_TEXTUREPAINT) 
1103                                 set_texturepaint(); /* Switch off tex paint */
1104                 }
1105         }
1106         
1107         /* sets scene->basact */
1108         BASACT= base;
1109         
1110         if(base) {
1111                 
1112                 /* signals to buttons */
1113                 redraw_test_buttons(base->object);
1114                 
1115                 /* signal to ipo */
1116                 allqueue(REDRAWIPO, base->object->ipowin);
1117                 
1118                 allqueue(REDRAWACTION, 0);
1119                 allqueue(REDRAWNLA, 0);
1120                 allqueue(REDRAWNODE, 0);
1121                 
1122                 /* signal to action */
1123                 select_actionchannel_by_name(base->object->action, "Object", 1);
1124                 
1125                 /* disable temporal locks */
1126                 for(tbase=FIRSTBASE; tbase; tbase= tbase->next) {
1127                         if(base!=tbase && (tbase->object->shapeflag & OB_SHAPE_TEMPLOCK)) {
1128                                 tbase->object->shapeflag &= ~OB_SHAPE_TEMPLOCK;
1129                                 DAG_object_flush_update(G.scene, tbase->object, OB_RECALC_DATA);
1130                         }
1131                 }
1132         }
1133 }
1134
1135 void set_active_object(Object *ob)
1136 {
1137         Base *base;
1138         
1139         for(base= FIRSTBASE; base; base= base->next) {
1140                 if(base->object==ob) {
1141                         set_active_base(base);
1142                         return;
1143                 }
1144         }
1145 }
1146
1147 static void select_all_from_groups(Base *basact)
1148 {
1149         Group *group;
1150         GroupObject *go;
1151         int deselect= basact->flag & SELECT;
1152         
1153         for(group= G.main->group.first; group; group= group->id.next) {
1154                 if(object_in_group(basact->object, group)) {
1155                         for(go= group->gobject.first; go; go= go->next) {
1156                                 if(deselect) go->ob->flag &= ~SELECT;
1157                                 else {
1158                                         if ((go->ob->restrictflag & OB_RESTRICT_SELECT)==0 &&
1159                                                 (go->ob->restrictflag & OB_RESTRICT_VIEW)==0)
1160                                                 go->ob->flag |= SELECT;
1161                                 }
1162                         }
1163                 }
1164         }
1165         /* sync bases */
1166         for(basact= G.scene->base.first; basact; basact= basact->next) {
1167                 if(basact->object->flag & SELECT)
1168                         select_base_v3d(basact, BA_SELECT);
1169                 else
1170                         select_base_v3d(basact, BA_DESELECT);
1171         }
1172 }
1173
1174 /* The max number of menu items in an object select menu */
1175 #define SEL_MENU_SIZE 22
1176
1177 static Base *mouse_select_menu(unsigned int *buffer, int hits, short *mval)
1178 {
1179         Base *baseList[SEL_MENU_SIZE]={NULL}; /*baseList is used to store all possible bases to bring up a menu */
1180         Base *base;
1181         short baseCount = 0;
1182         char menuText[20 + SEL_MENU_SIZE*32] = "Select Object%t";       /* max ob name = 22 */
1183         char str[32];
1184         
1185         for(base=FIRSTBASE; base; base= base->next) {
1186                 if BASE_SELECTABLE(base) {
1187                         baseList[baseCount] = NULL;
1188                         
1189                         /* two selection methods, the CTRL select uses max dist of 15 */
1190                         if(buffer) {
1191                                 int a;
1192                                 for(a=0; a<hits; a++) {
1193                                         /* index was converted */
1194                                         if(base->selcol==buffer[ (4 * a) + 3 ]) baseList[baseCount] = base;
1195                                 }
1196                         }
1197                         else {
1198                                 int temp, dist=15;
1199                                 
1200                                 project_short(base->object->obmat[3], &base->sx);
1201                                 
1202                                 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
1203                                 if(temp<dist ) baseList[baseCount] = base;
1204                         }
1205                         
1206                         if(baseList[baseCount]) {
1207                                 if (baseCount < SEL_MENU_SIZE) {
1208                                         baseList[baseCount] = base;
1209                                         sprintf(str, "|%s %%x%d", base->object->id.name+2, baseCount+1);        /* max ob name == 22 */
1210                                         strcat(menuText, str);
1211                                         baseCount++;
1212                                 }
1213                         }
1214                 }
1215         }
1216         
1217         if(baseCount<=1) return baseList[0];
1218         else {
1219                 baseCount = pupmenu(menuText);
1220                 
1221                 if (baseCount != -1) { /* If nothing is selected then dont do anything */
1222                         return baseList[baseCount-1];
1223                 }
1224                 else return NULL;
1225         }
1226 }
1227
1228 /* we want a select buffer with bones, if there are... */
1229 /* so check three selection levels and compare */
1230 static short mixed_bones_object_selectbuffer(unsigned int *buffer, short *mval)
1231 {
1232         int offs;
1233         short a, hits15, hits9=0, hits5=0;
1234         short has_bones15=0, has_bones9=0, has_bones5=0;
1235         
1236         hits15= view3d_opengl_select(buffer, MAXPICKBUF, mval[0]-14, mval[1]-14, mval[0]+14, mval[1]+14);
1237         if(hits15>0) {
1238                 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
1239                 
1240                 offs= 4*hits15;
1241                 hits9= view3d_opengl_select(buffer+offs, MAXPICKBUF-offs, mval[0]-9, mval[1]-9, mval[0]+9, mval[1]+9);
1242                 if(hits9>0) {
1243                         for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
1244                         
1245                         offs+= 4*hits9;
1246                         hits5= view3d_opengl_select(buffer+offs, MAXPICKBUF-offs, mval[0]-5, mval[1]-5, mval[0]+5, mval[1]+5);
1247                         if(hits5>0) {
1248                                 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
1249                         }
1250                 }
1251                 
1252                 if(has_bones5) {
1253                         offs= 4*hits15 + 4*hits9;
1254                         memcpy(buffer, buffer+offs, 4*offs);
1255                         return hits5;
1256                 }
1257                 if(has_bones9) {
1258                         offs= 4*hits15;
1259                         memcpy(buffer, buffer+offs, 4*offs);
1260                         return hits9;
1261                 }
1262                 if(has_bones15) {
1263                         return hits15;
1264                 }
1265                 
1266                 if(hits5>0) {
1267                         offs= 4*hits15 + 4*hits9;
1268                         memcpy(buffer, buffer+offs, 4*offs);
1269                         return hits5;
1270                 }
1271                 if(hits9>0) {
1272                         offs= 4*hits15;
1273                         memcpy(buffer, buffer+offs, 4*offs);
1274                         return hits9;
1275                 }
1276                 return hits15;
1277         }
1278         
1279         return 0;
1280 }
1281
1282 void mouse_select(void)
1283 {
1284         Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
1285         unsigned int buffer[MAXPICKBUF];
1286         int temp, a, dist=100;
1287         short hits, mval[2];
1288
1289         /* always start list from basact in wire mode */
1290         startbase=  FIRSTBASE;
1291         if(BASACT && BASACT->next) startbase= BASACT->next;
1292
1293         getmouseco_areawin(mval);
1294         
1295         /* This block uses the control key to make the object selected by its center point rather then its contents */
1296         if(G.obedit==0 && (G.qual & LR_CTRLKEY)) {
1297                 
1298                 /* note; shift+alt goes to group-flush-selecting */
1299                 if(G.qual == (LR_ALTKEY|LR_CTRLKEY)) 
1300                         basact= mouse_select_menu(NULL, 0, mval);
1301                 else {
1302                         base= startbase;
1303                         while(base) {
1304                                 if BASE_SELECTABLE(base) {
1305                                         project_short(base->object->obmat[3], &base->sx);
1306                                         
1307                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
1308                                         if(base==BASACT) temp+=10;
1309                                         if(temp<dist ) {
1310                                                 
1311                                                 dist= temp;
1312                                                 basact= base;
1313                                         }
1314                                 }
1315                                 base= base->next;
1316                                 
1317                                 if(base==0) base= FIRSTBASE;
1318                                 if(base==startbase) break;
1319                         }
1320                 }
1321         }
1322         else {
1323                 /* if objects have posemode set, the bones are in the same selection buffer */
1324                 
1325                 hits= mixed_bones_object_selectbuffer(buffer, mval);
1326                 
1327                 if(hits>0) {
1328                         int has_bones= 0;
1329                         
1330                         for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1331
1332                         /* note; shift+alt goes to group-flush-selecting */
1333                         if(has_bones==0 && (G.qual == LR_ALTKEY)) 
1334                                 basact= mouse_select_menu(buffer, hits, mval);
1335                         else {
1336                                 static short lastmval[2]={-100, -100};
1337                                 int donearest= 0;
1338                                 
1339                                 /* define if we use solid nearest select or not */
1340                                 if(G.vd->drawtype>OB_WIRE) {
1341                                         donearest= 1;
1342                                         if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
1343                                                 if(!has_bones)  /* hrms, if theres bones we always do nearest */
1344                                                         donearest= 0;
1345                                         }
1346                                 }
1347                                 lastmval[0]= mval[0]; lastmval[1]= mval[1];
1348                                 
1349                                 if(donearest) {
1350                                         unsigned int min= 0xFFFFFFFF;
1351                                         int selcol= 0, notcol=0;
1352                                         
1353
1354                                         if(has_bones) {
1355                                                 /* we skip non-bone hits */
1356                                                 for(a=0; a<hits; a++) {
1357                                                         if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
1358                                                                 min= buffer[4*a+1];
1359                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1360                                                         }
1361                                                 }
1362                                         }
1363                                         else {
1364                                                 /* only exclude active object when it is selected... */
1365                                                 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol; 
1366                                         
1367                                                 for(a=0; a<hits; a++) {
1368                                                         if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1369                                                                 min= buffer[4*a+1];
1370                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1371                                                         }
1372                                                 }
1373                                         }
1374
1375                                         base= FIRSTBASE;
1376                                         while(base) {
1377                                                 if(base->lay & G.vd->lay) {
1378                                                         if(base->selcol==selcol) break;
1379                                                 }
1380                                                 base= base->next;
1381                                         }
1382                                         if(base) basact= base;
1383                                 }
1384                                 else {
1385                                         
1386                                         base= startbase;
1387                                         while(base) {
1388                                                 /* skip objects with select restriction, to prevent prematurely ending this loop
1389                                                  * with an un-selectable choice */
1390                                                 if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1391                                                         base=base->next;
1392                                                         if(base==NULL) base= FIRSTBASE;
1393                                                         if(base==startbase) break;
1394                                                 }
1395                                         
1396                                                 if(base->lay & G.vd->lay) {
1397                                                         for(a=0; a<hits; a++) {
1398                                                                 if(has_bones) {
1399                                                                         /* skip non-bone objects */
1400                                                                         if((buffer[4*a+3] & 0xFFFF0000)) {
1401                                                                                 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1402                                                                                         basact= base;
1403                                                                         }
1404                                                                 }
1405                                                                 else {
1406                                                                         if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1407                                                                                 basact= base;
1408                                                                 }
1409                                                         }
1410                                                 }
1411                                                 
1412                                                 if(basact) break;
1413                                                 
1414                                                 base= base->next;
1415                                                 if(base==NULL) base= FIRSTBASE;
1416                                                 if(base==startbase) break;
1417                                         }
1418                                 }
1419                         }
1420                         
1421                         if(has_bones && basact) {
1422                                 if( do_pose_selectbuffer(basact, buffer, hits) ) {      /* then bone is found */
1423                                 
1424                                         /* we make the armature selected: 
1425                                            not-selected active object in posemode won't work well for tools */
1426                                         basact->flag|= SELECT;
1427                                         basact->object->flag= basact->flag;
1428                                         
1429                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1430                                         if(G.f & G_WEIGHTPAINT) {
1431                                                 /* prevent activating */
1432                                                 basact= NULL;
1433                                         }
1434                                 }
1435                                 /* prevent bone selecting to pass on to object selecting */
1436                                 if(basact==BASACT)
1437                                         basact= NULL;
1438                         }
1439                 }
1440         }
1441         
1442         /* so, do we have something selected? */
1443         if(basact) {
1444                 
1445                 if(G.obedit) {
1446                         /* only do select */
1447                         deselectall_except(basact);
1448                         select_base_v3d(basact, BA_SELECT);
1449                 }
1450                 /* also prevent making it active on mouse selection */
1451                 else if BASE_SELECTABLE(basact) {
1452
1453                         oldbasact= BASACT;
1454                         BASACT= basact;
1455                         
1456                         if((G.qual & LR_SHIFTKEY)==0) {
1457                                 deselectall_except(basact);
1458                                 select_base_v3d(basact, BA_SELECT);
1459                         }
1460                         else if(G.qual==(LR_SHIFTKEY|LR_ALTKEY)) {
1461                                 select_all_from_groups(basact);
1462                         }
1463                         else {
1464                                 if(basact->flag & SELECT) {
1465                                         if(basact==oldbasact)
1466                                                 select_base_v3d(basact, BA_DESELECT);
1467                                 }
1468                                 else select_base_v3d(basact, BA_SELECT);
1469                         }
1470
1471                         /* copy */
1472                         basact->object->flag= basact->flag;
1473                         
1474                         if(oldbasact != basact) {
1475                                 set_active_base(basact);
1476                         }
1477
1478                         /* for visual speed, only in wire mode */
1479                         if(G.vd->drawtype==OB_WIRE) {
1480                                 /* however, not for posemodes */
1481                                 if(basact->object->flag & OB_POSEMODE);
1482                                 else if(oldbasact && (oldbasact->object->flag & OB_POSEMODE));
1483                                 else {
1484                                         if(oldbasact && oldbasact != basact && (oldbasact->lay & G.vd->lay)) 
1485                                                 draw_object_ext(oldbasact);
1486                                         draw_object_ext(basact);
1487                                 }
1488                         }
1489                         
1490                         allqueue(REDRAWBUTSLOGIC, 0);
1491                         allqueue(REDRAWDATASELECT, 0);
1492                         allqueue(REDRAWBUTSOBJECT, 0);
1493                         allqueue(REDRAWACTION, 0);
1494                         allqueue(REDRAWNLA, 0);
1495                         allqueue(REDRAWTIME, 0);
1496                         allqueue(REDRAWHEADERS, 0);     /* To force display update for the posebutton */
1497                 }
1498                 /* also because multiple 3d windows can be open */
1499                 allqueue(REDRAWVIEW3D, 0);
1500                 
1501         }
1502
1503         countall();
1504
1505         rightmouse_transform(); /* does undo push! */
1506 }
1507
1508 /* ------------------------------------------------------------------------- */
1509
1510 static int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1511 {
1512         int radsq= rad*rad;
1513         float v1[2], v2[2], v3[2];
1514         
1515         /* check points in circle itself */
1516         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1517         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1518         
1519         /* pointdistline */
1520         v3[0]= centx;
1521         v3[1]= centy;
1522         v1[0]= x1;
1523         v1[1]= y1;
1524         v2[0]= x2;
1525         v2[1]= y2;
1526         
1527         if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1528         
1529         return 0;
1530 }
1531
1532 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1533 {
1534         struct { rcti *rect; int select; } *data = userData;
1535
1536         if (BLI_in_rcti(data->rect, x, y)) {
1537                 if (bp) {
1538                         bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1539                 } else {
1540                         if (beztindex==0) {
1541                                 bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
1542                         } else if (beztindex==1) {
1543                                 bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
1544                         } else {
1545                                 bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
1546                         }
1547                 }
1548         }
1549 }
1550 static void do_nurbs_box_select(rcti *rect, int select)
1551 {
1552         struct { rcti *rect; int select; } data;
1553
1554         data.rect = rect;
1555         data.select = select;
1556
1557         nurbs_foreachScreenVert(do_nurbs_box_select__doSelect, &data);
1558 }
1559
1560 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1561 {
1562         struct { rcti *rect; int select; } *data = userData;
1563
1564         if (BLI_in_rcti(data->rect, x, y)) {
1565                 bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1566         }
1567 }
1568 static void do_lattice_box_select(rcti *rect, int select)
1569 {
1570         struct { rcti *rect; int select, pass, done; } data;
1571
1572         data.rect = rect;
1573         data.select = select;
1574
1575         lattice_foreachScreenVert(do_lattice_box_select__doSelect, &data);
1576 }
1577
1578 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1579 {
1580         struct { rcti *rect; short select, pass, done; } *data = userData;
1581
1582         if (BLI_in_rcti(data->rect, x, y)) {
1583                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1584         }
1585 }
1586 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1587 {
1588         struct { rcti *rect; short select, pass, done; } *data = userData;
1589
1590         if(EM_check_backbuf(em_solidoffs+index)) {
1591                 if (data->pass==0) {
1592                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1593                                 EM_select_edge(eed, data->select);
1594                                 data->done = 1;
1595                         }
1596                 } else {
1597                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1598                                 EM_select_edge(eed, data->select);
1599                         }
1600                 }
1601         }
1602 }
1603 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1604 {
1605         struct { rcti *rect; short select, pass, done; } *data = userData;
1606
1607         if (BLI_in_rcti(data->rect, x, y)) {
1608                 EM_select_face_fgon(efa, data->select);
1609         }
1610 }
1611 static void do_mesh_box_select(rcti *rect, int select)
1612 {
1613         struct { rcti *rect; short select, pass, done; } data;
1614         EditMesh *em = G.editMesh;
1615         int bbsel;
1616         
1617         data.rect = rect;
1618         data.select = select;
1619         data.pass = 0;
1620         data.done = 0;
1621
1622         bbsel= EM_init_backbuf_border(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1623
1624         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1625                 if (bbsel) {
1626                         EM_backbuf_checkAndSelectVerts(em, select);
1627                 } else {
1628                         mesh_foreachScreenVert(do_mesh_box_select__doSelectVert, &data, 1);
1629                 }
1630         }
1631         if(G.scene->selectmode & SCE_SELECT_EDGE) {
1632                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1633
1634                 data.pass = 0;
1635                 mesh_foreachScreenEdge(do_mesh_box_select__doSelectEdge, &data, 0);
1636
1637                 if (data.done==0) {
1638                         data.pass = 1;
1639                         mesh_foreachScreenEdge(do_mesh_box_select__doSelectEdge, &data, 0);
1640                 }
1641         }
1642         
1643         if(G.scene->selectmode & SCE_SELECT_FACE) {
1644                 if(bbsel) {
1645                         EM_backbuf_checkAndSelectFaces(em, select);
1646                 } else {
1647                         mesh_foreachScreenFace(do_mesh_box_select__doSelectFace, &data);
1648                 }
1649         }
1650         
1651         EM_free_backbuf();
1652                 
1653         EM_selectmode_flush();
1654 }
1655
1656 /**
1657  * Does the 'borderselect' command. (Select verts based on selecting with a 
1658  * border: key 'b'). All selecting seems to be done in the get_border part.
1659  */
1660 void borderselect(void)
1661 {
1662         rcti rect;
1663         Base *base;
1664         MetaElem *ml;
1665         unsigned int buffer[MAXPICKBUF];
1666         int a, index;
1667         short hits, val;
1668
1669         if(G.obedit==NULL && (FACESEL_PAINT_TEST)) {
1670                 face_borderselect();
1671                 return;
1672         }
1673
1674         a = 0;
1675 #ifdef __APPLE__
1676         a = is_a_really_crappy_intel_card();
1677 #endif
1678         if (!a) setlinestyle(2);
1679         val= get_border(&rect, 3);
1680         if (!a) setlinestyle(0);
1681         
1682         if(val==0) {
1683                 if (EM_texFaceCheck())
1684                         allqueue(REDRAWIMAGE, 0);
1685                 return;
1686         }
1687         
1688         if(G.obedit) {
1689                 if(G.obedit->type==OB_MESH) {
1690                         do_mesh_box_select(&rect, (val==LEFTMOUSE));
1691                         allqueue(REDRAWVIEW3D, 0);
1692                         if (EM_texFaceCheck())
1693                                 allqueue(REDRAWIMAGE, 0);
1694                         
1695                 }
1696                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
1697                         do_nurbs_box_select(&rect, val==LEFTMOUSE);
1698                         allqueue(REDRAWVIEW3D, 0);
1699                 }
1700                 else if(G.obedit->type==OB_MBALL) {
1701                         hits= view3d_opengl_select(buffer, MAXPICKBUF, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1702                         
1703                         ml= editelems.first;
1704                         
1705                         while(ml) {
1706                                 for(a=0; a<hits; a++) {
1707                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1708                                                 ml->flag |= MB_SCALE_RAD;
1709                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1710                                                 else ml->flag &= ~SELECT;
1711                                                 break;
1712                                         }
1713                                         if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1714                                                 ml->flag &= ~MB_SCALE_RAD;
1715                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1716                                                 else ml->flag &= ~SELECT;
1717                                                 break;
1718                                         }
1719                                 }
1720                                 ml= ml->next;
1721                         }
1722                         allqueue(REDRAWVIEW3D, 0);
1723                 }
1724                 else if(G.obedit->type==OB_ARMATURE) {
1725                         EditBone *ebone;
1726                         
1727                         /* clear flag we use to detect point was affected */
1728                         for(ebone= G.edbo.first; ebone; ebone= ebone->next)
1729                                 ebone->flag &= ~BONE_DONE;
1730                         
1731                         hits= view3d_opengl_select(buffer, MAXPICKBUF, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1732                         
1733                         /* first we only check points inside the border */
1734                         for (a=0; a<hits; a++){
1735                                 index = buffer[(4*a)+3];
1736                                 if (index!=-1) {
1737                                         ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1738                                         if (index & BONESEL_TIP) {
1739                                                 ebone->flag |= BONE_DONE;
1740                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
1741                                                 else ebone->flag &= ~BONE_TIPSEL;
1742                                         }
1743                                         
1744                                         if (index & BONESEL_ROOT) {
1745                                                 ebone->flag |= BONE_DONE;
1746                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
1747                                                 else ebone->flag &= ~BONE_ROOTSEL;
1748                                         }
1749                                 }
1750                         }
1751                         
1752                         /* now we have to flush tag from parents... */
1753                         for(ebone= G.edbo.first; ebone; ebone= ebone->next) {
1754                                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1755                                         if(ebone->parent->flag & BONE_DONE)
1756                                                 ebone->flag |= BONE_DONE;
1757                                 }
1758                         }
1759                         
1760                         /* only select/deselect entire bones when no points where in the rect */
1761                         for (a=0; a<hits; a++){
1762                                 index = buffer[(4*a)+3];
1763                                 if (index!=-1) {
1764                                         ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1765                                         if (index & BONESEL_BONE) {
1766                                                 if(!(ebone->flag & BONE_DONE)) {
1767                                                         if (val==LEFTMOUSE)
1768                                                                 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1769                                                         else
1770                                                                 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1771                                                 }
1772                                         }
1773                                 }
1774                         }
1775                         
1776                         allqueue(REDRAWBUTSEDIT, 0);
1777                         allqueue(REDRAWBUTSOBJECT, 0);
1778                         allqueue(REDRAWACTION, 0);
1779                         allqueue(REDRAWVIEW3D, 0);
1780                 }
1781                 else if(G.obedit->type==OB_LATTICE) {
1782                         do_lattice_box_select(&rect, val==LEFTMOUSE);
1783                         allqueue(REDRAWVIEW3D, 0);
1784                 }
1785         }
1786         else {  /* no editmode, unified for bones and objects */
1787                 Bone *bone;
1788                 unsigned int *vbuffer=NULL; /* selection buffer */
1789                 unsigned int *col;                      /* color in buffer      */
1790                 short selecting = 0;
1791                 Object *ob= OBACT;
1792                 int bone_only;
1793                 
1794                 if((ob) && (ob->flag & OB_POSEMODE))
1795                         bone_only= 1;
1796                 else
1797                         bone_only= 0;
1798                 
1799                 if (val==LEFTMOUSE)
1800                         selecting = 1;
1801                 
1802                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1803                 vbuffer = MEM_mallocN(4 * (G.totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1804                 hits= view3d_opengl_select(vbuffer, 4*(G.totobj+MAXPICKBUF), rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1805                 /*
1806                 LOGIC NOTES (theeth):
1807                 The buffer and ListBase have the same relative order, which makes the selection
1808                 very simple. Loop through both data sets at the same time, if the color
1809                 is the same as the object, we have a hit and can move to the next color
1810                 and object pair, if not, just move to the next object,
1811                 keeping the same color until we have a hit.
1812
1813                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1814                 does it incorrectly.
1815                 */
1816
1817                 if (hits>0) { /* no need to loop if there's no hit */
1818                         base= FIRSTBASE;
1819                         col = vbuffer + 3;
1820                         while(base && hits) {
1821                                 Base *next = base->next;
1822                                 if(base->lay & G.vd->lay) {
1823                                         while (base->selcol == (*col & 0xFFFF)) {       /* we got an object */
1824                                                 
1825                                                 if(*col & 0xFFFF0000) {                                 /* we got a bone */
1826                                                         bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1827                                                         if(bone) {
1828                                                                 if(selecting) {
1829                                                                         bone->flag |= BONE_SELECTED;
1830                                                                         select_actionchannel_by_name(base->object->action, bone->name, 1);
1831                                                                 }
1832                                                                 else {
1833                                                                         bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1834                                                                         select_actionchannel_by_name(base->object->action, bone->name, 0);
1835                                                                 }
1836                                                         }
1837                                                 }
1838                                                 else if(!bone_only) {
1839                                                         if (selecting)
1840                                                                 select_base_v3d(base, BA_SELECT);
1841                                                         else
1842                                                                 select_base_v3d(base, BA_DESELECT);
1843
1844                                                         base->object->flag= base->flag;
1845                                                 }
1846
1847                                                 col+=4; /* next color */
1848                                                 hits--;
1849                                                 if(hits==0) break;
1850                                         }
1851                                 }
1852                                 
1853                                 base= next;
1854                         }
1855                 }
1856                 /* frontbuffer flush */
1857                 bglFlush();
1858
1859                 MEM_freeN(vbuffer);
1860                 
1861                 allqueue(REDRAWDATASELECT, 0);
1862                 allqueue(REDRAWBUTSLOGIC, 0);
1863                 allqueue(REDRAWNLA, 0);
1864         }
1865
1866         countall();
1867         
1868         allqueue(REDRAWBUTSOBJECT, 0);
1869         allqueue(REDRAWVIEW3D, 0);
1870         allqueue(REDRAWINFO, 0);
1871
1872         BIF_undo_push("Border select");
1873         
1874 } /* end of borderselect() */
1875
1876 /* ------------------------------------------------------------------------- */
1877
1878 /** The following functions are quick & dirty callback functions called
1879   * on the Circle select function (press B twice in Editmode)
1880   * They were torn out of the circle_select to make the latter more reusable
1881   * The callback version of circle_select (called circle_selectCB) was moved
1882   * to edit.c because of it's (wanted) generality.
1883
1884         XXX These callback functions are still dirty, because they call globals... 
1885   */
1886
1887 static void mesh_selectionCB__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
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                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1895         }
1896 }
1897 static void mesh_selectionCB__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1898 {
1899         struct { short select, mval[2]; float radius; } *data = userData;
1900
1901         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1902                 EM_select_edge(eed, data->select);
1903         }
1904 }
1905 static void mesh_selectionCB__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1906 {
1907         struct { short select, mval[2]; float radius; } *data = userData;
1908         int mx = x - data->mval[0], my = y - data->mval[1];
1909         float r = sqrt(mx*mx + my*my);
1910
1911         if (r<=data->radius) {
1912                 EM_select_face_fgon(efa, data->select);
1913         }
1914 }
1915 static void mesh_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1916 {
1917         struct { short select, mval[2]; float radius; } data;
1918         EditMesh *em = G.editMesh;
1919         int bbsel;
1920
1921         if(!G.obedit && (FACESEL_PAINT_TEST)) {
1922                 Mesh *me = get_mesh(OBACT);
1923
1924                 if (me) {
1925                         em_vertoffs= me->totface+1;     /* max index array */
1926
1927                         bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
1928                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1929                         EM_free_backbuf();
1930
1931                         object_tface_flags_changed(OBACT, 0);
1932                 }
1933
1934                 return;
1935         }
1936
1937         bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
1938         
1939         data.select = (selecting==LEFTMOUSE);
1940         data.mval[0] = mval[0];
1941         data.mval[1] = mval[1];
1942         data.radius = rad;
1943
1944         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1945                 if(bbsel) {
1946                         EM_backbuf_checkAndSelectVerts(em, selecting==LEFTMOUSE);
1947                 } else {
1948                         mesh_foreachScreenVert(mesh_selectionCB__doSelectVert, &data, 1);
1949                 }
1950         }
1951
1952         if(G.scene->selectmode & SCE_SELECT_EDGE) {
1953                 if (bbsel) {
1954                         EM_backbuf_checkAndSelectEdges(em, selecting==LEFTMOUSE);
1955                 } else {
1956                         mesh_foreachScreenEdge(mesh_selectionCB__doSelectEdge, &data, 0);
1957                 }
1958         }
1959         
1960         if(G.scene->selectmode & SCE_SELECT_FACE) {
1961                 if(bbsel) {
1962                         EM_backbuf_checkAndSelectFaces(em, selecting==LEFTMOUSE);
1963                 } else {
1964                         mesh_foreachScreenFace(mesh_selectionCB__doSelectFace, &data);
1965                 }
1966         }
1967
1968         EM_free_backbuf();
1969         EM_selectmode_flush();
1970 }
1971
1972
1973 static void nurbscurve_selectionCB__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1974 {
1975         struct { short select, mval[2]; float radius; } *data = userData;
1976         int mx = x - data->mval[0], my = y - data->mval[1];
1977         float r = sqrt(mx*mx + my*my);
1978
1979         if (r<=data->radius) {
1980                 if (bp) {
1981                         bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1982                 } else {
1983                         if (beztindex==0) {
1984                                 bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
1985                         } else if (beztindex==1) {
1986                                 bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
1987                         } else {
1988                                 bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
1989                         }
1990                 }
1991         }
1992 }
1993 static void nurbscurve_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1994 {
1995         struct { short select, mval[2]; float radius; } data;
1996
1997         data.select = (selecting==LEFTMOUSE);
1998         data.mval[0] = mval[0];
1999         data.mval[1] = mval[1];
2000         data.radius = rad;
2001
2002         nurbs_foreachScreenVert(nurbscurve_selectionCB__doSelect, &data);
2003 }
2004
2005
2006 static void latticecurve_selectionCB__doSelect(void *userData, BPoint *bp, int x, int y)
2007 {
2008         struct { short select, mval[2]; float radius; } *data = userData;
2009         int mx = x - data->mval[0], my = y - data->mval[1];
2010         float r = sqrt(mx*mx + my*my);
2011
2012         if (r<=data->radius) {
2013                 bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
2014         }
2015 }
2016 static void lattice_selectionCB(int selecting, Object *editobj, short *mval, float rad)
2017 {
2018         struct { short select, mval[2]; float radius; } data;
2019
2020         data.select = (selecting==LEFTMOUSE);
2021         data.mval[0] = mval[0];
2022         data.mval[1] = mval[1];
2023         data.radius = rad;
2024
2025         lattice_foreachScreenVert(latticecurve_selectionCB__doSelect, &data);
2026 }
2027
2028 /** Callbacks for selection in Editmode */
2029
2030 void obedit_selectionCB(short selecting, Object *editobj, short *mval, float rad) 
2031 {
2032         switch(editobj->type) {         
2033         case OB_MESH:
2034                 mesh_selectionCB(selecting, editobj, mval, rad);
2035                 break;
2036         case OB_CURVE:
2037         case OB_SURF:
2038                 nurbscurve_selectionCB(selecting, editobj, mval, rad);
2039                 break;
2040         case OB_LATTICE:
2041                 lattice_selectionCB(selecting, editobj, mval, rad);
2042                 break;
2043         default:
2044                 return;
2045         }
2046
2047         draw_sel_circle(0, 0, 0, 0, 0); /* signal */
2048         force_draw(0);
2049 }
2050
2051 void set_render_border(void)
2052 {
2053         rcti rect;
2054         short val;
2055         
2056         val= get_border(&rect, 3);
2057         if(val) {
2058                 rctf vb;
2059
2060                 calc_viewborder(G.vd, &vb);
2061
2062                 G.scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
2063                 G.scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
2064                 G.scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
2065                 G.scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
2066                 
2067                 CLAMP(G.scene->r.border.xmin, 0.0, 1.0);
2068                 CLAMP(G.scene->r.border.ymin, 0.0, 1.0);
2069                 CLAMP(G.scene->r.border.xmax, 0.0, 1.0);
2070                 CLAMP(G.scene->r.border.ymax, 0.0, 1.0);
2071                 
2072                 allqueue(REDRAWVIEWCAM, 1);
2073                 /* if it was not set, we do this */
2074                 G.scene->r.mode |= R_BORDER;
2075                 allqueue(REDRAWBUTSSCENE, 1);
2076         }
2077 }
2078
2079 void view3d_border_zoom(void)
2080 {
2081         /* Zooms in on a border drawn by the user */
2082         rcti rect;
2083         short val;
2084         float dvec[3], vb[2], xscale, yscale, scale;
2085         
2086         /* SMOOTHVIEW */
2087         float new_dist;
2088         float new_ofs[3];
2089         
2090         /* doesn't work fine for perspective */
2091         if(G.vd->persp==1)
2092                 return;
2093         
2094         val = get_border(&rect, 3); //box select input
2095         if(val)
2096         {
2097                 /* find the current window width and height */
2098                 vb[0] = G.vd->area->winx;
2099                 vb[1] = G.vd->area->winy;
2100                 
2101                 new_dist = G.vd->dist;
2102                 new_ofs[0] = G.vd->ofs[0];
2103                 new_ofs[1] = G.vd->ofs[1];
2104                 new_ofs[2] = G.vd->ofs[2];
2105                 
2106                 /* convert the drawn rectangle into 3d space */
2107                 initgrabz(-new_ofs[0], -new_ofs[1], -new_ofs[2]);
2108                 
2109                 window_to_3d(dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
2110                 
2111                 /* center the view to the center of the rectangle */
2112                 VecSubf(new_ofs, new_ofs, dvec);
2113                 
2114                 /* work out the ratios, so that everything selected fits when we zoom */
2115                 xscale = ((rect.xmax-rect.xmin)/vb[0]);
2116                 yscale = ((rect.ymax-rect.ymin)/vb[1]);
2117                 scale = (xscale >= yscale)?xscale:yscale;
2118                 
2119                 /* zoom in as required, or as far as we can go */
2120                 new_dist = ((new_dist*scale) >= 0.001*G.vd->grid)? new_dist*scale:0.001*G.vd->grid;
2121                 
2122                 smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
2123                 
2124         }
2125 }
2126
2127 void fly(void)
2128 {
2129         /*
2130         fly mode - Shift+F
2131         a fly loop where the user can move move the view as if they are flying
2132         */
2133         float speed=0.0, /* the speed the view is moving per redraw */
2134         mat[3][3], /* 3x3 copy of the view matrix so we can move allong the view axis */
2135         dvec[3]={0,0,0}, /* this is the direction thast added to the view offset per redraw */
2136         dvec_old[3]={0,0,0}, /* old for some lag */
2137         dvec_tmp[3]={0,0,0}, /* old for some lag */
2138         dvec_lag=0.0, /* old for some lag */
2139         
2140         /* Camera Uprighting variables */
2141         roll, /* similar to the angle between the camera's up and the Z-up, but its very rough so just roll*/
2142         upvec[3]={0,0,0}, /* stores the view's up vector */
2143         
2144         dist_backup, /* backup the views distance since we use a zero dist for fly mode */
2145         rot_backup[4], /* backup the views quat incase the user cancels flying in non camera mode */
2146         ofs_backup[3], /* backup the views offset incase the user cancels flying in non camera mode */
2147         moffset[2], /* mouse offset from the views center */
2148         tmp_quat[4], /* used for rotating the view */
2149         winxf, winyf, /* scale the mouse movement by this value - scales mouse movement to the view size */
2150         time_redraw, time_redraw_clamped, time_wheel; /*time how fast it takes for us to redraw, this is so simple scenes dont fly too fast */
2151         
2152         /* time_lastwheel is used to accelerate when using the mousewheel a lot */
2153         double time_current, time_lastdraw, time_currwheel, time_lastwheel;
2154         
2155         short val, /* used for toets to see if a buttons pressed */
2156         cent_orig[2], /* view center */
2157         cent[2], /* view center modified */
2158         mval[2], /* mouse location */
2159         action=0, /* while zero stay in fly mode and wait for action, also used to see if we accepted or canceled 1:ok 2:Cancel */
2160         xmargin, ymargin; /* x and y margin are define the safe area where the mouses movement wont rotate the view */
2161         unsigned short
2162         toets; /* for reading the event */
2163         unsigned char
2164         apply_rotation= 1, /* if the user presses shift they can look about without movinf the direction there looking*/
2165         axis= 2, /* Axis index to move allong by default Z to move allong the view */
2166         persp_backup, /* remember if were ortho or not, only used for restoring the view if it was a ortho view */
2167         pan_view=0; /* if true, pan the view instead of rotating */
2168         
2169         /* relative view axis locking - xlock, zlock
2170         0; disabled
2171         1; enabled but not checking because mouse hasnt moved outside the margin since locking was checked an not needed
2172            when the mouse moves, locking is set to 2 so checks are done.
2173         2; mouse moved and checking needed, if no view altering is donem its changed back to 1 */
2174         short xlock=0, zlock=0;
2175         float xlock_momentum=0.0f, zlock_momentum=0.0f; /* nicer dynamics */
2176         
2177         /* for recording */
2178         int playing_anim = has_screenhandler(G.curscreen, SCREEN_HANDLER_ANIM);
2179         int cfra = -1; /*so the first frame always has a key added */
2180         char *actname="";
2181         
2182         if(curarea->spacetype!=SPACE_VIEW3D) return;
2183                 
2184         if(G.vd->persp==2 && G.vd->camera->id.lib) {
2185                 error("Cannot fly a camera from an external library");
2186                 return;
2187         }
2188         
2189         if(G.vd->ob_centre) {
2190                 error("Cannot fly when the view is locked to an object");
2191                 return;
2192         }
2193         
2194         
2195         /* detect weather to start with Z locking */
2196         upvec[0]=1; upvec[1]=0; upvec[2]=0;
2197         Mat3CpyMat4(mat, G.vd->viewinv);
2198         Mat3MulVecfl(mat, upvec);
2199         if (fabs(upvec[2]) < 0.1)
2200                 zlock = 1;
2201         upvec[0]=0; upvec[1]=0; upvec[2]=0;
2202         
2203         persp_backup= G.vd->persp;
2204         dist_backup= G.vd->dist;
2205         if (G.vd->persp==2) { /* Camera */
2206                 if(G.vd->camera->constraints.first) {
2207                         error("Cannot fly an object with constraints");
2208                         return;
2209                 }
2210                 
2211                 /* store the origoinal camera loc and rot */
2212                 VECCOPY(ofs_backup, G.vd->camera->loc);
2213                 VECCOPY(rot_backup, G.vd->camera->rot);
2214                 
2215                 where_is_object(G.vd->camera);
2216                 VECCOPY(G.vd->ofs, G.vd->camera->obmat[3]);
2217                 VecMulf(G.vd->ofs, -1.0f); /*flip the vector*/
2218                 
2219                 G.vd->dist=0.0;
2220                 G.vd->viewbut=0;
2221                 
2222                 /* used for recording */
2223                 if(G.vd->camera->ipoflag & OB_ACTION_OB)
2224                         actname= "Object";
2225                 
2226         } else {
2227                 /* perspective or ortho */
2228                 if (G.vd->persp==0)
2229                         G.vd->persp= 1; /*if ortho projection, make perspective */
2230                 QUATCOPY(rot_backup, G.vd->viewquat);
2231                 VECCOPY(ofs_backup, G.vd->ofs);
2232                 G.vd->dist= 0.0;
2233                 
2234                 upvec[2]=dist_backup; /*x and y are 0*/
2235                 Mat3MulVecfl(mat, upvec);
2236                 VecSubf(G.vd->ofs, G.vd->ofs, upvec);
2237                 /*Done with correcting for the dist*/
2238         }
2239         
2240         /* the dist defines a vector that is infront of the offset
2241         to rotate the view about.
2242         this is no good for fly mode because we
2243         want to rotate about the viewers center.
2244         but to correct the dist removal we must
2245         alter offset so the view dosent jump. */
2246         
2247         xmargin= (short)((float)(curarea->winx)/20.0);
2248         ymargin= (short)((float)(curarea->winy)/20.0);
2249         
2250         cent_orig[0]= curarea->winrct.xmin+(curarea->winx)/2;
2251         cent_orig[1]= curarea->winrct.ymin+(curarea->winy)/2;
2252         
2253         warp_pointer(cent_orig[0], cent_orig[1]);
2254
2255         /* we have to rely on events to give proper mousecoords after a warp_pointer */
2256         mval[0]= cent[0]=  (curarea->winx)/2;
2257         mval[1]= cent[1]=  (curarea->winy)/2;
2258         /* window size minus margin - use this to get the mouse range for rotation */
2259         winxf= (float)(curarea->winx)-(xmargin*2);
2260         winyf= (float)(curarea->winy)-(ymargin*2); 
2261         
2262         
2263         time_lastdraw= time_lastwheel= PIL_check_seconds_timer();
2264         
2265         G.vd->flag2 |= V3D_FLYMODE; /* so we draw the corner margins */
2266         scrarea_do_windraw(curarea);
2267         screen_swapbuffers();
2268         
2269         while(action==0) { /* keep flying, no acton taken */
2270                 while(qtest()) {
2271                         toets= extern_qread(&val);
2272                         
2273                         if(val) {
2274                                 if(toets==MOUSEY) getmouseco_areawin(mval);
2275                                 else if(toets==ESCKEY || toets==RIGHTMOUSE) {
2276                                         action= 2; /* Canceled */
2277                                         break;
2278                                 } else if(toets==SPACEKEY || toets==LEFTMOUSE) {
2279                                         action= 1; /* Accepted */
2280                                         break;
2281                                 } else if(toets==PADPLUSKEY || toets==EQUALKEY || toets==WHEELUPMOUSE) {
2282                                         time_currwheel= PIL_check_seconds_timer();
2283                                         time_wheel = (float)(time_currwheel - time_lastwheel);
2284                                         time_lastwheel = time_currwheel;
2285                                         /*printf("Wheel %f\n", time_wheel);*/
2286                                         /*Mouse wheel delays range from 0.5==slow to 0.01==fast*/ 
2287                                         time_wheel = 1+ (10 - (20*MIN2(time_wheel, 0.5))); /* 0-0.5 -> 0-5.0 */
2288                                         
2289                                         if (speed<0) speed=0;
2290                                         else {
2291                                                 if (G.qual & LR_SHIFTKEY)
2292                                                         speed+= G.vd->grid*time_wheel*0.1;
2293                                                 else
2294                                                         speed+= G.vd->grid*time_wheel;
2295                                         }
2296                                         
2297                                 } else if(toets==PADMINUS || toets==MINUSKEY || toets==WHEELDOWNMOUSE) {
2298                                         time_currwheel= PIL_check_seconds_timer();
2299                                         time_wheel = (float)(time_currwheel - time_lastwheel);
2300                                         time_lastwheel = time_currwheel;
2301                                         time_wheel = 1+ (10 - (20*MIN2(time_wheel, 0.5))); /* 0-0.5 -> 0-5.0 */
2302                                         
2303                                         if (speed>0) speed=0;
2304                                         else {
2305                                                 if (G.qual & LR_SHIFTKEY)
2306                                                         speed-= G.vd->grid*time_wheel*0.1;
2307                                                 else
2308                                                         speed-= G.vd->grid*time_wheel;
2309                                         }
2310                                 
2311                                 } else if (toets==MIDDLEMOUSE) {
2312                                         /* make it so the camera direction dosent follow the view
2313                                         good for flying backwards! - Only when MMB is held */
2314                                         
2315                                         /*apply_rotation=0;*/
2316                                         pan_view= 1;
2317                                         
2318                                 /* impliment WASD keys */
2319                                 } else if(toets==WKEY) {
2320                                         if (speed<0) speed=-speed; /* flip speed rather then stopping, game like motion */
2321                                         else speed+= G.vd->grid; /* increse like mousewheel if were alredy moving in that difection*/
2322                                         axis= 2;
2323                                 } else if(toets==SKEY) { /*SAME as above but flipped */
2324                                         if (speed>0) speed=-speed;
2325                                         else speed-= G.vd->grid;
2326                                         axis= 2;
2327                                 
2328                                 } else if(toets==AKEY) {
2329                                         if (speed<0) speed=-speed;
2330                                         axis= 0;
2331                                 } else if(toets==DKEY) {
2332                                         if (speed>0) speed=-speed;
2333                                         axis= 0;
2334                                 } else if(toets==FKEY) {
2335                                         if (speed<0) speed=-speed;
2336                                         axis= 1;
2337                                 } else if(toets==RKEY) {
2338                                         if (speed>0) speed=-speed;
2339                                         axis= 1;
2340                                 
2341                                 /* axis locking */
2342                                 } else if(toets==XKEY) {
2343                                         if (xlock) xlock=0;
2344                                         else {
2345                                                 xlock = 2;
2346                                                 xlock_momentum = 0.0;
2347                                         }
2348                                 } else if(toets==ZKEY) {
2349                                         if (zlock) zlock=0;
2350                                         else {
2351                                                 zlock = 2;
2352                                                 zlock_momentum = 0.0;
2353                                         }
2354                                 }
2355                                 
2356                         } else {
2357                                 /* mouse buttons lifted */
2358                                 if (toets==MIDDLEMOUSE && pan_view) {
2359                                         /*apply_rotation=1;*/
2360                                         warp_pointer(cent_orig[0], cent_orig[1]);
2361                                         pan_view= 0;
2362                                 }
2363                         }
2364                 }
2365                 if(action != 0) break;
2366                 
2367                 moffset[0]= mval[0]-cent[0];
2368                 moffset[1]= mval[1]-cent[1];
2369                 
2370                 /* enforce a view margin */
2371                 if (moffset[0]>xmargin)         moffset[0]-=xmargin;
2372                 else if (moffset[0]<-xmargin)moffset[0]+=xmargin;
2373                 else                                    moffset[0]=0;
2374
2375                 if (moffset[1]>ymargin)         moffset[1]-=ymargin;
2376                 else if (moffset[1]<-ymargin)moffset[1]+=ymargin;
2377                 else                                    moffset[1]=0;
2378                 
2379                 /* scale the mouse offset so the distance the mouse moves isnt linear */
2380                 if (moffset[0]) {
2381                         moffset[0]= moffset[0]/winxf;
2382                         moffset[0]= moffset[0]*fabs(moffset[0]);
2383                 }
2384                 
2385                 if (moffset[1]) {
2386                         moffset[1]= moffset[1]/winyf;
2387                         moffset[1]= moffset[1]*fabs(moffset[1]);
2388                 }
2389                 
2390                 /* Should we redraw? */
2391                 if(speed!=0.0 || moffset[0] || moffset[1] || zlock || xlock || dvec[0] || dvec[1] || dvec[2] ) {
2392                         
2393                         time_current= PIL_check_seconds_timer();
2394                         time_redraw= (float)(time_current-time_lastdraw);
2395                         time_redraw_clamped= MIN2(0.05, time_redraw); /* clamt the redraw time to avoid jitter in roll correction */
2396                         time_lastdraw= time_current;
2397                         /*fprintf(stderr, "%f\n", time_redraw);*/ /* 0.002 is a small redraw 0.02 is larger */
2398                         
2399                         /* Scale the time to use shift to scale the speed down- just like
2400                         shift slows many other areas of blender down */
2401                         if (G.qual & LR_SHIFTKEY)
2402                                 speed= speed * (1-time_redraw_clamped);
2403                         
2404                         Mat3CpyMat4(mat, G.vd->viewinv);
2405                         
2406                         if (pan_view) {
2407                                 /* pan only */
2408                                 dvec_tmp[0]= -moffset[0];
2409                                 dvec_tmp[1]= -moffset[1];
2410                                 dvec_tmp[2]= 0;
2411                                 
2412                                 if (G.qual & LR_SHIFTKEY) {
2413                                         dvec_tmp[0] *= 0.1;
2414                                         dvec_tmp[1] *= 0.1;
2415                                 }
2416                                 
2417                                 Mat3MulVecfl(mat, dvec_tmp);
2418                                 VecMulf(dvec_tmp, time_redraw*200.0 * G.vd->grid);
2419                                 
2420                         } else {
2421                                 /* rotate about the X axis- look up/down */
2422                                 if (moffset[1]) {
2423                                         upvec[0]=1;
2424                                         upvec[1]=0;
2425                                         upvec[2]=0;
2426                                         Mat3MulVecfl(mat, upvec);
2427                                         VecRotToQuat( upvec, (float)moffset[1]*-time_redraw*20, tmp_quat); /* Rotate about the relative up vec */
2428                                         QuatMul(G.vd->viewquat, G.vd->viewquat, tmp_quat);
2429                                         
2430                                         if (xlock) xlock = 2; /*check for rotation*/
2431                                         if (zlock) zlock = 2;
2432                                         xlock_momentum= 0.0;
2433                                 }
2434                                 
2435                                 /* rotate about the Y axis- look left/right */
2436                                 if (moffset[0]) {
2437                                         
2438                                         if (zlock) {
2439                                                 upvec[0]=0;
2440                                                 upvec[1]=0;
2441                                                 upvec[2]=1;
2442                                         } else {
2443                                                 upvec[0]=0;
2444                                                 upvec[1]=1;
2445                                                 upvec[2]=0;
2446                                                 Mat3MulVecfl(mat, upvec);
2447                                         }
2448                                                 
2449                                         VecRotToQuat( upvec, (float)moffset[0]*time_redraw*20, tmp_quat); /* Rotate about the relative up vec */
2450                                         QuatMul(G.vd->viewquat, G.vd->viewquat, tmp_quat);
2451                                         
2452                                         if (xlock) xlock = 2;/*check for rotation*/
2453                                         if (zlock) zlock = 2;
2454                                 }
2455                                 
2456                                 if (zlock==2) {
2457                                         upvec[0]=1;
2458                                         upvec[1]=0;
2459                                         upvec[2]=0;
2460                                         Mat3MulVecfl(mat, upvec);
2461
2462                                         /*make sure we have some z rolling*/
2463                                         if (fabs(upvec[2]) > 0.00001) {
2464                                                 roll= upvec[2]*5;
2465                                                 upvec[0]=0; /*rotate the view about this axis*/
2466                                                 upvec[1]=0;
2467                                                 upvec[2]=1;
2468                                                 
2469                                                 Mat3MulVecfl(mat, upvec);
2470                                                 VecRotToQuat( upvec, roll*time_redraw_clamped*zlock_momentum*0.1, tmp_quat); /* Rotate about the relative up vec */
2471                                                 QuatMul(G.vd->viewquat, G.vd->viewquat, tmp_quat);
2472                                                 
2473                                                 zlock_momentum += 0.05;
2474                                         } else {
2475                                                 zlock=1; /* dont check until the view rotates again */
2476                                                 zlock_momentum= 0.0;
2477                                         }
2478                                 }
2479                                 
2480                                 if (xlock==2 && moffset[1]==0) { /*only apply xcorrect when mouse isnt applying x rot*/
2481                                         upvec[0]=0;
2482                                         upvec[1]=0;
2483                                         upvec[2]=1;
2484                                         Mat3MulVecfl(mat, upvec);
2485                                         /*make sure we have some z rolling*/
2486                                         if (fabs(upvec[2]) > 0.00001) {
2487                                                 roll= upvec[2]*-5;
2488                                                 
2489                                                 upvec[0]=1; /*rotate the view about this axis*/
2490                                                 upvec[1]=0;
2491                                                 upvec[2]=0;
2492                                                 
2493                                                 Mat3MulVecfl(mat, upvec);
2494                                                 
2495                                                 VecRotToQuat( upvec, roll*time_redraw_clamped*xlock_momentum*0.1, tmp_quat); /* Rotate about the relative up vec */
2496                                                 QuatMul(G.vd->viewquat, G.vd->viewquat, tmp_quat);
2497                                                 
2498                                                 xlock_momentum += 0.05;
2499                                         } else {
2500                                                 xlock=1; /* see above */
2501                                                 xlock_momentum= 0.0;
2502                                         }
2503                                 }
2504
2505
2506                                 if (apply_rotation) {
2507                                         /* Normal operation */
2508                                         /* define dvec, view direction vector */
2509                                         dvec_tmp[0]= dvec_tmp[1]= dvec_tmp[2]= 0;
2510                                         /* move along the current axis */
2511                                         dvec_tmp[axis]= 1.0f;
2512                                         
2513                                         Mat3MulVecfl(mat, dvec_tmp);
2514                                         
2515                                         VecMulf(dvec_tmp, speed*time_redraw*0.25);
2516                                 }
2517                         }
2518                         
2519                         /* impose a directional lag */
2520                         dvec_lag = 1.0/(1+(time_redraw*5));
2521                         dvec[0] = dvec_tmp[0]*(1-dvec_lag) + dvec_old[0]*dvec_lag;
2522                         dvec[1] = dvec_tmp[1]*(1-dvec_lag) + dvec_old[1]*dvec_lag;
2523                         dvec[2] = dvec_tmp[2]*(1-dvec_lag) + dvec_old[2]*dvec_lag;
2524                         
2525                         
2526                         if (G.vd->persp==2) {
2527                                 if (G.vd->camera->protectflag & OB_LOCK_LOCX)
2528                                         dvec[0] = 0.0;
2529                                 if (G.vd->camera->protectflag & OB_LOCK_LOCY)
2530                                         dvec[1] = 0.0;
2531                                 if (G.vd->camera->protectflag & OB_LOCK_LOCZ)
2532                                         dvec[2] = 0.0;
2533                         }
2534                         
2535                         VecAddf(G.vd->ofs, G.vd->ofs, dvec);
2536                         if (zlock && xlock)
2537                                 headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X  on/Z on,   Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2538                         else if (zlock) 
2539                                 headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X off/Z on,   Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2540                         else if (xlock)
2541                                 headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X  on/Z off,  Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2542                         else
2543                                 headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X off/Z off,  Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2544                         
2545                         do_screenhandlers(G.curscreen); /* advance the next frame */
2546                         
2547                         /* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to teh view */
2548                         if (G.vd->persp==2) {
2549                                 G.vd->persp= 1; /*set this so setviewmatrixview3d uses the ofs and quat instead of the camera */
2550                                 setviewmatrixview3d();
2551                                 setcameratoview3d();
2552                                 G.vd->persp= 2;
2553                                 
2554                                 /* record the motion */
2555                                 if (G.flags & G_RECORDKEYS && (!playing_anim || cfra != G.scene->r.cfra)) {
2556                                         cfra = G.scene->r.cfra;
2557                                         
2558                                         if (xlock || zlock || moffset[0] || moffset[1]) {
2559                                                 insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_ROT_X);
2560                                                 insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_ROT_Y);
2561                                                 insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_ROT_Z);
2562                                         }
2563                                         if (speed) {
2564                                                 insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_LOC_X);
2565                                                 insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_LOC_Y);
2566                                                 insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_LOC_Z);
2567                                         }
2568                                 }
2569                         }
2570                         scrarea_do_windraw(curarea);
2571                         screen_swapbuffers();
2572                 } else 
2573                         /*were not redrawing but we need to update the time else the view will jump */
2574                         time_lastdraw= PIL_check_seconds_timer();
2575                 /* end drawing */
2576                 VECCOPY(dvec_old, dvec);
2577         }
2578         
2579         G.vd->dist= dist_backup;
2580         
2581         /* Revert to original view? */ 
2582         if (action == 2) { /* action == 2 means the user pressed Esc of RMB, and not to apply view to camera */
2583                 if (persp_backup==2) { /* a camera view */
2584                         G.vd->viewbut=1;
2585                         VECCOPY(G.vd->camera->loc, ofs_backup);
2586                         VECCOPY(G.vd->camera->rot, rot_backup);
2587                         DAG_object_flush_update(G.scene, G.vd->camera, OB_RECALC_OB);
2588                 } else {
2589                         /* Non Camera we need to reset the view back to the original location bacause the user canceled*/
2590                         QUATCOPY(G.vd->viewquat, rot_backup);
2591                         VECCOPY(G.vd->ofs, ofs_backup);
2592                         G.vd->persp= persp_backup;
2593                 }
2594         }
2595         else if (persp_backup==2) {     /* camera */
2596                 float mat3[3][3];
2597                 Mat3CpyMat4(mat3, G.vd->camera->obmat);
2598                 Mat3ToCompatibleEul(mat3, G.vd->camera->rot, rot_backup);
2599                 
2600                 DAG_object_flush_update(G.scene, G.vd->camera, OB_RECALC_OB);
2601                 
2602                 if (G.flags & G_RECORDKEYS) {
2603                         allqueue(REDRAWIPO, 0);
2604                         allspace(REMAKEIPO, 0);
2605                         allqueue(REDRAWNLA, 0);
2606                         allqueue(REDRAWTIME, 0);
2607                 }
2608         }
2609         else { /* not camera */
2610                 /* Apply the fly mode view */
2611                 /*restore the dist*/
2612                 upvec[0]= upvec[1]= 0;
2613                 upvec[2]=dist_backup; /*x and y are 0*/
2614                 Mat3CpyMat4(mat, G.vd->viewinv);
2615                 Mat3MulVecfl(mat, upvec);
2616                 VecAddf(G.vd->ofs, G.vd->ofs, upvec);
2617                 /*Done with correcting for the dist */
2618         }
2619         
2620         G.vd->flag2 &= ~V3D_FLYMODE;
2621         allqueue(REDRAWVIEW3D, 0);
2622         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT); /* not working at the moment not sure why */
2623 }
2624
2625 void view3d_edit_clipping(View3D *v3d)
2626 {
2627         
2628         if(v3d->flag & V3D_CLIPPING) {
2629                 v3d->flag &= ~V3D_CLIPPING;
2630                 scrarea_queue_winredraw(curarea);
2631                 if(v3d->clipbb) MEM_freeN(v3d->clipbb);
2632                 v3d->clipbb= NULL;
2633         }
2634         else {
2635                 rcti rect;
2636                 double mvmatrix[16];
2637                 double projmatrix[16];
2638                 double xs, ys, p[3];
2639                 GLint viewport[4];
2640                 short val;
2641                 
2642                 /* get border in window coords */
2643                 setlinestyle(2);
2644                 val= get_border(&rect, 3);
2645                 setlinestyle(0);
2646                 if(val==0) return;
2647                 
2648                 v3d->flag |= V3D_CLIPPING;
2649                 v3d->clipbb= MEM_mallocN(sizeof(BoundBox), "clipbb");
2650                 
2651                 /* convert border to 3d coordinates */
2652                 
2653                 /* Get the matrices needed for gluUnProject */
2654                 glGetIntegerv(GL_VIEWPORT, viewport);
2655                 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
2656                 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
2657
2658                 /* near zero floating point values can give issues with gluUnProject
2659                    in side view on some implementations */
2660                 if(fabs(mvmatrix[0]) < 1e-6) mvmatrix[0]= 0.0;
2661                 if(fabs(mvmatrix[5]) < 1e-6) mvmatrix[5]= 0.0;
2662                 
2663                 /* Set up viewport so that gluUnProject will give correct values */
2664                 viewport[0] = 0;
2665                 viewport[1] = 0;
2666                 
2667                 /* four clipping planes and bounding volume */
2668                 /* first do the bounding volume */
2669                 for(val=0; val<4; val++) {
2670                         
2671                         xs= (val==0||val==3)?rect.xmin:rect.xmax;
2672                         ys= (val==0||val==1)?rect.ymin:rect.ymax;
2673                         
2674                         gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
2675                         VECCOPY(v3d->clipbb->vec[val], p);
2676                         
2677                         gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
2678                         VECCOPY(v3d->clipbb->vec[4+val], p);
2679                 }
2680                 
2681                 /* then plane equations */
2682                 for(val=0; val<4; val++) {
2683                         
2684                         CalcNormFloat(v3d->clipbb->vec[val], v3d->clipbb->vec[val==3?0:val+1], v3d->clipbb->vec[val+4],
2685                                                   v3d->clip[val]); 
2686                         
2687                         v3d->clip[val][3]= - v3d->clip[val][0]*v3d->clipbb->vec[val][0] 
2688                                                            - v3d->clip[val][1]*v3d->clipbb->vec[val][1] 
2689                                                            - v3d->clip[val][2]*v3d->clipbb->vec[val][2];
2690                 }
2691         }
2692 }
2693