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