6dfdd3cf1c0f98999f48810777b7f5364dc62a32
[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         /* doesn't work fine for perspective */
2062         if(G.vd->persp==1)
2063                 return;
2064         
2065         val = get_border(&rect, 3); //box select input
2066         if(val)
2067         {
2068                 /* find the current window width and height */
2069                 vb[0] = G.vd->area->winx;
2070                 vb[1] = G.vd->area->winy;
2071                 
2072                 /* convert the drawn rectangle into 3d space */
2073                 initgrabz(-G.vd->ofs[0], -G.vd->ofs[1], -G.vd->ofs[2]);
2074                 window_to_3d(dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
2075                 
2076                 /* center the view to the center of the rectangle */
2077                 VecSubf(G.vd->ofs, G.vd->ofs, dvec);
2078                 
2079                 /* work out the ratios, so that everything selected fits when we zoom */
2080                 xscale = ((rect.xmax-rect.xmin)/vb[0]);
2081                 yscale = ((rect.ymax-rect.ymin)/vb[1]);
2082                 scale = (xscale >= yscale)?xscale:yscale;
2083                 
2084                 /* zoom in as required, or as far as we can go */
2085                 G.vd->dist = ((G.vd->dist*scale) >= 0.001*G.vd->grid)? G.vd->dist*scale:0.001*G.vd->grid;
2086         }
2087 }
2088
2089 void fly(void)
2090 {
2091         /*
2092         fly mode - Shift+F
2093         a fly loop where the user can move move the view as if they are flying
2094         */
2095         float speed=0.0, /* the speed the view is moving per redraw */
2096         mat[3][3], /* 3x3 copy of the view matrix so we can move allong the view axis */
2097         dvec[3]={0,0,0}, /* this is the direction thast added to the view offset per redraw */
2098         dvec_old[3]={0,0,0}, /* old for some lag */
2099         dvec_tmp[3]={0,0,0}, /* old for some lag */
2100         dvec_lag=0.0, /* old for some lag */
2101         
2102         /* Camera Uprighting variables */
2103         roll, /* similar to the angle between the camera's up and the Z-up, but its very rough so just roll*/
2104         upvec[3]={0,0,0}, /* stores the view's up vector */
2105         
2106         dist_backup, /* backup the views distance since we use a zero dist for fly mode */
2107         rot_backup[4], /* backup the views quat incase the user cancels flying in non camera mode */
2108         ofs_backup[3], /* backup the views offset incase the user cancels flying in non camera mode */
2109         moffset[2], /* mouse offset from the views center */
2110         tmp_quat[4], /* used for rotating the view */
2111         winxf, winyf, /* scale the mouse movement by this value - scales mouse movement to the view size */
2112         time_redraw, time_redraw_clamped; /*time how fast it takes for us to redraw, this is so simple scenes dont fly too fast */
2113         
2114         
2115         double time_current, time_lastdraw;
2116         
2117         short val, /* used for toets to see if a buttons pressed */
2118         cent_orig[2], /* view center */
2119         cent[2], /* view center modified */
2120         mval[2], /* mouse location */
2121         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 */
2122         xmargin, ymargin; /* x and y margin are define the safe area where the mouses movement wont rotate the view */
2123         unsigned short
2124         toets; /* for reading the event */
2125         unsigned char
2126         apply_rotation= 1, /* if the user presses shift they can look about without movinf the direction there looking*/
2127         axis= 2, /* Axis index to move allong by default Z to move allong the view */
2128         persp_backup, /* remember if were ortho or not, only used for restoring the view if it was a ortho view */
2129         pan_view=0; /* if true, pan the view instead of rotating */
2130         
2131         /* relative view axis locking - xlock, zlock
2132         0; disabled
2133         1; enabled but not checking because mouse hasnt moved outside the margin since locking was checked an not needed
2134            when the mouse moves, locking is set to 2 so checks are done.
2135         2; mouse moved and checking needed, if no view altering is donem its changed back to 1 */
2136         short xlock=0, zlock=0;
2137         float xlock_momentum=0.0f, zlock_momentum=0.0f; /* nicer dynamics */
2138         
2139         /* for recording */
2140         int playing_anim = has_screenhandler(G.curscreen, SCREEN_HANDLER_ANIM);
2141         int cfra = -1; /*so the first frame always has a key added */
2142         char *actname="";
2143         
2144         if(curarea->spacetype!=SPACE_VIEW3D) return;
2145                 
2146         if(G.vd->persp==2 && G.vd->camera->id.lib) {
2147                 error("Cannot fly a camera from an external library");
2148                 return;
2149         }
2150         
2151         if(G.vd->ob_centre) {
2152                 error("Cannot fly when the view is locked to an object");
2153                 return;
2154         }
2155         
2156         
2157         /* detect weather to start with Z locking */
2158         upvec[0]=1; upvec[1]=0; upvec[2]=0;
2159         Mat3CpyMat4(mat, G.vd->viewinv);
2160         Mat3MulVecfl(mat, upvec);
2161         if (fabs(upvec[2]) < 0.1)
2162                 zlock = 1;
2163         upvec[0]=0; upvec[1]=0; upvec[2]=0;
2164         
2165         persp_backup= G.vd->persp;
2166         dist_backup= G.vd->dist;
2167         if (G.vd->persp==2) { /* Camera */
2168                 if(G.vd->camera->constraints.first) {
2169                         error("Cannot fly an object with constraints");
2170                         return;
2171                 }
2172                 
2173                 /* store the origoinal camera loc and rot */
2174                 VECCOPY(ofs_backup, G.vd->camera->loc);
2175                 VECCOPY(rot_backup, G.vd->camera->rot);
2176                 
2177                 where_is_object(G.vd->camera);
2178                 VECCOPY(G.vd->ofs, G.vd->camera->obmat[3]);
2179                 VecMulf(G.vd->ofs, -1.0f); /*flip the vector*/
2180                 
2181                 G.vd->dist=0.0;
2182                 G.vd->viewbut=0;
2183                 
2184                 /* used for recording */
2185                 if(G.vd->camera->ipoflag & OB_ACTION_OB)
2186                         actname= "Object";
2187                 
2188         } else {
2189                 /* perspective or ortho */
2190                 if (G.vd->persp==0)
2191                         G.vd->persp= 1; /*if ortho projection, make perspective */
2192                 QUATCOPY(rot_backup, G.vd->viewquat);
2193                 VECCOPY(ofs_backup, G.vd->ofs);
2194                 G.vd->dist= 0.0;
2195                 
2196                 upvec[2]=dist_backup; /*x and y are 0*/
2197                 Mat3MulVecfl(mat, upvec);
2198                 VecSubf(G.vd->ofs, G.vd->ofs, upvec);
2199                 /*Done with correcting for the dist*/
2200         }
2201         
2202         /* the dist defines a vector that is infront of the offset
2203         to rotate the view about.
2204         this is no good for fly mode because we
2205         want to rotate about the viewers center.
2206         but to correct the dist removal we must
2207         alter offset so the view dosent jump. */
2208         
2209         xmargin= (short)((float)(curarea->winx)/20.0);
2210         ymargin= (short)((float)(curarea->winy)/20.0);
2211         
2212         cent_orig[0]= curarea->winrct.xmin+(curarea->winx)/2;
2213         cent_orig[1]= curarea->winrct.ymin+(curarea->winy)/2;
2214         
2215         warp_pointer(cent_orig[0], cent_orig[1]);
2216
2217         /* we have to rely on events to give proper mousecoords after a warp_pointer */
2218         mval[0]= cent[0]=  (curarea->winx)/2;
2219         mval[1]= cent[1]=  (curarea->winy)/2;
2220         /* window size minus margin - use this to get the mouse range for rotation */
2221         winxf= (float)(curarea->winx)-(xmargin*2);
2222         winyf= (float)(curarea->winy)-(ymargin*2); 
2223         
2224         
2225         time_lastdraw= PIL_check_seconds_timer();
2226         
2227         G.vd->flag2 |= V3D_FLYMODE; /* so we draw the corner margins */
2228         scrarea_do_windraw(curarea);
2229         screen_swapbuffers();
2230         
2231         while(action==0) { /* keep flying, no acton taken */
2232                 while(qtest()) {
2233                         toets= extern_qread(&val);
2234                         
2235                         if(val) {
2236                                 if(toets==MOUSEY) getmouseco_areawin(mval);
2237                                 else if(toets==ESCKEY || toets==RIGHTMOUSE) {
2238                                         action= 2; /* Canceled */
2239                                         break;
2240                                 } else if(toets==SPACEKEY || toets==LEFTMOUSE) {
2241                                         action= 1; /* Accepted */
2242                                         break;
2243                                 } else if(toets==PADPLUSKEY || toets==EQUALKEY || toets==WHEELUPMOUSE) {
2244                                         if (speed<0) speed=0;
2245                                         else speed+= G.vd->grid;
2246                                 } else if(toets==PADMINUS || toets==MINUSKEY || toets==WHEELDOWNMOUSE) {
2247                                         if (speed>0) speed=0;
2248                                         else speed-= G.vd->grid;
2249                                 
2250                                 } else if (toets==MIDDLEMOUSE) {
2251                                         /* make it so the camera direction dosent follow the view
2252                                         good for flying backwards! - Only when MMB is held */
2253                                         
2254                                         /*apply_rotation=0;*/
2255                                         pan_view= 1;
2256                                         
2257                                 /* impliment WASD keys */
2258                                 } else if(toets==WKEY) {
2259                                         if (speed<0) speed=-speed; /* flip speed rather then stopping, game like motion */
2260                                         else speed+= G.vd->grid; /* increse like mousewheel if were alredy moving in that difection*/
2261                                         axis= 2;
2262                                 } else if(toets==SKEY) { /*SAME as above but flipped */
2263                                         if (speed>0) speed=-speed;
2264                                         else speed-= G.vd->grid;
2265                                         axis= 2;
2266                                 
2267                                 } else if(toets==AKEY) {
2268                                         if (speed<0) speed=-speed;
2269                                         axis= 0;
2270                                 } else if(toets==DKEY) {
2271                                         if (speed>0) speed=-speed;
2272                                         axis= 0;
2273                                 } else if(toets==FKEY) {
2274                                         if (speed<0) speed=-speed;
2275                                         axis= 1;
2276                                 } else if(toets==RKEY) {
2277                                         if (speed>0) speed=-speed;
2278                                         axis= 1;
2279                                 
2280                                 /* axis locking */
2281                                 } else if(toets==XKEY) {
2282                                         if (xlock) xlock=0;
2283                                         else {
2284                                                 xlock = 2;
2285                                                 xlock_momentum = 0.0;
2286                                         }
2287                                 } else if(toets==ZKEY) {
2288                                         if (zlock) zlock=0;
2289                                         else {
2290                                                 zlock = 2;
2291                                                 zlock_momentum = 0.0;
2292                                         }
2293                                 }
2294                                 
2295                         } else {
2296                                 /* mouse buttons lifted */
2297                                 if (toets==MIDDLEMOUSE && pan_view) {
2298                                         /*apply_rotation=1;*/
2299                                         warp_pointer(cent_orig[0], cent_orig[1]);
2300                                         pan_view= 0;
2301                                 }
2302                         }
2303                 }
2304                 if(action != 0) break;
2305                 
2306                 moffset[0]= mval[0]-cent[0];
2307                 moffset[1]= mval[1]-cent[1];
2308                 
2309                 /* enforce a view margin */
2310                 if (moffset[0]>xmargin)         moffset[0]-=xmargin;
2311                 else if (moffset[0]<-xmargin)moffset[0]+=xmargin;
2312                 else                                    moffset[0]=0;
2313
2314                 if (moffset[1]>ymargin)         moffset[1]-=ymargin;
2315                 else if (moffset[1]<-ymargin)moffset[1]+=ymargin;
2316                 else                                    moffset[1]=0;
2317                 
2318                 /* scale the mouse offset so the distance the mouse moves isnt linear */
2319                 if (moffset[0]) {
2320                         moffset[0]= moffset[0]/winxf;
2321                         moffset[0]= moffset[0]*fabs(moffset[0]);
2322                 }
2323                 
2324                 if (moffset[1]) {
2325                         moffset[1]= moffset[1]/winyf;
2326                         moffset[1]= moffset[1]*fabs(moffset[1]);
2327                 }
2328                 
2329                 /* Should we redraw? */
2330                 if(speed!=0.0 || moffset[0] || moffset[1] || zlock || xlock || dvec[0] || dvec[1] || dvec[2] ) {
2331                         
2332                         time_current= PIL_check_seconds_timer();
2333                         time_redraw= (float)(time_current-time_lastdraw);
2334                         time_redraw_clamped= MIN2(0.05, time_redraw); /* clamt the redraw time to avoid jitter in roll correction */
2335                         time_lastdraw= time_current;
2336                         /*fprintf(stderr, "%f\n", time_redraw);*/ /* 0.002 is a small redraw 0.02 is larger */
2337                         
2338                         /* Scale the time to use shift to scale the speed down- just like
2339                         shift slows many other areas of blender down */
2340                         if (G.qual & LR_SHIFTKEY)
2341                                 speed= speed * (1-time_redraw_clamped);
2342                         
2343                         Mat3CpyMat4(mat, G.vd->viewinv);
2344                         
2345                         if (pan_view) {
2346                                 /* pan only */
2347                                 dvec_tmp[0]= -moffset[0];
2348                                 dvec_tmp[1]= -moffset[1];
2349                                 dvec_tmp[2]= 0;
2350                                 /* z axis can stay teh same, just keep costing */
2351                                 
2352                                 Mat3MulVecfl(mat, dvec_tmp);
2353                                 VecMulf(dvec_tmp, time_redraw*200.0 * G.vd->grid);
2354                                 
2355                         } else {
2356                                 /* rotate about the X axis- look up/down */
2357                                 if (moffset[1]) {
2358                                         upvec[0]=1;
2359                                         upvec[1]=0;
2360                                         upvec[2]=0;
2361                                         Mat3MulVecfl(mat, upvec);
2362                                         VecRotToQuat( upvec, (float)moffset[1]*-time_redraw*20, tmp_quat); /* Rotate about the relative up vec */
2363                                         QuatMul(G.vd->viewquat, G.vd->viewquat, tmp_quat);
2364                                         
2365                                         if (xlock) xlock = 2; /*check for rotation*/
2366                                         if (zlock) zlock = 2;
2367                                         xlock_momentum= 0.0;
2368                                 }
2369                                 
2370                                 /* rotate about the Y axis- look left/right */
2371                                 if (moffset[0]) {
2372                                         
2373                                         if (zlock) {
2374                                                 upvec[0]=0;
2375                                                 upvec[1]=0;
2376                                                 upvec[2]=1;
2377                                         } else {
2378                                                 upvec[0]=0;
2379                                                 upvec[1]=1;
2380                                                 upvec[2]=0;
2381                                                 Mat3MulVecfl(mat, upvec);
2382                                         }
2383                                                 
2384                                         VecRotToQuat( upvec, (float)moffset[0]*time_redraw*20, tmp_quat); /* Rotate about the relative up vec */
2385                                         QuatMul(G.vd->viewquat, G.vd->viewquat, tmp_quat);
2386                                         
2387                                         if (xlock) xlock = 2;/*check for rotation*/
2388                                         if (zlock) zlock = 2;
2389                                 }
2390                                 
2391                                 if (zlock==2) {
2392                                         upvec[0]=1;
2393                                         upvec[1]=0;
2394                                         upvec[2]=0;
2395                                         Mat3MulVecfl(mat, upvec);
2396
2397                                         /*make sure we have some z rolling*/
2398                                         if (fabs(upvec[2]) > 0.00001) {
2399                                                 roll= upvec[2]*5;
2400                                                 upvec[0]=0; /*rotate the view about this axis*/
2401                                                 upvec[1]=0;
2402                                                 upvec[2]=1;
2403                                                 
2404                                                 Mat3MulVecfl(mat, upvec);
2405                                                 VecRotToQuat( upvec, roll*time_redraw_clamped*zlock_momentum*0.1, tmp_quat); /* Rotate about the relative up vec */
2406                                                 QuatMul(G.vd->viewquat, G.vd->viewquat, tmp_quat);
2407                                                 
2408                                                 zlock_momentum += 0.05;
2409                                         } else {
2410                                                 zlock=1; /* dont check until the view rotates again */
2411                                                 zlock_momentum= 0.0;
2412                                         }
2413                                 }
2414                                 
2415                                 if (xlock==2 && moffset[1]==0) { /*only apply xcorrect when mouse isnt applying x rot*/
2416                                         upvec[0]=0;
2417                                         upvec[1]=0;
2418                                         upvec[2]=1;
2419                                         Mat3MulVecfl(mat, upvec);
2420                                         /*make sure we have some z rolling*/
2421                                         if (fabs(upvec[2]) > 0.00001) {
2422                                                 roll= upvec[2]*-5;
2423                                                 
2424                                                 upvec[0]=1; /*rotate the view about this axis*/
2425                                                 upvec[1]=0;
2426                                                 upvec[2]=0;
2427                                                 
2428                                                 Mat3MulVecfl(mat, upvec);
2429                                                 
2430                                                 VecRotToQuat( upvec, roll*time_redraw_clamped*xlock_momentum*0.1, tmp_quat); /* Rotate about the relative up vec */
2431                                                 QuatMul(G.vd->viewquat, G.vd->viewquat, tmp_quat);
2432                                                 
2433                                                 xlock_momentum += 0.05;
2434                                         } else {
2435                                                 xlock=1; /* see above */
2436                                                 xlock_momentum= 0.0;
2437                                         }
2438                                 }
2439
2440
2441                                 if (apply_rotation) {
2442                                         /* Normal operation */
2443                                         /* define dvec, view direction vector */
2444                                         dvec_tmp[0]= dvec_tmp[1]= dvec_tmp[2]= 0;
2445                                         /* move along the current axis */
2446                                         dvec_tmp[axis]= 1.0f;
2447                                         
2448                                         Mat3MulVecfl(mat, dvec_tmp);
2449                                         
2450                                         VecMulf(dvec_tmp, speed*time_redraw*0.5);
2451                                 }
2452                         }
2453                         
2454                         /* impose a directional lag */
2455                         dvec_lag = 1.0/(1+(time_redraw*5));
2456                         dvec[0] = dvec_tmp[0]*(1-dvec_lag) + dvec_old[0]*dvec_lag;
2457                         dvec[1] = dvec_tmp[1]*(1-dvec_lag) + dvec_old[1]*dvec_lag;
2458                         dvec[2] = dvec_tmp[2]*(1-dvec_lag) + dvec_old[2]*dvec_lag;
2459                         
2460                         
2461                         if (G.vd->persp==2) {
2462                                 if (G.vd->camera->protectflag & OB_LOCK_LOCX)
2463                                         dvec[0] = 0.0;
2464                                 if (G.vd->camera->protectflag & OB_LOCK_LOCY)
2465                                         dvec[1] = 0.0;
2466                                 if (G.vd->camera->protectflag & OB_LOCK_LOCZ)
2467                                         dvec[2] = 0.0;
2468                         }
2469                         
2470                         VecAddf(G.vd->ofs, G.vd->ofs, dvec);
2471                         if (zlock && xlock)
2472                                 headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X  on/Z on,   Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2473                         else if (zlock) 
2474                                 headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X off/Z on,   Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2475                         else if (xlock)
2476                                 headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X  on/Z off,  Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2477                         else
2478                                 headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X off/Z off,  Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2479                         
2480                         do_screenhandlers(G.curscreen); /* advance the next frame */
2481                         
2482                         /* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to teh view */
2483                         if (G.vd->persp==2) {
2484                                 G.vd->persp= 1; /*set this so setviewmatrixview3d uses the ofs and quat instead of the camera */
2485                                 setviewmatrixview3d();
2486                                 setcameratoview3d();
2487                                 G.vd->persp= 2;
2488                                 
2489                                 /* record the motion */
2490                                 if (G.flags & G_RECORDKEYS && (!playing_anim || cfra != G.scene->r.cfra)) {
2491                                         cfra = G.scene->r.cfra;
2492                                         
2493                                         if (xlock || zlock || moffset[0] || moffset[1]) {
2494                                                 insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_ROT_X);
2495                                                 insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_ROT_Y);
2496                                                 insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_ROT_Z);
2497                                         }
2498                                         if (speed) {
2499                                                 insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_LOC_X);
2500                                                 insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_LOC_Y);
2501                                                 insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_LOC_Z);
2502                                         }
2503                                 }
2504                         }
2505                         scrarea_do_windraw(curarea);
2506                         screen_swapbuffers();
2507                 } else 
2508                         /*were not redrawing but we need to update the time else the view will jump */
2509                         time_lastdraw= PIL_check_seconds_timer();
2510                 /* end drawing */
2511                 VECCOPY(dvec_old, dvec);
2512         }
2513         
2514         G.vd->dist= dist_backup;
2515         
2516         /* Revert to original view? */ 
2517         if (action == 2) { /* action == 2 means the user pressed Esc of RMB, and not to apply view to camera */
2518                 if (persp_backup==2) { /* a camera view */
2519                         G.vd->viewbut=1;
2520                         VECCOPY(G.vd->camera->loc, ofs_backup);
2521                         VECCOPY(G.vd->camera->rot, rot_backup);
2522                         DAG_object_flush_update(G.scene, G.vd->camera, OB_RECALC_OB);
2523                 } else {
2524                         /* Non Camera we need to reset the view back to the original location bacause the user canceled*/
2525                         QUATCOPY(G.vd->viewquat, rot_backup);
2526                         VECCOPY(G.vd->ofs, ofs_backup);
2527                         G.vd->persp= persp_backup;
2528                 }
2529         }
2530         else if (persp_backup==2) {     /* camera */
2531                 float mat3[3][3];
2532                 Mat3CpyMat4(mat3, G.vd->camera->obmat);
2533                 Mat3ToCompatibleEul(mat3, G.vd->camera->rot, rot_backup);
2534                 
2535                 DAG_object_flush_update(G.scene, G.vd->camera, OB_RECALC_OB);
2536                 
2537                 if (G.flags & G_RECORDKEYS) {
2538                         allqueue(REDRAWIPO, 0);
2539                         allspace(REMAKEIPO, 0);
2540                         allqueue(REDRAWNLA, 0);
2541                         allqueue(REDRAWTIME, 0);
2542                 }
2543         }
2544         else { /* not camera */
2545                 /* Apply the fly mode view */
2546                 /*restore the dist*/
2547                 upvec[0]= upvec[1]= 0;
2548                 upvec[2]=dist_backup; /*x and y are 0*/
2549                 Mat3CpyMat4(mat, G.vd->viewinv);
2550                 Mat3MulVecfl(mat, upvec);
2551                 VecAddf(G.vd->ofs, G.vd->ofs, upvec);
2552                 /*Done with correcting for the dist */
2553         }
2554         
2555         G.vd->flag2 &= ~V3D_FLYMODE;
2556         allqueue(REDRAWVIEW3D, 0);
2557         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT); /* not working at the moment not sure why */
2558 }
2559
2560 void view3d_edit_clipping(View3D *v3d)
2561 {
2562         
2563         if(v3d->flag & V3D_CLIPPING) {
2564                 v3d->flag &= ~V3D_CLIPPING;
2565                 scrarea_queue_winredraw(curarea);
2566                 if(v3d->clipbb) MEM_freeN(v3d->clipbb);
2567                 v3d->clipbb= NULL;
2568         }
2569         else {
2570                 rcti rect;
2571                 double mvmatrix[16];
2572                 double projmatrix[16];
2573                 double xs, ys, p[3];
2574                 GLint viewport[4];
2575                 short val;
2576                 
2577                 /* get border in window coords */
2578                 setlinestyle(2);
2579                 val= get_border(&rect, 3);
2580                 setlinestyle(0);
2581                 if(val==0) return;
2582                 
2583                 v3d->flag |= V3D_CLIPPING;
2584                 v3d->clipbb= MEM_mallocN(sizeof(BoundBox), "clipbb");
2585                 
2586                 /* convert border to 3d coordinates */
2587                 
2588                 /* Get the matrices needed for gluUnProject */
2589                 glGetIntegerv(GL_VIEWPORT, viewport);
2590                 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
2591                 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
2592
2593                 /* near zero floating point values can give issues with gluUnProject
2594                    in side view on some implementations */
2595                 if(fabs(mvmatrix[0]) < 1e-6) mvmatrix[0]= 0.0;
2596                 if(fabs(mvmatrix[5]) < 1e-6) mvmatrix[5]= 0.0;
2597                 
2598                 /* Set up viewport so that gluUnProject will give correct values */
2599                 viewport[0] = 0;
2600                 viewport[1] = 0;
2601                 
2602                 /* four clipping planes and bounding volume */
2603                 /* first do the bounding volume */
2604                 for(val=0; val<4; val++) {
2605                         
2606                         xs= (val==0||val==3)?rect.xmin:rect.xmax;
2607                         ys= (val==0||val==1)?rect.ymin:rect.ymax;
2608                         
2609                         gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
2610                         VECCOPY(v3d->clipbb->vec[val], p);
2611                         
2612                         gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
2613                         VECCOPY(v3d->clipbb->vec[4+val], p);
2614                 }
2615                 
2616                 /* then plane equations */
2617                 for(val=0; val<4; val++) {
2618                         
2619                         CalcNormFloat(v3d->clipbb->vec[val], v3d->clipbb->vec[val==3?0:val+1], v3d->clipbb->vec[val+4],
2620                                                   v3d->clip[val]); 
2621                         
2622                         v3d->clip[val][3]= - v3d->clip[val][0]*v3d->clipbb->vec[val][0] 
2623                                                            - v3d->clip[val][1]*v3d->clipbb->vec[val][1] 
2624                                                            - v3d->clip[val][2]*v3d->clipbb->vec[val][2];
2625                 }
2626         }
2627 }
2628