adding the initial patch updated to 2.44 in ndof branch
[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     /* Sensitivity will control how fast the view rotates.  The value was
831      * obtained experimentally by tweaking until the author didn't get dizzy watching.
832      * Perhaps this should be a configurable user parameter. 
833      */
834     float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
835     const float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
836     const float zsens = 0.1f;   /* zoom sensitivity */
837
838     const float minZoom = -30.0f;
839     const float maxZoom = 300.0f;
840
841         if (G.obedit==NULL && ob && !(ob->flag & OB_POSEMODE)) {
842                 use_sel = 1;
843         }
844
845     /*----------------------------------------------------
846          * sometimes this routine is called from headerbuttons
847      * viewmove needs to refresh the screen
848      */
849         areawinset(curarea->win);
850
851     /*----------------------------------------------------
852      * record how much time has passed. clamp at 10 Hz
853      * pretend the previous frame occured at the clamped time 
854      */
855     now = PIL_check_seconds_timer();
856     frametime = (now - prevTime);
857     if (frametime > 0.1f){        /* if more than 1/10s */
858         frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
859     }
860     prevTime = now;
861     sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
862
863     /* fetch the current state of the ndof device */
864     getndof(fval);
865
866     /* set object offset */
867         if (ob) {
868                 obofs[0] = -ob->obmat[3][0];
869                 obofs[1] = -ob->obmat[3][1];
870                 obofs[2] = -ob->obmat[3][2];
871         }
872         else {
873                 VECCOPY(obofs, G.vd->ofs);
874         }
875
876     /* calc an adjustment based on distance from camera */
877     if (ob) {
878         VecSubf(diff, obofs, G.vd->ofs);
879         d = VecLength(diff);
880     }
881     else {
882         d = 1.0f;
883     }
884     reverse = (G.vd->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
885
886     /*----------------------------------------------------
887      * ndof device pan 
888      */
889     psens *= 1.0f + d;
890     curareaX = sbadjust * psens * fval[0];
891     curareaY = sbadjust * psens * fval[1];
892     dvec[0] = curareaX * G.vd->persinv[0][0] + curareaY * G.vd->persinv[1][0];
893     dvec[1] = curareaX * G.vd->persinv[0][1] + curareaY * G.vd->persinv[1][1];
894     dvec[2] = curareaX * G.vd->persinv[0][2] + curareaY * G.vd->persinv[1][2];
895     VecAddf(G.vd->ofs, G.vd->ofs, dvec);
896
897     /*----------------------------------------------------
898      * ndof device dolly 
899      */
900     len = zsens * sbadjust * fval[2];
901
902     if (G.vd->persp==2) {
903         if(G.vd->persp==2) {
904             G.vd->camzoom+= 10.0f * -len;
905         }
906         if (G.vd->camzoom < minZoom) G.vd->camzoom = minZoom;
907         else if (G.vd->camzoom > maxZoom) G.vd->camzoom = maxZoom;
908     }
909     else if ((G.vd->dist> 0.001*G.vd->grid) && (G.vd->dist<10.0*G.vd->far)) {
910         G.vd->dist*=(1.0 + len);
911     }
912
913
914     /*----------------------------------------------------
915      * ndof device turntable
916      * derived from the turntable code in viewmove
917      */
918
919     /* Get the 3x3 matrix and its inverse from the quaternion */
920     QuatToMat3(G.vd->viewquat, m);
921     Mat3Inv(m_inv,m);
922
923     /* Determine the direction of the x vector (for rotating up and down) */
924     /* This can likely be compuated directly from the quaternion. */
925     Mat3MulVecfl(m_inv,xvec);
926
927     /* Perform the up/down rotation */
928     phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
929     si = sin(phi);
930     q1[0] = cos(phi);
931     q1[1] = si * xvec[0];
932     q1[2] = si * xvec[1];
933     q1[3] = si * xvec[2];
934     QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
935
936     if (use_sel) {
937         QuatConj(q1); /* conj == inv for unit quat */
938         VecSubf(G.vd->ofs, G.vd->ofs, obofs);
939         QuatMulVecf(q1, G.vd->ofs);
940         VecAddf(G.vd->ofs, G.vd->ofs, obofs);
941     }
942
943     /* Perform the orbital rotation */
944     phi = sbadjust * rsens * reverse * fval[4];     /* twist the knob, y axis */
945     q1[0] = cos(phi);
946     q1[1] = q1[2] = 0.0;
947     q1[3] = sin(phi);
948     QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
949
950     if (use_sel) {
951         QuatConj(q1);
952         VecSubf(G.vd->ofs, G.vd->ofs, obofs);
953         QuatMulVecf(q1, G.vd->ofs);
954         VecAddf(G.vd->ofs, G.vd->ofs, obofs);
955     }
956
957     /*----------------------------------------------------
958      * refresh the screen
959      */
960     scrarea_do_windraw(curarea);
961     screen_swapbuffers();
962 }
963
964
965
966
967 /* Gets the lens and clipping values from a camera of lamp type object */
968 void object_view_settings(Object *ob, float *lens, float *clipsta, float *clipend)
969 {       
970         if (!ob) return;
971         
972         if(ob->type==OB_LAMP ) {
973                 Lamp *la = ob->data;
974                 if (lens) {
975                         float x1, fac;
976                         fac= cos( M_PI*la->spotsize/360.0);
977                         x1= saacos(fac);
978                         *lens= 16.0*fac/sin(x1);
979                 }
980                 if (clipsta)    *clipsta= la->clipsta;
981                 if (clipend)    *clipend= la->clipend;
982         }
983         else if(ob->type==OB_CAMERA) {
984                 Camera *cam= ob->data;
985                 if (lens)               *lens= cam->lens;
986                 if (clipsta)    *clipsta= cam->clipsta;
987                 if (clipend)    *clipend= cam->clipend;
988         }
989 }
990
991
992 int get_view3d_viewplane(int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
993 {
994         Camera *cam=NULL;
995         float lens, fac, x1, y1, x2, y2;
996         float winx= (float)winxi, winy= (float)winyi;
997         int orth= 0;
998         
999         lens= G.vd->lens;       
1000         
1001         *clipsta= G.vd->near;
1002         *clipend= G.vd->far;
1003
1004 /*      
1005  * Cant use this since we need the fac and x1 values set
1006  * if(G.vd->persp==2)
1007                 object_view_settings(G.vd->camera, &lens, &(*clipsta), &(*clipend));*/
1008         
1009         if(G.vd->persp==2) {
1010                 if(G.vd->camera) {
1011                         if(G.vd->camera->type==OB_LAMP ) {
1012                                 Lamp *la;
1013                                 
1014                                 la= G.vd->camera->data;
1015                                 fac= cos( M_PI*la->spotsize/360.0);
1016                                 
1017                                 x1= saacos(fac);
1018                                 lens= 16.0*fac/sin(x1);
1019                 
1020                                 *clipsta= la->clipsta;
1021                                 *clipend= la->clipend;
1022                         }
1023                         else if(G.vd->camera->type==OB_CAMERA) {
1024                                 cam= G.vd->camera->data;
1025                                 lens= cam->lens;
1026                                 *clipsta= cam->clipsta;
1027                                 *clipend= cam->clipend;
1028                         }
1029                 }
1030         }
1031         
1032         if(G.vd->persp==0) {
1033                 if(winx>winy) x1= -G.vd->dist;
1034                 else x1= -winx*G.vd->dist/winy;
1035                 x2= -x1;
1036
1037                 if(winx>winy) y1= -winy*G.vd->dist/winx;
1038                 else y1= -G.vd->dist;
1039                 y2= -y1;
1040                 
1041                 *clipend *= 0.5;        // otherwise too extreme low zbuffer quality
1042                 *clipsta= - *clipend;
1043                 orth= 1;
1044         }
1045         else {
1046                 /* fac for zoom, also used for camdx */
1047                 if(G.vd->persp==2) {
1048                         fac= (1.41421+( (float)G.vd->camzoom )/50.0);
1049                         fac*= fac;
1050                 }
1051                 else fac= 2.0;
1052                 
1053                 /* viewplane size depends... */
1054                 if(cam && cam->type==CAM_ORTHO) {
1055                         /* ortho_scale == 1 means exact 1 to 1 mapping */
1056                         float dfac= 2.0*cam->ortho_scale/fac;
1057                         
1058                         if(winx>winy) x1= -dfac;
1059                         else x1= -winx*dfac/winy;
1060                         x2= -x1;
1061                         
1062                         if(winx>winy) y1= -winy*dfac/winx;
1063                         else y1= -dfac;
1064                         y2= -y1;
1065                         orth= 1;
1066                 }
1067                 else {
1068                         float dfac;
1069                         
1070                         if(winx>winy) dfac= 64.0/(fac*winx*lens);
1071                         else dfac= 64.0/(fac*winy*lens);
1072                         
1073                         x1= - *clipsta * winx*dfac;
1074                         x2= -x1;
1075                         y1= - *clipsta * winy*dfac;
1076                         y2= -y1;
1077                         orth= 0;
1078                 }
1079                 /* cam view offset */
1080                 if(cam) {
1081                         float dx= 0.5*fac*G.vd->camdx*(x2-x1);
1082                         float dy= 0.5*fac*G.vd->camdy*(y2-y1);
1083                         x1+= dx;
1084                         x2+= dx;
1085                         y1+= dy;
1086                         y2+= dy;
1087                 }
1088         }
1089
1090         if(pixsize) {
1091                 float viewfac;
1092
1093                 if(orth) {
1094                         viewfac= (winx >= winy)? winx: winy;
1095                         *pixsize= 1.0f/viewfac;
1096                 }
1097                 else {
1098                         viewfac= (((winx >= winy)? winx: winy)*lens)/32.0;
1099                         *pixsize= *clipsta/viewfac;
1100                 }
1101         }
1102         
1103         viewplane->xmin= x1;
1104         viewplane->ymin= y1;
1105         viewplane->xmax= x2;
1106         viewplane->ymax= y2;
1107         
1108         return orth;
1109 }
1110
1111 /* important to not set windows active in here, can be renderwin for example */
1112 void setwinmatrixview3d(int winx, int winy, rctf *rect)         /* rect: for picking */
1113 {
1114         rctf viewplane;
1115         float clipsta, clipend, x1, y1, x2, y2;
1116         int orth;
1117         
1118         orth= get_view3d_viewplane(winx, winy, &viewplane, &clipsta, &clipend, NULL);
1119 //      printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
1120         x1= viewplane.xmin;
1121         y1= viewplane.ymin;
1122         x2= viewplane.xmax;
1123         y2= viewplane.ymax;
1124         
1125         if(rect) {              /* picking */
1126                 rect->xmin/= (float)curarea->winx;
1127                 rect->xmin= x1+rect->xmin*(x2-x1);
1128                 rect->ymin/= (float)curarea->winy;
1129                 rect->ymin= y1+rect->ymin*(y2-y1);
1130                 rect->xmax/= (float)curarea->winx;
1131                 rect->xmax= x1+rect->xmax*(x2-x1);
1132                 rect->ymax/= (float)curarea->winy;
1133                 rect->ymax= y1+rect->ymax*(y2-y1);
1134                 
1135                 if(orth) myortho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
1136                 else mywindow(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
1137                 
1138         }
1139         else {
1140                 if(orth) myortho(x1, x2, y1, y2, clipsta, clipend);
1141                 else mywindow(x1, x2, y1, y2, clipsta, clipend);
1142         }
1143
1144         /* not sure what this was for? (ton) */
1145         glMatrixMode(GL_PROJECTION);
1146         mygetmatrix(curarea->winmat);
1147         glMatrixMode(GL_MODELVIEW);
1148 }
1149
1150 void obmat_to_viewmat(Object *ob, short smooth)
1151 {
1152         float bmat[4][4];
1153         float tmat[3][3];
1154
1155         Mat4CpyMat4(bmat, ob->obmat);
1156         Mat4Ortho(bmat);
1157         Mat4Invert(G.vd->viewmat, bmat);
1158         
1159         /* view quat calculation, needed for add object */
1160         Mat3CpyMat4(tmat, G.vd->viewmat);
1161         if (smooth) {
1162                 float new_quat[4];
1163                 if (G.vd->persp==2 && G.vd->camera) {
1164                         /* were from a camera view */
1165                         
1166                         float orig_ofs[3];
1167                         float orig_dist= G.vd->dist;
1168                         float orig_lens= G.vd->lens;
1169                         VECCOPY(orig_ofs, G.vd->ofs);
1170                         
1171                         /* Switch from camera view */
1172                         Mat3ToQuat(tmat, new_quat);
1173                         
1174                         G.vd->persp=1;
1175                         G.vd->dist= 0.0;
1176                         
1177                         view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
1178                         smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
1179                         
1180                         G.vd->persp=2; /* just to be polite, not needed */
1181                         
1182                 } else {
1183                         Mat3ToQuat(tmat, new_quat);
1184                         smooth_view(G.vd, NULL, new_quat, NULL, NULL);
1185                 }
1186         } else {
1187                 Mat3ToQuat(tmat, G.vd->viewquat);
1188         }
1189 }
1190
1191 /* dont set windows active in in here, is used by renderwin too */
1192 void setviewmatrixview3d()
1193 {
1194         Camera *cam;
1195
1196         if(G.vd->persp>=2) {        /* obs/camera */
1197                 if(G.vd->camera) {
1198                         
1199                         where_is_object(G.vd->camera);  
1200                         obmat_to_viewmat(G.vd->camera, 0);
1201                         
1202                         if(G.vd->camera->type==OB_CAMERA) {
1203                                 cam= G.vd->camera->data;
1204                                 //if(cam->type==CAM_ORTHO) G.vd->viewmat[3][2]*= 100.0;
1205                         }
1206                 }
1207                 else {
1208                         QuatToMat4(G.vd->viewquat, G.vd->viewmat);
1209                         G.vd->viewmat[3][2]-= G.vd->dist;
1210                 }
1211         }
1212         else {
1213                 
1214                 QuatToMat4(G.vd->viewquat, G.vd->viewmat);
1215                 if(G.vd->persp==1) G.vd->viewmat[3][2]-= G.vd->dist;
1216                 if(G.vd->ob_centre) {
1217                         Object *ob= G.vd->ob_centre;
1218                         float vec[3];
1219                         
1220                         VECCOPY(vec, ob->obmat[3]);
1221                         if(ob->type==OB_ARMATURE && G.vd->ob_centre_bone[0]) {
1222                                 bPoseChannel *pchan= get_pose_channel(ob->pose, G.vd->ob_centre_bone);
1223                                 if(pchan) {
1224                                         VECCOPY(vec, pchan->pose_mat[3]);
1225                                         Mat4MulVecfl(ob->obmat, vec);
1226                                 }
1227                         }
1228                         i_translate(-vec[0], -vec[1], -vec[2], G.vd->viewmat);
1229                 }
1230                 else i_translate(G.vd->ofs[0], G.vd->ofs[1], G.vd->ofs[2], G.vd->viewmat);
1231         }
1232 }
1233
1234 void setcameratoview3d(void)
1235 {
1236         Object *ob;
1237         float dvec[3];
1238
1239         ob= G.vd->camera;
1240         dvec[0]= G.vd->dist*G.vd->viewinv[2][0];
1241         dvec[1]= G.vd->dist*G.vd->viewinv[2][1];
1242         dvec[2]= G.vd->dist*G.vd->viewinv[2][2];                                        
1243         VECCOPY(ob->loc, dvec);
1244         VecSubf(ob->loc, ob->loc, G.vd->ofs);
1245         G.vd->viewquat[0]= -G.vd->viewquat[0];
1246         if (ob->transflag & OB_QUAT) {
1247                 QUATCOPY(ob->quat, G.vd->viewquat);
1248         } else {
1249                 QuatToEul(G.vd->viewquat, ob->rot);
1250         }
1251         G.vd->viewquat[0]= -G.vd->viewquat[0];
1252 }
1253
1254 /* IGLuint-> GLuint*/
1255 /* Warning: be sure to account for a negative return value
1256  *   This is an error, "Too many objects in select buffer"
1257  *   and no action should be taken (can crash blender) if this happens
1258  */
1259 short  view3d_opengl_select(unsigned int *buffer, unsigned int bufsize, short x1, short y1, short x2, short y2)
1260 {
1261         rctf rect;
1262         short mval[2], code, hits;
1263
1264         G.f |= G_PICKSEL;
1265         
1266         if(x1==0 && x2==0 && y1==0 && y2==0) {
1267                 getmouseco_areawin(mval);
1268                 rect.xmin= mval[0]-12;  // seems to be default value for bones only now
1269                 rect.xmax= mval[0]+12;
1270                 rect.ymin= mval[1]-12;
1271                 rect.ymax= mval[1]+12;
1272         }
1273         else {
1274                 rect.xmin= x1;
1275                 rect.xmax= x2;
1276                 rect.ymin= y1;
1277                 rect.ymax= y2;
1278         }
1279         /* get rid of overlay button matrix */
1280         persp(PERSP_VIEW);
1281         setwinmatrixview3d(curarea->winx, curarea->winy, &rect);
1282         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
1283         
1284         if(G.vd->drawtype > OB_WIRE) {
1285                 G.vd->zbuf= TRUE;
1286                 glEnable(GL_DEPTH_TEST);
1287         }
1288
1289         if(G.vd->flag & V3D_CLIPPING)
1290                 view3d_set_clipping(G.vd);
1291         
1292         glSelectBuffer( bufsize, (GLuint *)buffer);
1293         glRenderMode(GL_SELECT);
1294         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1295         glPushName(-1);
1296         code= 1;
1297         
1298         if(G.obedit && G.obedit->type==OB_MBALL) {
1299                 draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1300         }
1301         else if ((G.obedit && G.obedit->type==OB_ARMATURE)) {
1302                 draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1303         }
1304         else {
1305                 Base *base;
1306                 
1307                 G.vd->xray= TRUE;       // otherwise it postpones drawing
1308                 for(base= G.scene->base.first; base; base= base->next) {
1309                         if(base->lay & G.vd->lay) {
1310                                 
1311                                 if (base->object->restrictflag & OB_RESTRICT_SELECT)
1312                                         base->selcol= 0;
1313                                 else {
1314                                         base->selcol= code;
1315                                         glLoadName(code);
1316                                         draw_object(base, DRAW_PICKING|DRAW_CONSTCOLOR);
1317                                         
1318                                         /* we draw group-duplicators for selection too */
1319                                         if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1320                                                 ListBase *lb;
1321                                                 DupliObject *dob;
1322                                                 Base tbase;
1323                                                 
1324                                                 tbase.flag= OB_FROMDUPLI;
1325                                                 lb= object_duplilist(G.scene, base->object);
1326                                                 
1327                                                 for(dob= lb->first; dob; dob= dob->next) {
1328                                                         tbase.object= dob->ob;
1329                                                         Mat4CpyMat4(dob->ob->obmat, dob->mat);
1330                                                         
1331                                                         draw_object(&tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1332                                                         
1333                                                         Mat4CpyMat4(dob->ob->obmat, dob->omat);
1334                                                 }
1335                                                 free_object_duplilist(lb);
1336                                         }
1337                                         code++;
1338                                 }                               
1339                         }
1340                 }
1341                 G.vd->xray= FALSE;      // restore
1342         }
1343         
1344         glPopName();    /* see above (pushname) */
1345         hits= glRenderMode(GL_RENDER);
1346
1347         G.f &= ~G_PICKSEL;
1348         setwinmatrixview3d(curarea->winx, curarea->winy, NULL);
1349         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
1350         
1351         if(G.vd->drawtype > OB_WIRE) {
1352                 G.vd->zbuf= 0;
1353                 glDisable(GL_DEPTH_TEST);
1354         }
1355         persp(PERSP_WIN);
1356         
1357         if(G.vd->flag & V3D_CLIPPING)
1358                 view3d_clr_clipping();
1359         
1360         if(hits<0) error("Too many objects in select buffer");
1361         
1362         return hits;
1363 }
1364
1365 float *give_cursor()
1366 {
1367         if(G.vd && G.vd->localview) return G.vd->cursor;
1368         else return G.scene->cursor;
1369 }
1370
1371 unsigned int free_localbit()
1372 {
1373         unsigned int lay;
1374         ScrArea *sa;
1375         bScreen *sc;
1376         
1377         lay= 0;
1378         
1379         /* sometimes we loose a localview: when an area is closed */
1380         /* check all areas: which localviews are in use? */
1381         sc= G.main->screen.first;
1382         while(sc) {
1383                 sa= sc->areabase.first;
1384                 while(sa) {
1385                         SpaceLink *sl= sa->spacedata.first;
1386                         while(sl) {
1387                                 if(sl->spacetype==SPACE_VIEW3D) {
1388                                         View3D *v3d= (View3D*) sl;
1389                                         lay |= v3d->lay;
1390                                 }
1391                                 sl= sl->next;
1392                         }
1393                         sa= sa->next;
1394                 }
1395                 sc= sc->id.next;
1396         }
1397         
1398         if( (lay & 0x01000000)==0) return 0x01000000;
1399         if( (lay & 0x02000000)==0) return 0x02000000;
1400         if( (lay & 0x04000000)==0) return 0x04000000;
1401         if( (lay & 0x08000000)==0) return 0x08000000;
1402         if( (lay & 0x10000000)==0) return 0x10000000;
1403         if( (lay & 0x20000000)==0) return 0x20000000;
1404         if( (lay & 0x40000000)==0) return 0x40000000;
1405         if( (lay & 0x80000000)==0) return 0x80000000;
1406         
1407         return 0;
1408 }
1409
1410
1411 void initlocalview()
1412 {
1413         Base *base;
1414         float size = 0.0, min[3], max[3], afm[3];
1415         unsigned int locallay;
1416         int ok=0;
1417
1418         if(G.vd->localvd) return;
1419
1420         min[0]= min[1]= min[2]= 1.0e10;
1421         max[0]= max[1]= max[2]= -1.0e10;
1422
1423         locallay= free_localbit();
1424
1425         if(locallay==0) {
1426                 error("Sorry,  no more than 8 localviews");
1427                 ok= 0;
1428         }
1429         else {
1430                 if(G.obedit) {
1431                         minmax_object(G.obedit, min, max);
1432                         
1433                         ok= 1;
1434                 
1435                         BASACT->lay |= locallay;
1436                         G.obedit->lay= BASACT->lay;
1437                 }
1438                 else {
1439                         base= FIRSTBASE;
1440                         while(base) {
1441                                 if TESTBASE(base)  {
1442                                         minmax_object(base->object, min, max);
1443                                         base->lay |= locallay;
1444                                         base->object->lay= base->lay;
1445                                         ok= 1;
1446                                 }
1447                                 base= base->next;
1448                         }
1449                 }
1450                 
1451                 afm[0]= (max[0]-min[0]);
1452                 afm[1]= (max[1]-min[1]);
1453                 afm[2]= (max[2]-min[2]);
1454                 size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1455                 if(size<=0.01) size= 0.01;
1456         }
1457         
1458         if(ok) {
1459                 G.vd->localvd= MEM_mallocN(sizeof(View3D), "localview");
1460                 memcpy(G.vd->localvd, G.vd, sizeof(View3D));
1461
1462                 G.vd->ofs[0]= -(min[0]+max[0])/2.0;
1463                 G.vd->ofs[1]= -(min[1]+max[1])/2.0;
1464                 G.vd->ofs[2]= -(min[2]+max[2])/2.0;
1465
1466                 G.vd->dist= size;
1467
1468                 // correction for window aspect ratio
1469                 if(curarea->winy>2 && curarea->winx>2) {
1470                         size= (float)curarea->winx/(float)curarea->winy;
1471                         if(size<1.0) size= 1.0/size;
1472                         G.vd->dist*= size;
1473                 }
1474                 
1475                 if (G.vd->persp>1) G.vd->persp= 1;
1476                 if (G.vd->near> 0.1) G.vd->near= 0.1;
1477                 
1478                 G.vd->cursor[0]= -G.vd->ofs[0];
1479                 G.vd->cursor[1]= -G.vd->ofs[1];
1480                 G.vd->cursor[2]= -G.vd->ofs[2];
1481
1482                 G.vd->lay= locallay;
1483                 
1484                 countall();
1485                 scrarea_queue_winredraw(curarea);
1486         }
1487         else {
1488                 /* clear flags */ 
1489                 base= FIRSTBASE;
1490                 while(base) {
1491                         if( base->lay & locallay ) {
1492                                 base->lay-= locallay;
1493                                 if(base->lay==0) base->lay= G.vd->layact;
1494                                 if(base->object != G.obedit) base->flag |= SELECT;
1495                                 base->object->lay= base->lay;
1496                         }
1497                         base= base->next;
1498                 }
1499                 scrarea_queue_headredraw(curarea);
1500                 
1501                 G.vd->localview= 0;
1502         }
1503         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1504 }
1505
1506 void centerview()       /* like a localview without local! */
1507 {
1508         Object *ob= OBACT;
1509         float size, min[3], max[3], afm[3];
1510         int ok=0;
1511         
1512         /* SMOOTHVIEW */
1513         float new_ofs[3];
1514         float new_dist;
1515         
1516         
1517         min[0]= min[1]= min[2]= 1.0e10;
1518         max[0]= max[1]= max[2]= -1.0e10;
1519
1520         if (G.f & G_WEIGHTPAINT) {
1521                 /* hardcoded exception, we look for the one selected armature */
1522                 /* this is weak code this way, we should make a generic active/selection callback interface once... */
1523                 Base *base;
1524                 for(base=FIRSTBASE; base; base= base->next) {
1525                         if(TESTBASELIB(base)) {
1526                                 if(base->object->type==OB_ARMATURE)
1527                                         if(base->object->flag & OB_POSEMODE)
1528                                                 break;
1529                         }
1530                 }
1531                 if(base)
1532                         ob= base->object;
1533         }
1534         
1535         
1536         if(G.obedit) {
1537                 ok = minmax_verts(min, max);    /* only selected */
1538         }
1539         else if(ob && (ob->flag & OB_POSEMODE)) {
1540                 if(ob->pose) {
1541                         bArmature *arm= ob->data;
1542                         bPoseChannel *pchan;
1543                         float vec[3];
1544                         
1545                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
1546                                 if(pchan->bone->flag & BONE_SELECTED) {
1547                                         if(pchan->bone->layer & arm->layer) {
1548                                                 ok= 1;
1549                                                 VECCOPY(vec, pchan->pose_head);
1550                                                 Mat4MulVecfl(ob->obmat, vec);
1551                                                 DO_MINMAX(vec, min, max);
1552                                                 VECCOPY(vec, pchan->pose_tail);
1553                                                 Mat4MulVecfl(ob->obmat, vec);
1554                                                 DO_MINMAX(vec, min, max);
1555                                         }
1556                                 }
1557                         }
1558                 }
1559         }
1560         else if (G.f & G_FACESELECT) {
1561                 ok= minmax_tface(min, max);
1562         }
1563         else {
1564                 Base *base= FIRSTBASE;
1565                 while(base) {
1566                         if TESTBASE(base)  {
1567                                 minmax_object(base->object, min, max);
1568                                 /* account for duplis */
1569                                 minmax_object_duplis(base->object, min, max);
1570                                 
1571                                 ok= 1;
1572                         }
1573                         base= base->next;
1574                 }
1575         }
1576         
1577         if(ok==0) return;
1578         
1579         afm[0]= (max[0]-min[0]);
1580         afm[1]= (max[1]-min[1]);
1581         afm[2]= (max[2]-min[2]);
1582         size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1583         
1584         if(size <= G.vd->near*1.5) size= G.vd->near*1.5;
1585         
1586         new_ofs[0]= -(min[0]+max[0])/2.0;
1587         new_ofs[1]= -(min[1]+max[1])/2.0;
1588         new_ofs[2]= -(min[2]+max[2])/2.0;
1589         
1590         new_dist = size;
1591
1592         /* correction for window aspect ratio */
1593         if(curarea->winy>2 && curarea->winx>2) {
1594                 size= (float)curarea->winx/(float)curarea->winy;
1595                 if(size<1.0) size= 1.0/size;
1596                 new_dist*= size;
1597         }
1598         
1599         G.vd->cursor[0]= -new_ofs[0];
1600         G.vd->cursor[1]= -new_ofs[1];
1601         G.vd->cursor[2]= -new_ofs[2];
1602         
1603         if (G.vd->persp==2 && G.vd->camera) {
1604                 float orig_lens= G.vd->lens;
1605                 
1606                 G.vd->persp=1;
1607                 G.vd->dist= 0.0;
1608                 view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
1609                 smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
1610         } else {
1611                 if(G.vd->persp>=2)
1612                         G.vd->persp= 1;
1613                 
1614                 smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
1615         }
1616         scrarea_queue_winredraw(curarea);
1617         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1618
1619 }
1620
1621
1622 void restore_localviewdata(View3D *vd)
1623 {
1624         if(vd->localvd==0) return;
1625         
1626         VECCOPY(vd->ofs, vd->localvd->ofs);
1627         vd->dist= vd->localvd->dist;
1628         vd->persp= vd->localvd->persp;
1629         vd->view= vd->localvd->view;
1630         vd->near= vd->localvd->near;
1631         vd->far= vd->localvd->far;
1632         vd->lay= vd->localvd->lay;
1633         vd->layact= vd->localvd->layact;
1634         vd->drawtype= vd->localvd->drawtype;
1635         vd->camera= vd->localvd->camera;
1636         QUATCOPY(vd->viewquat, vd->localvd->viewquat);
1637         
1638 }
1639
1640 void endlocalview(ScrArea *sa)
1641 {
1642         View3D *v3d;
1643         struct Base *base;
1644         unsigned int locallay;
1645         
1646         if(sa->spacetype!=SPACE_VIEW3D) return;
1647         v3d= sa->spacedata.first;
1648         
1649         if(v3d->localvd) {
1650                 
1651                 locallay= v3d->lay & 0xFF000000;
1652                 
1653                 restore_localviewdata(v3d);
1654                 
1655                 MEM_freeN(v3d->localvd);
1656                 v3d->localvd= 0;
1657                 v3d->localview= 0;
1658
1659                 /* for when in other window the layers have changed */
1660                 if(v3d->scenelock) v3d->lay= G.scene->lay;
1661                 
1662                 base= FIRSTBASE;
1663                 while(base) {
1664                         if( base->lay & locallay ) {
1665                                 base->lay-= locallay;
1666                                 if(base->lay==0) base->lay= v3d->layact;
1667                                 if(base->object != G.obedit) {
1668                                         base->flag |= SELECT;
1669                                         base->object->flag |= SELECT;
1670                                 }
1671                                 base->object->lay= base->lay;
1672                         }
1673                         base= base->next;
1674                 }
1675
1676                 countall();
1677                 allqueue(REDRAWVIEW3D, 0);      /* because of select */
1678                 allqueue(REDRAWOOPS, 0);        /* because of select */
1679                 BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1680         } 
1681 }
1682
1683 void view3d_home(int center)
1684 {
1685         Base *base;
1686         float size, min[3], max[3], afm[3];
1687         int ok= 1, onedone=0;
1688
1689         if(center) {
1690                 min[0]= min[1]= min[2]= 0.0;
1691                 max[0]= max[1]= max[2]= 0.0;
1692         }
1693         else {
1694                 min[0]= min[1]= min[2]= 1.0e10;
1695                 max[0]= max[1]= max[2]= -1.0e10;
1696         }
1697         
1698         for(base= FIRSTBASE; base; base= base->next) {
1699                 if(base->lay & G.vd->lay) {
1700                         onedone= 1;
1701                         minmax_object(base->object, min, max);
1702                 }
1703         }
1704         if(!onedone) return;
1705         
1706         afm[0]= (max[0]-min[0]);
1707         afm[1]= (max[1]-min[1]);
1708         afm[2]= (max[2]-min[2]);
1709         size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1710         if(size==0.0) ok= 0;
1711                 
1712         if(ok) {
1713                 float new_dist;
1714                 float new_ofs[3];
1715                 
1716                 new_dist = size;
1717                 new_ofs[0]= -(min[0]+max[0])/2.0;
1718                 new_ofs[1]= -(min[1]+max[1])/2.0;
1719                 new_ofs[2]= -(min[2]+max[2])/2.0;
1720                 
1721                 // correction for window aspect ratio
1722                 if(curarea->winy>2 && curarea->winx>2) {
1723                         size= (float)curarea->winx/(float)curarea->winy;
1724                         if(size<1.0) size= 1.0/size;
1725                         new_dist*= size;
1726                 }
1727                 
1728                 if (G.vd->persp==2 && G.vd->camera) {
1729                         /* switch out of camera view */
1730                         float orig_lens= G.vd->lens;
1731                         
1732                         G.vd->persp=1;
1733                         G.vd->dist= 0.0;
1734                         view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
1735                         smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
1736                         
1737                 } else {
1738                         if(G.vd->persp>=2) G.vd->persp= 1;
1739                         smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
1740                 }
1741                 scrarea_queue_winredraw(curarea);
1742         }
1743         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1744
1745 }
1746
1747
1748 void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3])
1749 {
1750         float alignaxis[3] = {0.0, 0.0, 0.0};
1751         float norm[3], axis[3], angle, new_quat[4];
1752
1753         if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
1754         else alignaxis[-axisidx-1]= -1.0;
1755
1756         VECCOPY(norm, vec);
1757         Normalize(norm);
1758
1759         angle= acos(Inpf(alignaxis, norm));
1760         Crossf(axis, alignaxis, norm);
1761         VecRotToQuat(axis, -angle, new_quat);
1762
1763         v3d->view= 0;
1764         
1765         if (v3d->persp==2 && v3d->camera) {
1766                 /* switch out of camera view */
1767                 float orig_ofs[3];
1768                 float orig_dist= v3d->dist;
1769                 float orig_lens= v3d->lens;
1770
1771                 VECCOPY(orig_ofs, v3d->ofs);
1772                 G.vd->persp=1;
1773                 G.vd->dist= 0.0;
1774                 view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens);
1775                 smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
1776         } else {
1777                 if (v3d->persp>=2) v3d->persp= 1; /* switch out of camera mode */
1778                 smooth_view(v3d, NULL, new_quat, NULL, NULL);
1779         }
1780 }
1781
1782
1783
1784 /* SMOOTHVIEW */
1785 void smooth_view(View3D *v3d, float *ofs, float *quat, float *dist, float *lens)
1786 {
1787         /* View Animation enabled */
1788         if (U.smooth_viewtx) {
1789                 int i;
1790                 char changed = 0;
1791                 float step = 0.0, step_inv;
1792                 float orig_dist;
1793                 float orig_lens;
1794                 float orig_quat[4];
1795                 float orig_ofs[3];
1796                 
1797                 double time_allowed, time_current, time_start;
1798                 
1799                 /* if there is no difference, return */
1800                 changed = 0; /* zero means no difference */
1801                 if (dist) {
1802                         if ((*dist) != v3d->dist)
1803                                 changed = 1;
1804                 }
1805                 
1806                 if (lens) {
1807                         if ((*lens) != v3d->lens)
1808                                 changed = 1;
1809                 }
1810                 
1811                 if (!changed && ofs) {
1812                         if ((ofs[0]!=v3d->ofs[0]) ||
1813                                 (ofs[1]!=v3d->ofs[1]) ||
1814                                 (ofs[2]!=v3d->ofs[2]) )
1815                                 changed = 1;
1816                 }
1817                 
1818                 if (!changed && quat ) {
1819                         if ((quat[0]!=v3d->viewquat[0]) ||
1820                                 (quat[1]!=v3d->viewquat[1]) ||
1821                                 (quat[2]!=v3d->viewquat[2]) ||
1822                                 (quat[3]!=v3d->viewquat[3]) )
1823                                 changed = 1;
1824                 }
1825                 
1826                 /* The new view is different from teh old one
1827                  * so animate the view */
1828                 if (changed) {
1829                         
1830                         /* store original values */
1831                         VECCOPY(orig_ofs,       v3d->ofs);
1832                         QUATCOPY(orig_quat,     v3d->viewquat);
1833                         orig_dist =                     v3d->dist;
1834                         orig_lens =                     v3d->lens;
1835                         
1836                         time_allowed= (float)U.smooth_viewtx / 1000.0;
1837                         time_current = time_start = PIL_check_seconds_timer();
1838                         
1839                         /* if this is view rotation only
1840                          * we can decrease the time allowed by
1841                          * the angle between quats 
1842                          * this means small rotations wont lag */
1843                          if (quat && !ofs && !dist) {
1844                                 float vec1[3], vec2[3];
1845                                 VECCOPY(vec1, quat);
1846                                 VECCOPY(vec2, v3d->viewquat);
1847                                 Normalize(vec1);
1848                                 Normalize(vec2);
1849                                 /* scale the time allowed by the rotation */
1850                                 time_allowed *= NormalizedVecAngle2(vec1, vec2)/(M_PI/2); 
1851                          }
1852                         
1853                         while (time_start + time_allowed > time_current) {
1854                                 
1855                                 step =  (float)((time_current-time_start) / time_allowed);
1856                                 
1857                                 /* ease in/out */
1858                                 if (step < 0.5) step = pow(step*2, 2)/2;
1859                                 else                    step = 1-(pow(2*(1-step) ,2)/2);
1860                                 
1861                                 step_inv = 1-step;
1862                                 
1863                                 if (ofs)
1864                                         for (i=0; i<3; i++)
1865                                                 v3d->ofs[i] = ofs[i]*step + orig_ofs[i]*step_inv;
1866                                 
1867                                 
1868                                 if (quat)
1869                                         QuatInterpol(v3d->viewquat, orig_quat, quat, step);
1870                                         
1871                                 if (dist)
1872                                         v3d->dist = ((*dist)*step) + (orig_dist*step_inv);
1873                                 
1874                                 if (lens)
1875                                         v3d->lens = ((*lens)*step) + (orig_lens*step_inv);
1876                                 
1877                                 /*redraw the view*/
1878                                 scrarea_do_windraw(curarea);
1879                                 screen_swapbuffers();
1880                                 
1881                                 time_current= PIL_check_seconds_timer();
1882                         }
1883                 }
1884         }
1885         
1886         /* set these values even if animation is enabled because flaot
1887          * error will make then not quite accurate */
1888         if (ofs)
1889                 VECCOPY(v3d->ofs, ofs);
1890         if (quat)
1891                 QUATCOPY(v3d->viewquat, quat);
1892         if (dist)
1893                 v3d->dist = *dist;
1894         if (lens)
1895                 v3d->lens = *lens;
1896         
1897 }
1898
1899
1900
1901 /* Gets the view trasnformation from a camera
1902  * currently dosnt take camzoom into account
1903  * 
1904  * The dist is not modified for this function, if NULL its assimed zero
1905  * */
1906 void view_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens)
1907 {       
1908         float bmat[4][4];
1909         float imat[4][4];
1910         float tmat[3][3];
1911         
1912         if (!ob) return;
1913         
1914         /* Offset */
1915         if (ofs) {
1916                 where_is_object(ob);
1917                 VECCOPY(ofs, ob->obmat[3]);
1918                 VecMulf(ofs, -1.0f); /*flip the vector*/
1919         }
1920         
1921         /* Quat */
1922         if (quat) {
1923                 Mat4CpyMat4(bmat, ob->obmat);
1924                 Mat4Ortho(bmat);
1925                 Mat4Invert(imat, bmat);
1926                 Mat3CpyMat4(tmat, imat);
1927                 Mat3ToQuat(tmat, quat);
1928         }
1929         
1930         if (dist) {
1931                 float vec[3];
1932                 Mat3CpyMat4(tmat, ob->obmat);
1933                 
1934                 vec[0]= vec[1] = 0.0;
1935                 vec[2]= -(*dist);
1936                 Mat3MulVecfl(tmat, vec);
1937                 VecSubf(ofs, ofs, vec);
1938         }
1939         
1940         /* Lens */
1941         if (lens)
1942                 object_view_settings(ob, lens, NULL, NULL);
1943 }
1944
1945 /* For use with smooth view
1946  * 
1947  * the current view is unchanged, blend between the current view and the
1948  * camera view
1949  * */
1950 void smooth_view_to_camera(View3D *v3d)
1951 {
1952         if (!U.smooth_viewtx || !v3d->camera || G.vd->persp != 2) {
1953                 return;
1954         } else {
1955                 Object *ob = v3d->camera;
1956                 
1957                 float orig_ofs[3];
1958                 float orig_dist=v3d->dist;
1959                 float orig_lens=v3d->lens;
1960                 float new_dist=0.0;
1961                 float new_lens=35.0;
1962                 float new_quat[4];
1963                 float new_ofs[3];
1964                 
1965                 VECCOPY(orig_ofs, v3d->ofs);
1966                 
1967                 view_settings_from_ob(ob, new_ofs, new_quat, NULL, &new_lens);
1968                 
1969                 G.vd->persp=1;
1970                 smooth_view(v3d, new_ofs, new_quat, &new_dist, &new_lens);
1971                 VECCOPY(v3d->ofs, orig_ofs);
1972                 v3d->lens= orig_lens;
1973                 v3d->dist = orig_dist; /* restore the dist */
1974                 
1975                 v3d->camera = ob;
1976                 v3d->persp=2;
1977         }
1978 }