first workable version on Os X
[blender.git] / source / blender / src / view.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  * Trackball math (in calctrackballvec())  Copyright (C) Silicon Graphics, Inc.
27  *
28  * The Original Code is: all of this file.
29  *
30  * Contributor(s): none yet.
31  *
32  * ***** END GPL/BL DUAL LICENSE BLOCK *****
33  */
34
35 #include <math.h>
36 #include <string.h>
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #ifdef WIN32
43 #include <io.h>
44 #else
45 #include <unistd.h>
46 #endif   
47
48 #include "MEM_guardedalloc.h"
49
50 #include "BLI_blenlib.h"
51 #include "BLI_arithb.h"
52
53 #include "DNA_action_types.h"
54 #include "DNA_armature_types.h"
55 #include "DNA_camera_types.h"
56 #include "DNA_lamp_types.h"
57 #include "DNA_object_types.h"
58 #include "DNA_screen_types.h"
59 #include "DNA_scene_types.h"
60 #include "DNA_space_types.h"
61 #include "DNA_userdef_types.h"
62 #include "DNA_view3d_types.h"
63
64 #include "BKE_action.h"
65 #include "BKE_anim.h"
66 #include "BKE_global.h"
67 #include "BKE_main.h"
68 #include "BKE_object.h"
69 #include "BKE_utildefines.h"
70
71 #include "BIF_gl.h"
72 #include "BIF_space.h"
73 #include "BIF_mywindow.h"
74 #include "BIF_previewrender.h"
75 #include "BIF_retopo.h"
76 #include "BIF_screen.h"
77 #include "BIF_toolbox.h"
78
79 #include "BSE_view.h"
80 #include "BSE_edit.h"           /* For countall */
81 #include "BSE_drawview.h"       /* For inner_play_anim_loop */
82
83 #include "BDR_drawobject.h"     /* For draw_object */
84 #include "BDR_editface.h"       /* For minmax_tface */
85 #include "BDR_sculptmode.h"
86
87 #include "mydevice.h"
88 #include "blendef.h"
89
90 #include "PIL_time.h" /* smoothview */
91 #include <float.h>
92
93 #define TRACKBALLSIZE  (1.1)
94 #define BL_NEAR_CLIP 0.001
95
96
97 /* local prototypes ----------*/
98 void setcameratoview3d(void); /* windows.c & toets.c */
99
100 void persp_general(int a)
101 {
102         /* for all window types, not 3D */
103         
104         if(a== 0) {
105                 glPushMatrix();
106                 glMatrixMode(GL_PROJECTION);
107                 glPushMatrix();
108                 glMatrixMode(GL_MODELVIEW);
109
110                 myortho2(-0.375, ((float)(curarea->winx))-0.375, -0.375, ((float)(curarea->winy))-0.375);
111                 glLoadIdentity();
112         }
113         else if(a== 1) {
114                 glMatrixMode(GL_PROJECTION);
115                 glPopMatrix();
116                 glMatrixMode(GL_MODELVIEW);
117                 glPopMatrix();
118         }
119 }
120
121 void persp(int a)
122 {
123         /* only 3D windows */
124
125         if(curarea->spacetype!=SPACE_VIEW3D) persp_general(a);
126         else if(a == PERSP_STORE) {             // only store
127                 glMatrixMode(GL_PROJECTION);
128                 mygetmatrix(G.vd->winmat1);     
129                 glMatrixMode(GL_MODELVIEW);
130                 mygetmatrix(G.vd->viewmat1); 
131         }
132         else if(a== PERSP_WIN) {                // only set
133                 myortho2(-0.375, (float)(curarea->winx)-0.375, -0.375, (float)(curarea->winy)-0.375);
134                 glLoadIdentity();
135         }
136         else if(a== PERSP_VIEW) {
137                 glMatrixMode(GL_PROJECTION);
138                 myloadmatrix(G.vd->winmat1); // put back
139                 Mat4CpyMat4(curarea->winmat, G.vd->winmat1); // to be sure? 
140                 glMatrixMode(GL_MODELVIEW); 
141                 myloadmatrix(G.vd->viewmat); // put back
142                 
143         }
144 }
145
146
147 void initgrabz(float x, float y, float z)
148 {
149         if(G.vd==NULL) return;
150         G.vd->zfac= G.vd->persmat[0][3]*x+ G.vd->persmat[1][3]*y+ G.vd->persmat[2][3]*z+ G.vd->persmat[3][3];
151
152         /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that 
153          * (accounting for near zero values)
154          * */
155         if (G.vd->zfac < 1.e-6f && G.vd->zfac > -1.e-6f) G.vd->zfac = 1.0f;
156 }
157
158 void window_to_3d(float *vec, short mx, short my)
159 {
160         /* always call initgrabz */
161         float dx, dy;
162         
163         dx= 2.0f*mx*G.vd->zfac/curarea->winx;
164         dy= 2.0f*my*G.vd->zfac/curarea->winy;
165         
166         vec[0]= (G.vd->persinv[0][0]*dx + G.vd->persinv[1][0]*dy);
167         vec[1]= (G.vd->persinv[0][1]*dx + G.vd->persinv[1][1]*dy);
168         vec[2]= (G.vd->persinv[0][2]*dx + G.vd->persinv[1][2]*dy);
169 }
170
171 void project_short(float *vec, short *adr)      /* clips */
172 {
173         float fx, fy, vec4[4];
174
175         adr[0]= IS_CLIPPED;
176         
177         if(G.vd->flag & V3D_CLIPPING) {
178                 if(view3d_test_clipping(G.vd, vec))
179                         return;
180         }
181
182         VECCOPY(vec4, vec);
183         vec4[3]= 1.0;
184         Mat4MulVec4fl(G.vd->persmat, vec4);
185         
186         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
187                 fx= (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
188                 
189                 if( fx>0 && fx<curarea->winx) {
190                 
191                         fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
192                         
193                         if(fy>0.0 && fy< (float)curarea->winy) {
194                                 adr[0]= floor(fx); 
195                                 adr[1]= floor(fy);
196                         }
197                 }
198         }
199 }
200
201 void project_int(float *vec, int *adr)
202 {
203         float fx, fy, vec4[4];
204
205         adr[0]= 2140000000.0f;
206         VECCOPY(vec4, vec);
207         vec4[3]= 1.0;
208         
209         Mat4MulVec4fl(G.vd->persmat, vec4);
210
211         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
212                 fx= (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
213                 
214                 if( fx>-2140000000.0f && fx<2140000000.0f) {
215                         fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
216                         
217                         if(fy>-2140000000.0f && fy<2140000000.0f) {
218                                 adr[0]= floor(fx); 
219                                 adr[1]= floor(fy);
220                         }
221                 }
222         }
223 }
224
225 void project_short_noclip(float *vec, short *adr)
226 {
227         float fx, fy, vec4[4];
228
229         adr[0]= IS_CLIPPED;
230         VECCOPY(vec4, vec);
231         vec4[3]= 1.0;
232         
233         Mat4MulVec4fl(G.vd->persmat, vec4);
234
235         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
236                 fx= (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
237                 
238                 if( fx>-32700 && fx<32700) {
239                 
240                         fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
241                         
242                         if(fy>-32700.0 && fy<32700.0) {
243                                 adr[0]= floor(fx); 
244                                 adr[1]= floor(fy);
245                         }
246                 }
247         }
248 }
249
250 void project_float(float *vec, float *adr)
251 {
252         float vec4[4];
253         
254         adr[0]= IS_CLIPPED;
255         VECCOPY(vec4, vec);
256         vec4[3]= 1.0;
257         
258         Mat4MulVec4fl(G.vd->persmat, vec4);
259
260         if( vec4[3]>BL_NEAR_CLIP ) {
261                 adr[0]= (curarea->winx/2.0)+(curarea->winx/2.0)*vec4[0]/vec4[3];        
262                 adr[1]= (curarea->winy/2.0)+(curarea->winy/2.0)*vec4[1]/vec4[3];
263         }
264 }
265
266 void view3d_get_object_project_mat(ScrArea *area, Object *ob, float pmat[4][4], float vmat[4][4])
267 {
268         if (area->spacetype!=SPACE_VIEW3D || !area->spacedata.first) {
269                 Mat4One(pmat);
270                 Mat4One(vmat);
271         } else {
272                 View3D *vd = area->spacedata.first;
273
274                 Mat4MulMat4(vmat, ob->obmat, vd->viewmat);
275                 Mat4MulMat4(pmat, vmat, vd->winmat1);
276                 Mat4CpyMat4(vmat, ob->obmat);
277         }
278 }
279
280 /* projectmat brings it to window coords, wmat to rotated world space */
281 void view3d_project_short_clip(ScrArea *area, float *vec, short *adr, float projmat[4][4], float wmat[4][4])
282 {
283         View3D *v3d= area->spacedata.first;
284         float fx, fy, vec4[4];
285
286         adr[0]= IS_CLIPPED;
287         
288         /* clipplanes in eye space */
289         if(v3d->flag & V3D_CLIPPING) {
290                 VECCOPY(vec4, vec);
291                 Mat4MulVecfl(wmat, vec4);
292                 if(view3d_test_clipping(v3d, vec4))
293                         return;
294         }
295         
296         VECCOPY(vec4, vec);
297         vec4[3]= 1.0;
298         
299         Mat4MulVec4fl(projmat, vec4);
300         
301         /* clipplanes in window space */
302         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
303                 fx= (area->winx/2)*(1 + vec4[0]/vec4[3]);
304                 
305                 if( fx>0 && fx<area->winx) {
306                 
307                         fy= (area->winy/2)*(1 + vec4[1]/vec4[3]);
308                         
309                         if(fy>0.0 && fy< (float)area->winy) {
310                                 adr[0]= floor(fx); 
311                                 adr[1]= floor(fy);
312                         }
313                 }
314         }
315 }
316
317 void view3d_project_short_noclip(ScrArea *area, float *vec, short *adr, float mat[4][4])
318 {
319         float fx, fy, vec4[4];
320
321         adr[0]= IS_CLIPPED;
322         
323         VECCOPY(vec4, vec);
324         vec4[3]= 1.0;
325         
326         Mat4MulVec4fl(mat, vec4);
327
328         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
329                 fx= (area->winx/2)*(1 + vec4[0]/vec4[3]);
330                 
331                 if( fx>-32700 && fx<32700) {
332                 
333                         fy= (area->winy/2)*(1 + vec4[1]/vec4[3]);
334                         
335                         if(fy>-32700.0 && fy<32700.0) {
336                                 adr[0]= floor(fx); 
337                                 adr[1]= floor(fy);
338                         }
339                 }
340         }
341 }
342
343 void view3d_project_float(ScrArea *area, float *vec, float *adr, float mat[4][4])
344 {
345         float vec4[4];
346         
347         adr[0]= IS_CLIPPED;
348         VECCOPY(vec4, vec);
349         vec4[3]= 1.0;
350         
351         Mat4MulVec4fl(mat, vec4);
352
353         if( vec4[3]>FLT_EPSILON ) {
354                 adr[0] = (area->winx/2.0)+(area->winx/2.0)*vec4[0]/vec4[3];     
355                 adr[1] = (area->winy/2.0)+(area->winy/2.0)*vec4[1]/vec4[3];
356         } else {
357                 adr[0] = adr[1] = 0.0;
358         }
359 }
360
361 int boundbox_clip(float obmat[][4], BoundBox *bb)
362 {
363         /* return 1: draw */
364         
365         float mat[4][4];
366         float vec[4], min, max;
367         int a, flag= -1, fl;
368         
369         if(bb==NULL) return 1;
370         if(bb->flag & OB_BB_DISABLED) return 1;
371         
372         Mat4MulMat4(mat, obmat, G.vd->persmat);
373
374         for(a=0; a<8; a++) {
375                 VECCOPY(vec, bb->vec[a]);
376                 vec[3]= 1.0;
377                 Mat4MulVec4fl(mat, vec);
378                 max= vec[3];
379                 min= -vec[3];
380
381                 fl= 0;
382                 if(vec[0] < min) fl+= 1;
383                 if(vec[0] > max) fl+= 2;
384                 if(vec[1] < min) fl+= 4;
385                 if(vec[1] > max) fl+= 8;
386                 if(vec[2] < min) fl+= 16;
387                 if(vec[2] > max) fl+= 32;
388                 
389                 flag &= fl;
390                 if(flag==0) return 1;
391         }
392
393         return 0;
394
395 }
396
397 void fdrawline(float x1, float y1, float x2, float y2)
398 {
399         float v[2];
400
401         glBegin(GL_LINE_STRIP);
402         v[0] = x1; v[1] = y1;
403         glVertex2fv(v);
404         v[0] = x2; v[1] = y2;
405         glVertex2fv(v);
406         glEnd();
407 }
408
409 void fdrawbox(float x1, float y1, float x2, float y2)
410 {
411         float v[2];
412
413         glBegin(GL_LINE_STRIP);
414
415         v[0] = x1; v[1] = y1;
416         glVertex2fv(v);
417         v[0] = x1; v[1] = y2;
418         glVertex2fv(v);
419         v[0] = x2; v[1] = y2;
420         glVertex2fv(v);
421         v[0] = x2; v[1] = y1;
422         glVertex2fv(v);
423         v[0] = x1; v[1] = y1;
424         glVertex2fv(v);
425
426         glEnd();
427 }
428
429 void sdrawline(short x1, short y1, short x2, short y2)
430 {
431         short v[2];
432
433         glBegin(GL_LINE_STRIP);
434         v[0] = x1; v[1] = y1;
435         glVertex2sv(v);
436         v[0] = x2; v[1] = y2;
437         glVertex2sv(v);
438         glEnd();
439 }
440
441 void sdrawbox(short x1, short y1, short x2, short y2)
442 {
443         short v[2];
444
445         glBegin(GL_LINE_STRIP);
446
447         v[0] = x1; v[1] = y1;
448         glVertex2sv(v);
449         v[0] = x1; v[1] = y2;
450         glVertex2sv(v);
451         v[0] = x2; v[1] = y2;
452         glVertex2sv(v);
453         v[0] = x2; v[1] = y1;
454         glVertex2sv(v);
455         v[0] = x1; v[1] = y1;
456         glVertex2sv(v);
457
458         glEnd();
459 }
460
461 /* the central math in this function was copied from trackball.cpp, sample code from the 
462    Developers Toolbox series by SGI. */
463
464 /* trackball: better one than a full spherical solution */
465
466 void calctrackballvecfirst(rcti *area, short *mval, float *vec)
467 {
468         float x, y, radius, d, z, t;
469         
470         radius= TRACKBALLSIZE;
471         
472         /* normalize x and y */
473         x= (area->xmax + area->xmin)/2 -mval[0];
474         x/= (float)((area->xmax - area->xmin)/2);
475         y= (area->ymax + area->ymin)/2 -mval[1];
476         y/= (float)((area->ymax - area->ymin)/2);
477         
478         d = sqrt(x*x + y*y);
479         if (d < radius*M_SQRT1_2)       /* Inside sphere */
480                 z = sqrt(radius*radius - d*d);
481         else
482         {                       /* On hyperbola */
483                 t = radius / M_SQRT2;
484                 z = t*t / d;
485         }
486
487         vec[0]= x;
488         vec[1]= y;
489         vec[2]= -z;             /* yah yah! */
490
491         if( fabs(vec[2])>fabs(vec[1]) && fabs(vec[2])>fabs(vec[0]) ) {
492                 vec[0]= 0.0;
493                 vec[1]= 0.0;
494                 if(vec[2]>0.0) vec[2]= 1.0; else vec[2]= -1.0;
495         }
496         else if( fabs(vec[1])>fabs(vec[0]) && fabs(vec[1])>fabs(vec[2]) ) {
497                 vec[0]= 0.0;
498                 vec[2]= 0.0;
499                 if(vec[1]>0.0) vec[1]= 1.0; else vec[1]= -1.0;
500         }
501         else  {
502                 vec[1]= 0.0;
503                 vec[2]= 0.0;
504                 if(vec[0]>0.0) vec[0]= 1.0; else vec[0]= -1.0;
505         }
506 }
507
508 void calctrackballvec(rcti *area, short *mval, float *vec)
509 {
510         float x, y, radius, d, z, t;
511         
512         radius= TRACKBALLSIZE;
513         
514         /* x en y normalizeren */
515         x= (area->xmax + area->xmin)/2 -mval[0];
516         x/= (float)((area->xmax - area->xmin)/4);
517         y= (area->ymax + area->ymin)/2 -mval[1];
518         y/= (float)((area->ymax - area->ymin)/2);
519         
520         d = sqrt(x*x + y*y);
521         if (d < radius*M_SQRT1_2)       /* Inside sphere */
522                 z = sqrt(radius*radius - d*d);
523         else
524         {                       /* On hyperbola */
525                 t = radius / M_SQRT2;
526                 z = t*t / d;
527         }
528
529         vec[0]= x;
530         vec[1]= y;
531         vec[2]= -z;             /* yah yah! */
532
533 }
534
535 void viewmove(int mode)
536 {
537         Object *ob = OBACT;
538         float firstvec[3], newvec[3], dvec[3];
539         float reverse, oldquat[4], q1[4], si, phi, dist0;
540         float ofs[3], obofs[3]= {0.0f, 0.0f, 0.0f};
541         int firsttime=1;
542         short mvalball[2], mval[2], mvalo[2];
543         short use_sel = 0;
544         short preview3d_event= 1;
545         
546         /* 3D window may not be defined */
547         if( !G.vd ) {
548                 fprintf( stderr, "G.vd == NULL in viewmove()\n" );
549                 return;
550         }
551
552         /* sometimes this routine is called from headerbuttons */
553
554         areawinset(curarea->win);
555         
556         initgrabz(-G.vd->ofs[0], -G.vd->ofs[1], -G.vd->ofs[2]);
557         
558         QUATCOPY(oldquat, G.vd->viewquat);
559         
560         getmouseco_sc(mvalo);           /* work with screen coordinates because of trackball function */
561         mvalball[0]= mvalo[0];                  /* needed for turntable to work */
562         mvalball[1]= mvalo[1];
563         dist0= G.vd->dist;
564         
565         calctrackballvec(&curarea->winrct, mvalo, firstvec);
566
567         /* cumultime(0); */
568
569         if(!G.obedit && (G.f & G_SCULPTMODE) && ob && G.vd->pivot_last) {
570                 use_sel= 1;
571                 VecCopyf(ofs, G.vd->ofs);
572
573                 VecCopyf(obofs,&sculpt_session()->pivot.x);
574                 Mat4MulVecfl(ob->obmat, obofs);
575                 obofs[0]= -obofs[0];
576                 obofs[1]= -obofs[1];
577                 obofs[2]= -obofs[2];
578         }
579         else if (ob && (U.uiflag & USER_ORBIT_SELECTION)) {
580                 use_sel = 1;
581                 
582                 VECCOPY(ofs, G.vd->ofs);
583                 
584                 /* If there's no selection, obofs is unmodified, so <0,0,0> */
585                 calculateTransformCenter(V3D_CENTROID, obofs);
586                 VecMulf(obofs, -1.0f);
587         }
588         else
589                 ofs[0] = ofs[1] = ofs[2] = 0.0f;
590
591         reverse= 1.0f;
592         if (G.vd->persmat[2][1] < 0.0f)
593                 reverse= -1.0f;
594
595         while(TRUE) {
596                 getmouseco_sc(mval);
597                 
598                 // if playanim = alt+A, screenhandlers are for animated UI, python, etc
599                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || (G.f & G_PLAYANIM) || do_screenhandlers(G.curscreen)) {
600                         
601                         if(firsttime) {
602                                 
603                                 firsttime= 0;
604                                 /* are we translating, rotating or zooming? */
605                                 if(mode==0) {
606                                         if(G.vd->view!=0) scrarea_queue_headredraw(curarea);    /*for button */
607                                         G.vd->view= 0;
608                                 }
609                                 if(G.vd->persp==2 && mode!=1 && G.vd->camera) {
610                                         G.vd->persp= 1;
611                                         scrarea_do_windraw(curarea);
612                                         scrarea_queue_headredraw(curarea);
613                                 }
614                         }
615
616                         if(mode==0) {   /* view rotate */
617                                 if (U.uiflag & USER_AUTOPERSP) G.vd->persp= 1;
618
619                                 if (U.flag & USER_TRACKBALL) mvalball[0]= mval[0];
620                                 mvalball[1]= mval[1];
621                                 
622                                 calctrackballvec(&curarea->winrct, mvalball, newvec);
623                                 
624                                 VecSubf(dvec, newvec, firstvec);
625                                 
626                                 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
627                                 si/= (2.0*TRACKBALLSIZE);
628                         
629                                 if (U.flag & USER_TRACKBALL) {
630                                         Crossf(q1+1, firstvec, newvec);
631         
632                                         Normalize(q1+1);
633         
634                                         /* Allow for rotation beyond the interval
635                                          * [-pi, pi] */
636                                         while (si > 1.0)
637                                                 si -= 2.0;
638                 
639                                         /* This relation is used instead of
640                                          * phi = asin(si) so that the angle
641                                          * of rotation is linearly proportional
642                                          * to the distance that the mouse is
643                                          * dragged. */
644                                         phi = si * M_PI / 2.0;
645                 
646                                         si= sin(phi);
647                                         q1[0]= cos(phi);
648                                         q1[1]*= si;
649                                         q1[2]*= si;
650                                         q1[3]*= si;     
651                                         QuatMul(G.vd->viewquat, q1, oldquat);
652
653                                         if (use_sel) {
654                                                 /* compute the post multiplication quat, to rotate the offset correctly */
655                                                 QUATCOPY(q1, oldquat);
656                                                 QuatConj(q1);
657                                                 QuatMul(q1, q1, G.vd->viewquat);
658
659                                                 QuatConj(q1); /* conj == inv for unit quat */
660                                                 VECCOPY(G.vd->ofs, ofs);
661                                                 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
662                                                 QuatMulVecf(q1, G.vd->ofs);
663                                                 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
664                                         }
665                                 } else {
666                                         /* New turntable view code by John Aughey */
667
668                                         float m[3][3];
669                                         float m_inv[3][3];
670                                         float xvec[3] = {1,0,0};
671                                         /* Sensitivity will control how fast the viewport rotates.  0.0035 was
672                                            obtained experimentally by looking at viewport rotation sensitivities
673                                            on other modeling programs. */
674                                         /* Perhaps this should be a configurable user parameter. */
675                                         const float sensitivity = 0.0035;
676
677                                         /* Get the 3x3 matrix and its inverse from the quaternion */
678                                         QuatToMat3(G.vd->viewquat, m);
679                                         Mat3Inv(m_inv,m);
680
681                                         /* Determine the direction of the x vector (for rotating up and down) */
682                                         /* This can likely be compuated directly from the quaternion. */
683                                         Mat3MulVecfl(m_inv,xvec);
684
685                                         /* Perform the up/down rotation */
686                                         phi = sensitivity * -(mval[1] - mvalo[1]);
687                                         si = sin(phi);
688                                         q1[0] = cos(phi);
689                                         q1[1] = si * xvec[0];
690                                         q1[2] = si * xvec[1];
691                                         q1[3] = si * xvec[2];
692                                         QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
693
694                                         if (use_sel) {
695                                                 QuatConj(q1); /* conj == inv for unit quat */
696                                                 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
697                                                 QuatMulVecf(q1, G.vd->ofs);
698                                                 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
699                                         }
700
701                                         /* Perform the orbital rotation */
702                                         phi = sensitivity * reverse * (mval[0] - mvalo[0]);
703                                         q1[0] = cos(phi);
704                                         q1[1] = q1[2] = 0.0;
705                                         q1[3] = sin(phi);
706                                         QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
707
708                                         if (use_sel) {
709                                                 QuatConj(q1);
710                                                 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
711                                                 QuatMulVecf(q1, G.vd->ofs);
712                                                 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
713                                         }
714                                 }
715                         }
716                         else if(mode==1) {      /* translate */
717                                 if(G.vd->persp==2) {
718                                         float max= (float)MAX2(curarea->winx, curarea->winy);
719
720                                         G.vd->camdx += (mvalo[0]-mval[0])/(max);
721                                         G.vd->camdy += (mvalo[1]-mval[1])/(max);
722                                         CLAMP(G.vd->camdx, -1.0f, 1.0f);
723                                         CLAMP(G.vd->camdy, -1.0f, 1.0f);
724                                         preview3d_event= 0;
725                                 }
726                                 else {
727                                         window_to_3d(dvec, mval[0]-mvalo[0], mval[1]-mvalo[1]);
728                                         VecAddf(G.vd->ofs, G.vd->ofs, dvec);
729                                 }
730                         }
731                         else if(mode==2) {
732                                 if(U.viewzoom==USER_ZOOM_CONT) {
733                                         // oldstyle zoom
734                                         G.vd->dist*= 1.0+(float)(mvalo[0]-mval[0]+mvalo[1]-mval[1])/1000.0;
735                                 }
736                                 else if(U.viewzoom==USER_ZOOM_SCALE) {
737                                         int ctr[2], len1, len2;
738                                         // method which zooms based on how far you move the mouse
739                                         
740                                         ctr[0] = (curarea->winrct.xmax + curarea->winrct.xmin)/2;
741                                         ctr[1] = (curarea->winrct.ymax + curarea->winrct.ymin)/2;
742                                         
743                                         len1 = (int)sqrt((ctr[0] - mval[0])*(ctr[0] - mval[0]) + (ctr[1] - mval[1])*(ctr[1] - mval[1])) + 5;
744                                         len2 = (int)sqrt((ctr[0] - mvalo[0])*(ctr[0] - mvalo[0]) + (ctr[1] - mvalo[1])*(ctr[1] - mvalo[1])) + 5;
745                                         
746                                         G.vd->dist= dist0 * ((float)len2/len1);
747                                 }
748                                 else {  /* USER_ZOOM_DOLLY */
749                                         float len1 = (curarea->winrct.ymax - mval[1]) + 5;
750                                         float len2 = (curarea->winrct.ymax - mvalo[1]) + 5;
751                                         
752                                         G.vd->dist= dist0 * (2.0*((len2/len1)-1.0) + 1.0);
753                                 }
754                                 
755                                 /* these limits are in toets.c too */
756                                 if(G.vd->dist<0.001*G.vd->grid) G.vd->dist= 0.001*G.vd->grid;
757                                 if(G.vd->dist>10.0*G.vd->far) G.vd->dist=10.0*G.vd->far;
758                                 
759                                 mval[1]= mvalo[1]; /* preserve first value */
760                                 mval[0]= mvalo[0];
761                                 
762                                 if(G.vd->persp==0 || G.vd->persp==2) preview3d_event= 0;
763                         }
764                         
765                         mvalo[0]= mval[0];
766                         mvalo[1]= mval[1];
767
768                         if(G.f & G_PLAYANIM) inner_play_anim_loop(0, 0);
769                         if(G.f & G_SIMULATION) break;
770
771                         /* If in retopo paint mode, update lines */
772                         if(retopo_mesh_paint_check() && G.vd->retopo_view_data) {
773                                 G.vd->retopo_view_data->queue_matrix_update= 1;
774                                 retopo_paint_view_update(G.vd);
775                         }
776
777                         scrarea_do_windraw(curarea);
778                         screen_swapbuffers();
779                 }
780                 else {
781                         short val;
782                         unsigned short event;
783                         /* we need to empty the queue... when you do this very long it overflows */
784                         while(qtest()) event= extern_qread(&val);
785                         
786                         BIF_wait_for_statechange();
787                 }
788                 
789                 /* this in the end, otherwise get_mbut does not work on a PC... */
790                 if( !(get_mbut() & (L_MOUSE|M_MOUSE))) break;
791         }
792
793         if(G.vd->depths) G.vd->depths->damaged= 1;
794         retopo_queue_updates(G.vd);
795         allqueue(REDRAWVIEW3D, 0);
796
797         if(preview3d_event) 
798                 BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
799         else
800                 BIF_view3d_previewrender_signal(curarea, PR_PROJECTED);
801
802 }
803
804
805
806
807
808 void viewmoveNDOF(int mode)
809 {
810     static double prevTime = 0.0;
811
812     int i;
813     float fval[7];
814     float dvec[3];
815     float sbadjust = 1.0f;
816     float len;
817     double now, frametime;
818         short use_sel = 0;
819         Object *ob = OBACT;
820     float m[3][3];
821     float m_inv[3][3];
822     float xvec[3] = {1,0,0};
823     float phi, si;
824     float q1[4];
825     float obofs[3];
826     float reverse;
827     float diff[4];
828     float d, curareaX, curareaY;
829
830 //printf("passing here \n");
831
832     /* Sensitivity will control how fast the view rotates.  The value was
833      * obtained experimentally by tweaking until the author didn't get dizzy watching.
834      * Perhaps this should be a configurable user parameter. 
835      */
836     float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
837     const float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
838     const float zsens = 0.1f;   /* zoom sensitivity */
839
840     const float minZoom = -30.0f;
841     const float maxZoom = 300.0f;
842
843         if (G.obedit==NULL && ob && !(ob->flag & OB_POSEMODE)) {
844                 use_sel = 1;
845         }
846
847     /*----------------------------------------------------
848          * sometimes this routine is called from headerbuttons
849      * viewmove needs to refresh the screen
850      */
851         areawinset(curarea->win);
852
853     /*----------------------------------------------------
854      * record how much time has passed. clamp at 10 Hz
855      * pretend the previous frame occured at the clamped time 
856      */
857 //    now = PIL_check_seconds_timer();
858  //   frametime = (now - prevTime);
859  //   if (frametime > 0.1f){        /* if more than 1/10s */
860  //       frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
861 //    }
862 //    prevTime = now;
863  //   sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
864
865     /* fetch the current state of the ndof device */
866     getndof(fval);
867    //         printf(" motion command %f %f %f %f %f %f %f \n", fval[0], fval[1], fval[2],
868    //                                                            fval[3], fval[4], fval[5], fval[6]);
869
870     /* set object offset */
871         if (ob) {
872                 obofs[0] = -ob->obmat[3][0];
873                 obofs[1] = -ob->obmat[3][1];
874                 obofs[2] = -ob->obmat[3][2];
875         }
876         else {
877                 VECCOPY(obofs, G.vd->ofs);
878         }
879
880     /* calc an adjustment based on distance from camera */
881     if (ob) {
882         VecSubf(diff, obofs, G.vd->ofs);
883         d = VecLength(diff);
884     }
885     else {
886         d = 1.0f;
887     }
888     reverse = (G.vd->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
889
890     /*----------------------------------------------------
891      * ndof device pan 
892      */
893     psens *= 1.0f + d;
894     curareaX = sbadjust * psens * fval[0];
895     curareaY = sbadjust * psens * fval[1];
896     dvec[0] = curareaX * G.vd->persinv[0][0] + curareaY * G.vd->persinv[1][0];
897     dvec[1] = curareaX * G.vd->persinv[0][1] + curareaY * G.vd->persinv[1][1];
898     dvec[2] = curareaX * G.vd->persinv[0][2] + curareaY * G.vd->persinv[1][2];
899     VecAddf(G.vd->ofs, G.vd->ofs, dvec);
900
901     /*----------------------------------------------------
902      * ndof device dolly 
903      */
904     len = zsens * sbadjust * fval[2];
905
906     if (G.vd->persp==2) {
907         if(G.vd->persp==2) {
908             G.vd->camzoom+= 10.0f * -len;
909         }
910         if (G.vd->camzoom < minZoom) G.vd->camzoom = minZoom;
911         else if (G.vd->camzoom > maxZoom) G.vd->camzoom = maxZoom;
912     }
913     else if ((G.vd->dist> 0.001*G.vd->grid) && (G.vd->dist<10.0*G.vd->far)) {
914         G.vd->dist*=(1.0 + len);
915     }
916
917
918     /*----------------------------------------------------
919      * ndof device turntable
920      * derived from the turntable code in viewmove
921      */
922
923     /* Get the 3x3 matrix and its inverse from the quaternion */
924     QuatToMat3(G.vd->viewquat, m);
925     Mat3Inv(m_inv,m);
926
927     /* Determine the direction of the x vector (for rotating up and down) */
928     /* This can likely be compuated directly from the quaternion. */
929     Mat3MulVecfl(m_inv,xvec);
930
931     /* Perform the up/down rotation */
932     phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
933     si = sin(phi);
934     q1[0] = cos(phi);
935     q1[1] = si * xvec[0];
936     q1[2] = si * xvec[1];
937     q1[3] = si * xvec[2];
938     QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
939
940     if (use_sel) {
941         QuatConj(q1); /* conj == inv for unit quat */
942         VecSubf(G.vd->ofs, G.vd->ofs, obofs);
943         QuatMulVecf(q1, G.vd->ofs);
944         VecAddf(G.vd->ofs, G.vd->ofs, obofs);
945     }
946
947     /* Perform the orbital rotation */
948     phi = sbadjust * rsens * reverse * fval[4];     /* twist the knob, y axis */
949     q1[0] = cos(phi);
950     q1[1] = q1[2] = 0.0;
951     q1[3] = sin(phi);
952     QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
953
954     if (use_sel) {
955         QuatConj(q1);
956         VecSubf(G.vd->ofs, G.vd->ofs, obofs);
957         QuatMulVecf(q1, G.vd->ofs);
958         VecAddf(G.vd->ofs, G.vd->ofs, obofs);
959     }
960
961     /*----------------------------------------------------
962      * refresh the screen
963      */
964     scrarea_do_windraw(curarea);
965     screen_swapbuffers();
966 }
967
968
969
970
971 /* Gets the lens and clipping values from a camera of lamp type object */
972 void object_view_settings(Object *ob, float *lens, float *clipsta, float *clipend)
973 {       
974         if (!ob) return;
975         
976         if(ob->type==OB_LAMP ) {
977                 Lamp *la = ob->data;
978                 if (lens) {
979                         float x1, fac;
980                         fac= cos( M_PI*la->spotsize/360.0);
981                         x1= saacos(fac);
982                         *lens= 16.0*fac/sin(x1);
983                 }
984                 if (clipsta)    *clipsta= la->clipsta;
985                 if (clipend)    *clipend= la->clipend;
986         }
987         else if(ob->type==OB_CAMERA) {
988                 Camera *cam= ob->data;
989                 if (lens)               *lens= cam->lens;
990                 if (clipsta)    *clipsta= cam->clipsta;
991                 if (clipend)    *clipend= cam->clipend;
992         }
993 }
994
995
996 int get_view3d_viewplane(int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
997 {
998         Camera *cam=NULL;
999         float lens, fac, x1, y1, x2, y2;
1000         float winx= (float)winxi, winy= (float)winyi;
1001         int orth= 0;
1002         
1003         lens= G.vd->lens;       
1004         
1005         *clipsta= G.vd->near;
1006         *clipend= G.vd->far;
1007
1008 /*      
1009  * Cant use this since we need the fac and x1 values set
1010  * if(G.vd->persp==2)
1011                 object_view_settings(G.vd->camera, &lens, &(*clipsta), &(*clipend));*/
1012         
1013         if(G.vd->persp==2) {
1014                 if(G.vd->camera) {
1015                         if(G.vd->camera->type==OB_LAMP ) {
1016                                 Lamp *la;
1017                                 
1018                                 la= G.vd->camera->data;
1019                                 fac= cos( M_PI*la->spotsize/360.0);
1020                                 
1021                                 x1= saacos(fac);
1022                                 lens= 16.0*fac/sin(x1);
1023                 
1024                                 *clipsta= la->clipsta;
1025                                 *clipend= la->clipend;
1026                         }
1027                         else if(G.vd->camera->type==OB_CAMERA) {
1028                                 cam= G.vd->camera->data;
1029                                 lens= cam->lens;
1030                                 *clipsta= cam->clipsta;
1031                                 *clipend= cam->clipend;
1032                         }
1033                 }
1034         }
1035         
1036         if(G.vd->persp==0) {
1037                 if(winx>winy) x1= -G.vd->dist;
1038                 else x1= -winx*G.vd->dist/winy;
1039                 x2= -x1;
1040
1041                 if(winx>winy) y1= -winy*G.vd->dist/winx;
1042                 else y1= -G.vd->dist;
1043                 y2= -y1;
1044                 
1045                 *clipend *= 0.5;        // otherwise too extreme low zbuffer quality
1046                 *clipsta= - *clipend;
1047                 orth= 1;
1048         }
1049         else {
1050                 /* fac for zoom, also used for camdx */
1051                 if(G.vd->persp==2) {
1052                         fac= (1.41421+( (float)G.vd->camzoom )/50.0);
1053                         fac*= fac;
1054                 }
1055                 else fac= 2.0;
1056                 
1057                 /* viewplane size depends... */
1058                 if(cam && cam->type==CAM_ORTHO) {
1059                         /* ortho_scale == 1 means exact 1 to 1 mapping */
1060                         float dfac= 2.0*cam->ortho_scale/fac;
1061                         
1062                         if(winx>winy) x1= -dfac;
1063                         else x1= -winx*dfac/winy;
1064                         x2= -x1;
1065                         
1066                         if(winx>winy) y1= -winy*dfac/winx;
1067                         else y1= -dfac;
1068                         y2= -y1;
1069                         orth= 1;
1070                 }
1071                 else {
1072                         float dfac;
1073                         
1074                         if(winx>winy) dfac= 64.0/(fac*winx*lens);
1075                         else dfac= 64.0/(fac*winy*lens);
1076                         
1077                         x1= - *clipsta * winx*dfac;
1078                         x2= -x1;
1079                         y1= - *clipsta * winy*dfac;
1080                         y2= -y1;
1081                         orth= 0;
1082                 }
1083                 /* cam view offset */
1084                 if(cam) {
1085                         float dx= 0.5*fac*G.vd->camdx*(x2-x1);
1086                         float dy= 0.5*fac*G.vd->camdy*(y2-y1);
1087                         x1+= dx;
1088                         x2+= dx;
1089                         y1+= dy;
1090                         y2+= dy;
1091                 }
1092         }
1093
1094         if(pixsize) {
1095                 float viewfac;
1096
1097                 if(orth) {
1098                         viewfac= (winx >= winy)? winx: winy;
1099                         *pixsize= 1.0f/viewfac;
1100                 }
1101                 else {
1102                         viewfac= (((winx >= winy)? winx: winy)*lens)/32.0;
1103                         *pixsize= *clipsta/viewfac;
1104                 }
1105         }
1106         
1107         viewplane->xmin= x1;
1108         viewplane->ymin= y1;
1109         viewplane->xmax= x2;
1110         viewplane->ymax= y2;
1111         
1112         return orth;
1113 }
1114
1115 /* important to not set windows active in here, can be renderwin for example */
1116 void setwinmatrixview3d(int winx, int winy, rctf *rect)         /* rect: for picking */
1117 {
1118         rctf viewplane;
1119         float clipsta, clipend, x1, y1, x2, y2;
1120         int orth;
1121         
1122         orth= get_view3d_viewplane(winx, winy, &viewplane, &clipsta, &clipend, NULL);
1123 //      printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
1124         x1= viewplane.xmin;
1125         y1= viewplane.ymin;
1126         x2= viewplane.xmax;
1127         y2= viewplane.ymax;
1128         
1129         if(rect) {              /* picking */
1130                 rect->xmin/= (float)curarea->winx;
1131                 rect->xmin= x1+rect->xmin*(x2-x1);
1132                 rect->ymin/= (float)curarea->winy;
1133                 rect->ymin= y1+rect->ymin*(y2-y1);
1134                 rect->xmax/= (float)curarea->winx;
1135                 rect->xmax= x1+rect->xmax*(x2-x1);
1136                 rect->ymax/= (float)curarea->winy;
1137                 rect->ymax= y1+rect->ymax*(y2-y1);
1138                 
1139                 if(orth) myortho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
1140                 else mywindow(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
1141                 
1142         }
1143         else {
1144                 if(orth) myortho(x1, x2, y1, y2, clipsta, clipend);
1145                 else mywindow(x1, x2, y1, y2, clipsta, clipend);
1146         }
1147
1148         /* not sure what this was for? (ton) */
1149         glMatrixMode(GL_PROJECTION);
1150         mygetmatrix(curarea->winmat);
1151         glMatrixMode(GL_MODELVIEW);
1152 }
1153
1154 void obmat_to_viewmat(Object *ob, short smooth)
1155 {
1156         float bmat[4][4];
1157         float tmat[3][3];
1158
1159         Mat4CpyMat4(bmat, ob->obmat);
1160         Mat4Ortho(bmat);
1161         Mat4Invert(G.vd->viewmat, bmat);
1162         
1163         /* view quat calculation, needed for add object */
1164         Mat3CpyMat4(tmat, G.vd->viewmat);
1165         if (smooth) {
1166                 float new_quat[4];
1167                 if (G.vd->persp==2 && G.vd->camera) {
1168                         /* were from a camera view */
1169                         
1170                         float orig_ofs[3];
1171                         float orig_dist= G.vd->dist;
1172                         float orig_lens= G.vd->lens;
1173                         VECCOPY(orig_ofs, G.vd->ofs);
1174                         
1175                         /* Switch from camera view */
1176                         Mat3ToQuat(tmat, new_quat);
1177                         
1178                         G.vd->persp=1;
1179                         G.vd->dist= 0.0;
1180                         
1181                         view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
1182                         smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
1183                         
1184                         G.vd->persp=2; /* just to be polite, not needed */
1185                         
1186                 } else {
1187                         Mat3ToQuat(tmat, new_quat);
1188                         smooth_view(G.vd, NULL, new_quat, NULL, NULL);
1189                 }
1190         } else {
1191                 Mat3ToQuat(tmat, G.vd->viewquat);
1192         }
1193 }
1194
1195 /* dont set windows active in in here, is used by renderwin too */
1196 void setviewmatrixview3d()
1197 {
1198         Camera *cam;
1199
1200         if(G.vd->persp>=2) {        /* obs/camera */
1201                 if(G.vd->camera) {
1202                         
1203                         where_is_object(G.vd->camera);  
1204                         obmat_to_viewmat(G.vd->camera, 0);
1205                         
1206                         if(G.vd->camera->type==OB_CAMERA) {
1207                                 cam= G.vd->camera->data;
1208                                 //if(cam->type==CAM_ORTHO) G.vd->viewmat[3][2]*= 100.0;
1209                         }
1210                 }
1211                 else {
1212                         QuatToMat4(G.vd->viewquat, G.vd->viewmat);
1213                         G.vd->viewmat[3][2]-= G.vd->dist;
1214                 }
1215         }
1216         else {
1217                 
1218                 QuatToMat4(G.vd->viewquat, G.vd->viewmat);
1219                 if(G.vd->persp==1) G.vd->viewmat[3][2]-= G.vd->dist;
1220                 if(G.vd->ob_centre) {
1221                         Object *ob= G.vd->ob_centre;
1222                         float vec[3];
1223                         
1224                         VECCOPY(vec, ob->obmat[3]);
1225                         if(ob->type==OB_ARMATURE && G.vd->ob_centre_bone[0]) {
1226                                 bPoseChannel *pchan= get_pose_channel(ob->pose, G.vd->ob_centre_bone);
1227                                 if(pchan) {
1228                                         VECCOPY(vec, pchan->pose_mat[3]);
1229                                         Mat4MulVecfl(ob->obmat, vec);
1230                                 }
1231                         }
1232                         i_translate(-vec[0], -vec[1], -vec[2], G.vd->viewmat);
1233                 }
1234                 else i_translate(G.vd->ofs[0], G.vd->ofs[1], G.vd->ofs[2], G.vd->viewmat);
1235         }
1236 }
1237
1238 void setcameratoview3d(void)
1239 {
1240         Object *ob;
1241         float dvec[3];
1242
1243         ob= G.vd->camera;
1244         dvec[0]= G.vd->dist*G.vd->viewinv[2][0];
1245         dvec[1]= G.vd->dist*G.vd->viewinv[2][1];
1246         dvec[2]= G.vd->dist*G.vd->viewinv[2][2];                                        
1247         VECCOPY(ob->loc, dvec);
1248         VecSubf(ob->loc, ob->loc, G.vd->ofs);
1249         G.vd->viewquat[0]= -G.vd->viewquat[0];
1250         if (ob->transflag & OB_QUAT) {
1251                 QUATCOPY(ob->quat, G.vd->viewquat);
1252         } else {
1253                 QuatToEul(G.vd->viewquat, ob->rot);
1254         }
1255         G.vd->viewquat[0]= -G.vd->viewquat[0];
1256 }
1257
1258 /* IGLuint-> GLuint*/
1259 /* Warning: be sure to account for a negative return value
1260  *   This is an error, "Too many objects in select buffer"
1261  *   and no action should be taken (can crash blender) if this happens
1262  */
1263 short  view3d_opengl_select(unsigned int *buffer, unsigned int bufsize, short x1, short y1, short x2, short y2)
1264 {
1265         rctf rect;
1266         short mval[2], code, hits;
1267
1268         G.f |= G_PICKSEL;
1269         
1270         if(x1==0 && x2==0 && y1==0 && y2==0) {
1271                 getmouseco_areawin(mval);
1272                 rect.xmin= mval[0]-12;  // seems to be default value for bones only now
1273                 rect.xmax= mval[0]+12;
1274                 rect.ymin= mval[1]-12;
1275                 rect.ymax= mval[1]+12;
1276         }
1277         else {
1278                 rect.xmin= x1;
1279                 rect.xmax= x2;
1280                 rect.ymin= y1;
1281                 rect.ymax= y2;
1282         }
1283         /* get rid of overlay button matrix */
1284         persp(PERSP_VIEW);
1285         setwinmatrixview3d(curarea->winx, curarea->winy, &rect);
1286         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
1287         
1288         if(G.vd->drawtype > OB_WIRE) {
1289                 G.vd->zbuf= TRUE;
1290                 glEnable(GL_DEPTH_TEST);
1291         }
1292
1293         if(G.vd->flag & V3D_CLIPPING)
1294                 view3d_set_clipping(G.vd);
1295         
1296         glSelectBuffer( bufsize, (GLuint *)buffer);
1297         glRenderMode(GL_SELECT);
1298         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1299         glPushName(-1);
1300         code= 1;
1301         
1302         if(G.obedit && G.obedit->type==OB_MBALL) {
1303                 draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1304         }
1305         else if ((G.obedit && G.obedit->type==OB_ARMATURE)) {
1306                 draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1307         }
1308         else {
1309                 Base *base;
1310                 
1311                 G.vd->xray= TRUE;       // otherwise it postpones drawing
1312                 for(base= G.scene->base.first; base; base= base->next) {
1313                         if(base->lay & G.vd->lay) {
1314                                 
1315                                 if (base->object->restrictflag & OB_RESTRICT_SELECT)
1316                                         base->selcol= 0;
1317                                 else {
1318                                         base->selcol= code;
1319                                         glLoadName(code);
1320                                         draw_object(base, DRAW_PICKING|DRAW_CONSTCOLOR);
1321                                         
1322                                         /* we draw group-duplicators for selection too */
1323                                         if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1324                                                 ListBase *lb;
1325                                                 DupliObject *dob;
1326                                                 Base tbase;
1327                                                 
1328                                                 tbase.flag= OB_FROMDUPLI;
1329                                                 lb= object_duplilist(G.scene, base->object);
1330                                                 
1331                                                 for(dob= lb->first; dob; dob= dob->next) {
1332                                                         tbase.object= dob->ob;
1333                                                         Mat4CpyMat4(dob->ob->obmat, dob->mat);
1334                                                         
1335                                                         draw_object(&tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1336                                                         
1337                                                         Mat4CpyMat4(dob->ob->obmat, dob->omat);
1338                                                 }
1339                                                 free_object_duplilist(lb);
1340                                         }
1341                                         code++;
1342                                 }                               
1343                         }
1344                 }
1345                 G.vd->xray= FALSE;      // restore
1346         }
1347         
1348         glPopName();    /* see above (pushname) */
1349         hits= glRenderMode(GL_RENDER);
1350
1351         G.f &= ~G_PICKSEL;
1352         setwinmatrixview3d(curarea->winx, curarea->winy, NULL);
1353         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
1354         
1355         if(G.vd->drawtype > OB_WIRE) {
1356                 G.vd->zbuf= 0;
1357                 glDisable(GL_DEPTH_TEST);
1358         }
1359         persp(PERSP_WIN);
1360         
1361         if(G.vd->flag & V3D_CLIPPING)
1362                 view3d_clr_clipping();
1363         
1364         if(hits<0) error("Too many objects in select buffer");
1365         
1366         return hits;
1367 }
1368
1369 float *give_cursor()
1370 {
1371         if(G.vd && G.vd->localview) return G.vd->cursor;
1372         else return G.scene->cursor;
1373 }
1374
1375 unsigned int free_localbit()
1376 {
1377         unsigned int lay;
1378         ScrArea *sa;
1379         bScreen *sc;
1380         
1381         lay= 0;
1382         
1383         /* sometimes we loose a localview: when an area is closed */
1384         /* check all areas: which localviews are in use? */
1385         sc= G.main->screen.first;
1386         while(sc) {
1387                 sa= sc->areabase.first;
1388                 while(sa) {
1389                         SpaceLink *sl= sa->spacedata.first;
1390                         while(sl) {
1391                                 if(sl->spacetype==SPACE_VIEW3D) {
1392                                         View3D *v3d= (View3D*) sl;
1393                                         lay |= v3d->lay;
1394                                 }
1395                                 sl= sl->next;
1396                         }
1397                         sa= sa->next;
1398                 }
1399                 sc= sc->id.next;
1400         }
1401         
1402         if( (lay & 0x01000000)==0) return 0x01000000;
1403         if( (lay & 0x02000000)==0) return 0x02000000;
1404         if( (lay & 0x04000000)==0) return 0x04000000;
1405         if( (lay & 0x08000000)==0) return 0x08000000;
1406         if( (lay & 0x10000000)==0) return 0x10000000;
1407         if( (lay & 0x20000000)==0) return 0x20000000;
1408         if( (lay & 0x40000000)==0) return 0x40000000;
1409         if( (lay & 0x80000000)==0) return 0x80000000;
1410         
1411         return 0;
1412 }
1413
1414
1415 void initlocalview()
1416 {
1417         Base *base;
1418         float size = 0.0, min[3], max[3], afm[3];
1419         unsigned int locallay;
1420         int ok=0;
1421
1422         if(G.vd->localvd) return;
1423
1424         min[0]= min[1]= min[2]= 1.0e10;
1425         max[0]= max[1]= max[2]= -1.0e10;
1426
1427         locallay= free_localbit();
1428
1429         if(locallay==0) {
1430                 error("Sorry,  no more than 8 localviews");
1431                 ok= 0;
1432         }
1433         else {
1434                 if(G.obedit) {
1435                         minmax_object(G.obedit, min, max);
1436                         
1437                         ok= 1;
1438                 
1439                         BASACT->lay |= locallay;
1440                         G.obedit->lay= BASACT->lay;
1441                 }
1442                 else {
1443                         base= FIRSTBASE;
1444                         while(base) {
1445                                 if TESTBASE(base)  {
1446                                         minmax_object(base->object, min, max);
1447                                         base->lay |= locallay;
1448                                         base->object->lay= base->lay;
1449                                         ok= 1;
1450                                 }
1451                                 base= base->next;
1452                         }
1453                 }
1454                 
1455                 afm[0]= (max[0]-min[0]);
1456                 afm[1]= (max[1]-min[1]);
1457                 afm[2]= (max[2]-min[2]);
1458                 size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1459                 if(size<=0.01) size= 0.01;
1460         }
1461         
1462         if(ok) {
1463                 G.vd->localvd= MEM_mallocN(sizeof(View3D), "localview");
1464                 memcpy(G.vd->localvd, G.vd, sizeof(View3D));
1465
1466                 G.vd->ofs[0]= -(min[0]+max[0])/2.0;
1467                 G.vd->ofs[1]= -(min[1]+max[1])/2.0;
1468                 G.vd->ofs[2]= -(min[2]+max[2])/2.0;
1469
1470                 G.vd->dist= size;
1471
1472                 // correction for window aspect ratio
1473                 if(curarea->winy>2 && curarea->winx>2) {
1474                         size= (float)curarea->winx/(float)curarea->winy;
1475                         if(size<1.0) size= 1.0/size;
1476                         G.vd->dist*= size;
1477                 }
1478                 
1479                 if (G.vd->persp>1) G.vd->persp= 1;
1480                 if (G.vd->near> 0.1) G.vd->near= 0.1;
1481                 
1482                 G.vd->cursor[0]= -G.vd->ofs[0];
1483                 G.vd->cursor[1]= -G.vd->ofs[1];
1484                 G.vd->cursor[2]= -G.vd->ofs[2];
1485
1486                 G.vd->lay= locallay;
1487                 
1488                 countall();
1489                 scrarea_queue_winredraw(curarea);
1490         }
1491         else {
1492                 /* clear flags */ 
1493                 base= FIRSTBASE;
1494                 while(base) {
1495                         if( base->lay & locallay ) {
1496                                 base->lay-= locallay;
1497                                 if(base->lay==0) base->lay= G.vd->layact;
1498                                 if(base->object != G.obedit) base->flag |= SELECT;
1499                                 base->object->lay= base->lay;
1500                         }
1501                         base= base->next;
1502                 }
1503                 scrarea_queue_headredraw(curarea);
1504                 
1505                 G.vd->localview= 0;
1506         }
1507         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1508 }
1509
1510 void centerview()       /* like a localview without local! */
1511 {
1512         Object *ob= OBACT;
1513         float size, min[3], max[3], afm[3];
1514         int ok=0;
1515         
1516         /* SMOOTHVIEW */
1517         float new_ofs[3];
1518         float new_dist;
1519         
1520         
1521         min[0]= min[1]= min[2]= 1.0e10;
1522         max[0]= max[1]= max[2]= -1.0e10;
1523
1524         if (G.f & G_WEIGHTPAINT) {
1525                 /* hardcoded exception, we look for the one selected armature */
1526                 /* this is weak code this way, we should make a generic active/selection callback interface once... */
1527                 Base *base;
1528                 for(base=FIRSTBASE; base; base= base->next) {
1529                         if(TESTBASELIB(base)) {
1530                                 if(base->object->type==OB_ARMATURE)
1531                                         if(base->object->flag & OB_POSEMODE)
1532                                                 break;
1533                         }
1534                 }
1535                 if(base)
1536                         ob= base->object;
1537         }
1538         
1539         
1540         if(G.obedit) {
1541                 ok = minmax_verts(min, max);    /* only selected */
1542         }
1543         else if(ob && (ob->flag & OB_POSEMODE)) {
1544                 if(ob->pose) {
1545                         bArmature *arm= ob->data;
1546                         bPoseChannel *pchan;
1547                         float vec[3];
1548                         
1549                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
1550                                 if(pchan->bone->flag & BONE_SELECTED) {
1551                                         if(pchan->bone->layer & arm->layer) {
1552                                                 ok= 1;
1553                                                 VECCOPY(vec, pchan->pose_head);
1554                                                 Mat4MulVecfl(ob->obmat, vec);
1555                                                 DO_MINMAX(vec, min, max);
1556                                                 VECCOPY(vec, pchan->pose_tail);
1557                                                 Mat4MulVecfl(ob->obmat, vec);
1558                                                 DO_MINMAX(vec, min, max);
1559                                         }
1560                                 }
1561                         }
1562                 }
1563         }
1564         else if (G.f & G_FACESELECT) {
1565                 ok= minmax_tface(min, max);
1566         }
1567         else {
1568                 Base *base= FIRSTBASE;
1569                 while(base) {
1570                         if TESTBASE(base)  {
1571                                 minmax_object(base->object, min, max);
1572                                 /* account for duplis */
1573                                 minmax_object_duplis(base->object, min, max);
1574                                 
1575                                 ok= 1;
1576                         }
1577                         base= base->next;
1578                 }
1579         }
1580         
1581         if(ok==0) return;
1582         
1583         afm[0]= (max[0]-min[0]);
1584         afm[1]= (max[1]-min[1]);
1585         afm[2]= (max[2]-min[2]);
1586         size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1587         
1588         if(size <= G.vd->near*1.5) size= G.vd->near*1.5;
1589         
1590         new_ofs[0]= -(min[0]+max[0])/2.0;
1591         new_ofs[1]= -(min[1]+max[1])/2.0;
1592         new_ofs[2]= -(min[2]+max[2])/2.0;
1593         
1594         new_dist = size;
1595
1596         /* correction for window aspect ratio */
1597         if(curarea->winy>2 && curarea->winx>2) {
1598                 size= (float)curarea->winx/(float)curarea->winy;
1599                 if(size<1.0) size= 1.0/size;
1600                 new_dist*= size;
1601         }
1602         
1603         G.vd->cursor[0]= -new_ofs[0];
1604         G.vd->cursor[1]= -new_ofs[1];
1605         G.vd->cursor[2]= -new_ofs[2];
1606         
1607         if (G.vd->persp==2 && G.vd->camera) {
1608                 float orig_lens= G.vd->lens;
1609                 
1610                 G.vd->persp=1;
1611                 G.vd->dist= 0.0;
1612                 view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
1613                 smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
1614         } else {
1615                 if(G.vd->persp>=2)
1616                         G.vd->persp= 1;
1617                 
1618                 smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
1619         }
1620         scrarea_queue_winredraw(curarea);
1621         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1622
1623 }
1624
1625
1626 void restore_localviewdata(View3D *vd)
1627 {
1628         if(vd->localvd==0) return;
1629         
1630         VECCOPY(vd->ofs, vd->localvd->ofs);
1631         vd->dist= vd->localvd->dist;
1632         vd->persp= vd->localvd->persp;
1633         vd->view= vd->localvd->view;
1634         vd->near= vd->localvd->near;
1635         vd->far= vd->localvd->far;
1636         vd->lay= vd->localvd->lay;
1637         vd->layact= vd->localvd->layact;
1638         vd->drawtype= vd->localvd->drawtype;
1639         vd->camera= vd->localvd->camera;
1640         QUATCOPY(vd->viewquat, vd->localvd->viewquat);
1641         
1642 }
1643
1644 void endlocalview(ScrArea *sa)
1645 {
1646         View3D *v3d;
1647         struct Base *base;
1648         unsigned int locallay;
1649         
1650         if(sa->spacetype!=SPACE_VIEW3D) return;
1651         v3d= sa->spacedata.first;
1652         
1653         if(v3d->localvd) {
1654                 
1655                 locallay= v3d->lay & 0xFF000000;
1656                 
1657                 restore_localviewdata(v3d);
1658                 
1659                 MEM_freeN(v3d->localvd);
1660                 v3d->localvd= 0;
1661                 v3d->localview= 0;
1662
1663                 /* for when in other window the layers have changed */
1664                 if(v3d->scenelock) v3d->lay= G.scene->lay;
1665                 
1666                 base= FIRSTBASE;
1667                 while(base) {
1668                         if( base->lay & locallay ) {
1669                                 base->lay-= locallay;
1670                                 if(base->lay==0) base->lay= v3d->layact;
1671                                 if(base->object != G.obedit) {
1672                                         base->flag |= SELECT;
1673                                         base->object->flag |= SELECT;
1674                                 }
1675                                 base->object->lay= base->lay;
1676                         }
1677                         base= base->next;
1678                 }
1679
1680                 countall();
1681                 allqueue(REDRAWVIEW3D, 0);      /* because of select */
1682                 allqueue(REDRAWOOPS, 0);        /* because of select */
1683                 BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1684         } 
1685 }
1686
1687 void view3d_home(int center)
1688 {
1689         Base *base;
1690         float size, min[3], max[3], afm[3];
1691         int ok= 1, onedone=0;
1692
1693         if(center) {
1694                 min[0]= min[1]= min[2]= 0.0;
1695                 max[0]= max[1]= max[2]= 0.0;
1696         }
1697         else {
1698                 min[0]= min[1]= min[2]= 1.0e10;
1699                 max[0]= max[1]= max[2]= -1.0e10;
1700         }
1701         
1702         for(base= FIRSTBASE; base; base= base->next) {
1703                 if(base->lay & G.vd->lay) {
1704                         onedone= 1;
1705                         minmax_object(base->object, min, max);
1706                 }
1707         }
1708         if(!onedone) return;
1709         
1710         afm[0]= (max[0]-min[0]);
1711         afm[1]= (max[1]-min[1]);
1712         afm[2]= (max[2]-min[2]);
1713         size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1714         if(size==0.0) ok= 0;
1715                 
1716         if(ok) {
1717                 float new_dist;
1718                 float new_ofs[3];
1719                 
1720                 new_dist = size;
1721                 new_ofs[0]= -(min[0]+max[0])/2.0;
1722                 new_ofs[1]= -(min[1]+max[1])/2.0;
1723                 new_ofs[2]= -(min[2]+max[2])/2.0;
1724                 
1725                 // correction for window aspect ratio
1726                 if(curarea->winy>2 && curarea->winx>2) {
1727                         size= (float)curarea->winx/(float)curarea->winy;
1728                         if(size<1.0) size= 1.0/size;
1729                         new_dist*= size;
1730                 }
1731                 
1732                 if (G.vd->persp==2 && G.vd->camera) {
1733                         /* switch out of camera view */
1734                         float orig_lens= G.vd->lens;
1735                         
1736                         G.vd->persp=1;
1737                         G.vd->dist= 0.0;
1738                         view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
1739                         smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
1740                         
1741                 } else {
1742                         if(G.vd->persp>=2) G.vd->persp= 1;
1743                         smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
1744                 }
1745                 scrarea_queue_winredraw(curarea);
1746         }
1747         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1748
1749 }
1750
1751
1752 void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3])
1753 {
1754         float alignaxis[3] = {0.0, 0.0, 0.0};
1755         float norm[3], axis[3], angle, new_quat[4];
1756
1757         if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
1758         else alignaxis[-axisidx-1]= -1.0;
1759
1760         VECCOPY(norm, vec);
1761         Normalize(norm);
1762
1763         angle= acos(Inpf(alignaxis, norm));
1764         Crossf(axis, alignaxis, norm);
1765         VecRotToQuat(axis, -angle, new_quat);
1766
1767         v3d->view= 0;
1768         
1769         if (v3d->persp==2 && v3d->camera) {
1770                 /* switch out of camera view */
1771                 float orig_ofs[3];
1772                 float orig_dist= v3d->dist;
1773                 float orig_lens= v3d->lens;
1774
1775                 VECCOPY(orig_ofs, v3d->ofs);
1776                 G.vd->persp=1;
1777                 G.vd->dist= 0.0;
1778                 view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens);
1779                 smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
1780         } else {
1781                 if (v3d->persp>=2) v3d->persp= 1; /* switch out of camera mode */
1782                 smooth_view(v3d, NULL, new_quat, NULL, NULL);
1783         }
1784 }
1785
1786
1787
1788 /* SMOOTHVIEW */
1789 void smooth_view(View3D *v3d, float *ofs, float *quat, float *dist, float *lens)
1790 {
1791         /* View Animation enabled */
1792         if (U.smooth_viewtx) {
1793                 int i;
1794                 char changed = 0;
1795                 float step = 0.0, step_inv;
1796                 float orig_dist;
1797                 float orig_lens;
1798                 float orig_quat[4];
1799                 float orig_ofs[3];
1800                 
1801                 double time_allowed, time_current, time_start;
1802                 
1803                 /* if there is no difference, return */
1804                 changed = 0; /* zero means no difference */
1805                 if (dist) {
1806                         if ((*dist) != v3d->dist)
1807                                 changed = 1;
1808                 }
1809                 
1810                 if (lens) {
1811                         if ((*lens) != v3d->lens)
1812                                 changed = 1;
1813                 }
1814                 
1815                 if (!changed && ofs) {
1816                         if ((ofs[0]!=v3d->ofs[0]) ||
1817                                 (ofs[1]!=v3d->ofs[1]) ||
1818                                 (ofs[2]!=v3d->ofs[2]) )
1819                                 changed = 1;
1820                 }
1821                 
1822                 if (!changed && quat ) {
1823                         if ((quat[0]!=v3d->viewquat[0]) ||
1824                                 (quat[1]!=v3d->viewquat[1]) ||
1825                                 (quat[2]!=v3d->viewquat[2]) ||
1826                                 (quat[3]!=v3d->viewquat[3]) )
1827                                 changed = 1;
1828                 }
1829                 
1830                 /* The new view is different from teh old one
1831                  * so animate the view */
1832                 if (changed) {
1833                         
1834                         /* store original values */
1835                         VECCOPY(orig_ofs,       v3d->ofs);
1836                         QUATCOPY(orig_quat,     v3d->viewquat);
1837                         orig_dist =                     v3d->dist;
1838                         orig_lens =                     v3d->lens;
1839                         
1840                         time_allowed= (float)U.smooth_viewtx / 1000.0;
1841                         time_current = time_start = PIL_check_seconds_timer();
1842                         
1843                         /* if this is view rotation only
1844                          * we can decrease the time allowed by
1845                          * the angle between quats 
1846                          * this means small rotations wont lag */
1847                          if (quat && !ofs && !dist) {
1848                                 float vec1[3], vec2[3];
1849                                 VECCOPY(vec1, quat);
1850                                 VECCOPY(vec2, v3d->viewquat);
1851                                 Normalize(vec1);
1852                                 Normalize(vec2);
1853                                 /* scale the time allowed by the rotation */
1854                                 time_allowed *= NormalizedVecAngle2(vec1, vec2)/(M_PI/2); 
1855                          }
1856                         
1857                         while (time_start + time_allowed > time_current) {
1858                                 
1859                                 step =  (float)((time_current-time_start) / time_allowed);
1860                                 
1861                                 /* ease in/out */
1862                                 if (step < 0.5) step = pow(step*2, 2)/2;
1863                                 else                    step = 1-(pow(2*(1-step) ,2)/2);
1864                                 
1865                                 step_inv = 1-step;
1866                                 
1867                                 if (ofs)
1868                                         for (i=0; i<3; i++)
1869                                                 v3d->ofs[i] = ofs[i]*step + orig_ofs[i]*step_inv;
1870                                 
1871                                 
1872                                 if (quat)
1873                                         QuatInterpol(v3d->viewquat, orig_quat, quat, step);
1874                                         
1875                                 if (dist)
1876                                         v3d->dist = ((*dist)*step) + (orig_dist*step_inv);
1877                                 
1878                                 if (lens)
1879                                         v3d->lens = ((*lens)*step) + (orig_lens*step_inv);
1880                                 
1881                                 /*redraw the view*/
1882                                 scrarea_do_windraw(curarea);
1883                                 screen_swapbuffers();
1884                                 
1885                                 time_current= PIL_check_seconds_timer();
1886                         }
1887                 }
1888         }
1889         
1890         /* set these values even if animation is enabled because flaot
1891          * error will make then not quite accurate */
1892         if (ofs)
1893                 VECCOPY(v3d->ofs, ofs);
1894         if (quat)
1895                 QUATCOPY(v3d->viewquat, quat);
1896         if (dist)
1897                 v3d->dist = *dist;
1898         if (lens)
1899                 v3d->lens = *lens;
1900         
1901 }
1902
1903
1904
1905 /* Gets the view trasnformation from a camera
1906  * currently dosnt take camzoom into account
1907  * 
1908  * The dist is not modified for this function, if NULL its assimed zero
1909  * */
1910 void view_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens)
1911 {       
1912         float bmat[4][4];
1913         float imat[4][4];
1914         float tmat[3][3];
1915         
1916         if (!ob) return;
1917         
1918         /* Offset */
1919         if (ofs) {
1920                 where_is_object(ob);
1921                 VECCOPY(ofs, ob->obmat[3]);
1922                 VecMulf(ofs, -1.0f); /*flip the vector*/
1923         }
1924         
1925         /* Quat */
1926         if (quat) {
1927                 Mat4CpyMat4(bmat, ob->obmat);
1928                 Mat4Ortho(bmat);
1929                 Mat4Invert(imat, bmat);
1930                 Mat3CpyMat4(tmat, imat);
1931                 Mat3ToQuat(tmat, quat);
1932         }
1933         
1934         if (dist) {
1935                 float vec[3];
1936                 Mat3CpyMat4(tmat, ob->obmat);
1937                 
1938                 vec[0]= vec[1] = 0.0;
1939                 vec[2]= -(*dist);
1940                 Mat3MulVecfl(tmat, vec);
1941                 VecSubf(ofs, ofs, vec);
1942         }
1943         
1944         /* Lens */
1945         if (lens)
1946                 object_view_settings(ob, lens, NULL, NULL);
1947 }
1948
1949 /* For use with smooth view
1950  * 
1951  * the current view is unchanged, blend between the current view and the
1952  * camera view
1953  * */
1954 void smooth_view_to_camera(View3D *v3d)
1955 {
1956         if (!U.smooth_viewtx || !v3d->camera || G.vd->persp != 2) {
1957                 return;
1958         } else {
1959                 Object *ob = v3d->camera;
1960                 
1961                 float orig_ofs[3];
1962                 float orig_dist=v3d->dist;
1963                 float orig_lens=v3d->lens;
1964                 float new_dist=0.0;
1965                 float new_lens=35.0;
1966                 float new_quat[4];
1967                 float new_ofs[3];
1968                 
1969                 VECCOPY(orig_ofs, v3d->ofs);
1970                 
1971                 view_settings_from_ob(ob, new_ofs, new_quat, NULL, &new_lens);
1972                 
1973                 G.vd->persp=1;
1974                 smooth_view(v3d, new_ofs, new_quat, &new_dist, &new_lens);
1975                 VECCOPY(v3d->ofs, orig_ofs);
1976                 v3d->lens= orig_lens;
1977                 v3d->dist = orig_dist; /* restore the dist */
1978                 
1979                 v3d->camera = ob;
1980                 v3d->persp=2;
1981         }
1982 }