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