(no commit message)
[blender-staging.git] / source / blender / src / view.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL 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.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Trackball math (in calctrackballvec())  Copyright (C) Silicon Graphics, Inc.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL LICENSE BLOCK *****
30  */
31
32 #include <math.h>
33 #include <string.h>
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #ifdef WIN32
40 #include <io.h>
41 #else
42 #include <unistd.h>
43 #endif   
44
45 #include "MEM_guardedalloc.h"
46
47 #include "BLI_blenlib.h"
48 #include "BLI_arithb.h"
49
50 #include "DNA_action_types.h"
51 #include "DNA_armature_types.h"
52 #include "DNA_camera_types.h"
53 #include "DNA_lamp_types.h"
54 #include "DNA_object_types.h"
55 #include "DNA_screen_types.h"
56 #include "DNA_scene_types.h"
57 #include "DNA_space_types.h"
58 #include "DNA_userdef_types.h"
59 #include "DNA_view3d_types.h"
60
61 #include "BKE_action.h"
62 #include "BKE_anim.h"
63 #include "BKE_global.h"
64 #include "BKE_main.h"
65 #include "BKE_object.h"
66 #include "BKE_sculpt.h"
67 #include "BKE_utildefines.h"
68
69 #include "BIF_transform.h"
70 #include "BIF_editparticle.h"
71 #include "BIF_gl.h"
72 #include "BIF_previewrender.h"
73 #include "BIF_mywindow.h"
74 #include "BIF_retopo.h"
75 #include "BIF_space.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 #include "transform.h"
90
91 #include "PIL_time.h" /* smoothview */
92 #include <float.h>
93
94 #define TRACKBALLSIZE  (1.1)
95 #define BL_NEAR_CLIP 0.001
96
97 #define COS45 0.70710678118654746
98 #define SIN45 COS45
99
100
101 /* local prototypes ----------*/
102 void setcameratoview3d(void); /* windows.c & toets.c */
103
104 void persp_general(int a)
105 {
106         /* for all window types, not 3D */
107         
108         if(a== 0) {
109                 glPushMatrix();
110                 glMatrixMode(GL_PROJECTION);
111                 glPushMatrix();
112                 glMatrixMode(GL_MODELVIEW);
113
114                 myortho2(-0.375f, ((float)(curarea->winx))-0.375f, -0.375f, ((float)(curarea->winy))-0.375f);
115                 glLoadIdentity();
116         }
117         else if(a== 1) {
118                 glMatrixMode(GL_PROJECTION);
119                 glPopMatrix();
120                 glMatrixMode(GL_MODELVIEW);
121                 glPopMatrix();
122         }
123 }
124
125 void persp(int a)
126 {
127         /* only 3D windows */
128
129         if(curarea->spacetype!=SPACE_VIEW3D) persp_general(a);
130         else if(a == PERSP_STORE) {             // only store
131                 glMatrixMode(GL_PROJECTION);
132                 mygetmatrix(G.vd->winmat1);     
133                 glMatrixMode(GL_MODELVIEW);
134                 mygetmatrix(G.vd->viewmat1); 
135         }
136         else if(a== PERSP_WIN) {                // only set
137                 myortho2(-0.375f, (float)(curarea->winx)-0.375f, -0.375f, (float)(curarea->winy)-0.375f);
138                 glLoadIdentity();
139         }
140         else if(a== PERSP_VIEW) {
141                 glMatrixMode(GL_PROJECTION);
142                 myloadmatrix(G.vd->winmat1); // put back
143                 Mat4CpyMat4(curarea->winmat, G.vd->winmat1); // to be sure? 
144                 glMatrixMode(GL_MODELVIEW); 
145                 myloadmatrix(G.vd->viewmat); // put back
146                 
147         }
148 }
149
150 /* create intersection ray in view Z direction at mouse coordinates */
151 void viewray(short mval[2], float ray_start[3], float ray_normal[3])
152 {
153         float ray_end[3];
154         viewline(mval, ray_start, ray_end);
155         VecSubf(ray_normal, ray_end, ray_start);
156         Normalize(ray_normal);
157 }
158
159 /* create intersection coordinates in view Z direction at mouse coordinates */
160 void viewline(short mval[2], float ray_start[3], float ray_end[3])
161 {
162         float vec[4];
163         
164         if(G.vd->persp != V3D_ORTHO){
165                 vec[0]= 2.0f * mval[0] / curarea->winx - 1;
166                 vec[1]= 2.0f * mval[1] / curarea->winy - 1;
167                 vec[2]= -1.0f;
168                 vec[3]= 1.0f;
169
170                 Mat4MulVec4fl(G.vd->persinv, vec);
171                 VecMulf(vec, 1.0f / vec[3]);
172
173                 VECCOPY(ray_start, G.vd->viewinv[3]);
174                 VECSUB(vec, vec, ray_start);
175                 Normalize(vec);
176
177                 VECADDFAC(ray_start, G.vd->viewinv[3], vec, G.vd->near);
178                 VECADDFAC(ray_end, G.vd->viewinv[3], vec, G.vd->far);
179         }
180         else {
181                 vec[0] = 2.0f * mval[0] / curarea->winx - 1;
182                 vec[1] = 2.0f * mval[1] / curarea->winy - 1;
183                 vec[2] = 0.0f;
184                 vec[3] = 1.0f;
185
186                 Mat4MulVec4fl(G.vd->persinv, vec);
187
188                 VECADDFAC(ray_start, vec, G.vd->viewinv[2],  1000.0f);
189                 VECADDFAC(ray_end, vec, G.vd->viewinv[2], -1000.0f);
190         }
191 }
192
193 void initgrabz(float x, float y, float z)
194 {
195         if(G.vd==NULL) return;
196         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];
197
198         /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that 
199          * (accounting for near zero values)
200          * */
201         if (G.vd->zfac < 1.e-6f && G.vd->zfac > -1.e-6f) G.vd->zfac = 1.0f;
202         
203         /* Negative zfac means x, y, z was behind the camera (in perspective).
204          * This gives flipped directions, so revert back to ok default case.
205          */
206         if (G.vd->zfac < 0.0f) G.vd->zfac = 1.0f;
207 }
208
209 void window_to_3d(float *vec, short mx, short my)
210 {
211         /* always call initgrabz */
212         float dx, dy;
213         
214         dx= 2.0f*mx*G.vd->zfac/curarea->winx;
215         dy= 2.0f*my*G.vd->zfac/curarea->winy;
216         
217         vec[0]= (G.vd->persinv[0][0]*dx + G.vd->persinv[1][0]*dy);
218         vec[1]= (G.vd->persinv[0][1]*dx + G.vd->persinv[1][1]*dy);
219         vec[2]= (G.vd->persinv[0][2]*dx + G.vd->persinv[1][2]*dy);
220 }
221
222 void project_short(float *vec, short *adr)      /* clips */
223 {
224         float fx, fy, vec4[4];
225
226         adr[0]= IS_CLIPPED;
227         
228         if(G.vd->flag & V3D_CLIPPING) {
229                 if(view3d_test_clipping(G.vd, vec))
230                         return;
231         }
232
233         VECCOPY(vec4, vec);
234         vec4[3]= 1.0;
235         Mat4MulVec4fl(G.vd->persmat, vec4);
236         
237         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
238                 fx= (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
239                 
240                 if( fx>0 && fx<curarea->winx) {
241                 
242                         fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
243                         
244                         if(fy>0.0 && fy< (float)curarea->winy) {
245                                 adr[0]= (short)floor(fx); 
246                                 adr[1]= (short)floor(fy);
247                         }
248                 }
249         }
250 }
251
252 void project_int(float *vec, int *adr)
253 {
254         float fx, fy, vec4[4];
255
256         adr[0]= (int)2140000000.0f;
257         VECCOPY(vec4, vec);
258         vec4[3]= 1.0;
259         
260         Mat4MulVec4fl(G.vd->persmat, vec4);
261
262         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
263                 fx= (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
264                 
265                 if( fx>-2140000000.0f && fx<2140000000.0f) {
266                         fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
267                         
268                         if(fy>-2140000000.0f && fy<2140000000.0f) {
269                                 adr[0]= (int)floor(fx); 
270                                 adr[1]= (int)floor(fy);
271                         }
272                 }
273         }
274 }
275
276 void project_int_noclip(float *vec, int *adr)
277 {
278         float fx, fy, vec4[4];
279
280         VECCOPY(vec4, vec);
281         vec4[3]= 1.0;
282         
283         Mat4MulVec4fl(G.vd->persmat, vec4);
284
285         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
286                 fx = (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
287                 fy = (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
288                         
289                 adr[0] = (int)floor(fx); 
290                 adr[1] = (int)floor(fy);
291         }
292         else
293         {
294                 adr[0] = curarea->winx / 2;
295                 adr[1] = curarea->winy / 2;
296         }
297 }
298
299 void project_short_noclip(float *vec, short *adr)
300 {
301         float fx, fy, vec4[4];
302
303         adr[0]= IS_CLIPPED;
304         VECCOPY(vec4, vec);
305         vec4[3]= 1.0;
306         
307         Mat4MulVec4fl(G.vd->persmat, vec4);
308
309         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
310                 fx= (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
311                 
312                 if( fx>-32700 && fx<32700) {
313                 
314                         fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
315                         
316                         if(fy>-32700.0 && fy<32700.0) {
317                                 adr[0]= (short)floor(fx); 
318                                 adr[1]= (short)floor(fy);
319                         }
320                 }
321         }
322 }
323
324 void project_float(float *vec, float *adr)
325 {
326         float vec4[4];
327         
328         adr[0]= IS_CLIPPED;
329         VECCOPY(vec4, vec);
330         vec4[3]= 1.0;
331         
332         Mat4MulVec4fl(G.vd->persmat, vec4);
333
334         if( vec4[3]>BL_NEAR_CLIP ) {
335                 adr[0] = (float)(curarea->winx/2.0)+(curarea->winx/2.0)*vec4[0]/vec4[3];        
336                 adr[1] = (float)(curarea->winy/2.0)+(curarea->winy/2.0)*vec4[1]/vec4[3];
337         }
338 }
339
340 void project_float_noclip(float *vec, float *adr)
341 {
342         float vec4[4];
343
344         VECCOPY(vec4, vec);
345         vec4[3]= 1.0;
346         
347         Mat4MulVec4fl(G.vd->persmat, vec4);
348
349         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
350                 adr[0] = (float)(curarea->winx/2.0)+(curarea->winx/2.0)*vec4[0]/vec4[3];        
351                 adr[1] = (float)(curarea->winy/2.0)+(curarea->winy/2.0)*vec4[1]/vec4[3];
352         }
353         else
354         {
355                 adr[0] = curarea->winx / 2.0f;
356                 adr[1] = curarea->winy / 2.0f;
357         }
358 }
359
360 void view3d_get_object_project_mat(ScrArea *area, Object *ob, float pmat[4][4], float vmat[4][4])
361 {
362         if (area->spacetype!=SPACE_VIEW3D || !area->spacedata.first) {
363                 Mat4One(pmat);
364                 Mat4One(vmat);
365         } else {
366                 View3D *vd = area->spacedata.first;
367
368                 Mat4MulMat4(vmat, ob->obmat, vd->viewmat);
369                 Mat4MulMat4(pmat, vmat, vd->winmat1);
370                 Mat4CpyMat4(vmat, ob->obmat);
371         }
372 }
373
374 /* projectmat brings it to window coords, wmat to rotated world space */
375 void view3d_project_short_clip(ScrArea *area, float *vec, short *adr, float projmat[4][4], float wmat[4][4])
376 {
377         View3D *v3d= area->spacedata.first;
378         float fx, fy, vec4[4];
379
380         adr[0]= IS_CLIPPED;
381         
382         /* clipplanes in eye space */
383         if(v3d->flag & V3D_CLIPPING) {
384                 VECCOPY(vec4, vec);
385                 Mat4MulVecfl(wmat, vec4);
386                 if(view3d_test_clipping(v3d, vec4))
387                         return;
388         }
389         
390         VECCOPY(vec4, vec);
391         vec4[3]= 1.0;
392         
393         Mat4MulVec4fl(projmat, vec4);
394         
395         /* clipplanes in window space */
396         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
397                 fx= (area->winx/2)*(1 + vec4[0]/vec4[3]);
398                 
399                 if( fx>0 && fx<area->winx) {
400                 
401                         fy= (area->winy/2)*(1 + vec4[1]/vec4[3]);
402                         
403                         if(fy>0.0 && fy< (float)area->winy) {
404                                 adr[0]= (short)floor(fx); 
405                                 adr[1]= (short)floor(fy);
406                         }
407                 }
408         }
409 }
410
411 void view3d_project_short_noclip(ScrArea *area, float *vec, short *adr, float mat[4][4])
412 {
413         float fx, fy, vec4[4];
414
415         adr[0]= IS_CLIPPED;
416         
417         VECCOPY(vec4, vec);
418         vec4[3]= 1.0;
419         
420         Mat4MulVec4fl(mat, vec4);
421
422         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
423                 fx= (area->winx/2)*(1 + vec4[0]/vec4[3]);
424                 
425                 if( fx>-32700 && fx<32700) {
426                 
427                         fy= (area->winy/2)*(1 + vec4[1]/vec4[3]);
428                         
429                         if(fy>-32700.0 && fy<32700.0) {
430                                 adr[0]= (short)floor(fx); 
431                                 adr[1]= (short)floor(fy);
432                         }
433                 }
434         }
435 }
436
437 void view3d_project_float(ScrArea *area, float *vec, float *adr, float mat[4][4])
438 {
439         float vec4[4];
440         
441         adr[0]= IS_CLIPPED;
442         VECCOPY(vec4, vec);
443         vec4[3]= 1.0;
444         
445         Mat4MulVec4fl(mat, vec4);
446
447         if( vec4[3]>FLT_EPSILON ) {
448                 adr[0] = (float)(area->winx/2.0f)+(area->winx/2.0f)*vec4[0]/vec4[3];    
449                 adr[1] = (float)(area->winy/2.0f)+(area->winy/2.0f)*vec4[1]/vec4[3];
450         } else {
451                 adr[0] = adr[1] = 0.0f;
452         }
453 }
454
455 int boundbox_clip(float obmat[][4], BoundBox *bb)
456 {
457         /* return 1: draw */
458         
459         float mat[4][4];
460         float vec[4], min, max;
461         int a, flag= -1, fl;
462         
463         if(bb==NULL) return 1;
464         if(bb->flag & OB_BB_DISABLED) return 1;
465         
466         Mat4MulMat4(mat, obmat, G.vd->persmat);
467
468         for(a=0; a<8; a++) {
469                 VECCOPY(vec, bb->vec[a]);
470                 vec[3]= 1.0;
471                 Mat4MulVec4fl(mat, vec);
472                 max= vec[3];
473                 min= -vec[3];
474
475                 fl= 0;
476                 if(vec[0] < min) fl+= 1;
477                 if(vec[0] > max) fl+= 2;
478                 if(vec[1] < min) fl+= 4;
479                 if(vec[1] > max) fl+= 8;
480                 if(vec[2] < min) fl+= 16;
481                 if(vec[2] > max) fl+= 32;
482                 
483                 flag &= fl;
484                 if(flag==0) return 1;
485         }
486
487         return 0;
488
489 }
490
491 void fdrawline(float x1, float y1, float x2, float y2)
492 {
493         float v[2];
494
495         glBegin(GL_LINE_STRIP);
496         v[0] = x1; v[1] = y1;
497         glVertex2fv(v);
498         v[0] = x2; v[1] = y2;
499         glVertex2fv(v);
500         glEnd();
501 }
502
503 void fdrawbox(float x1, float y1, float x2, float y2)
504 {
505         float v[2];
506
507         glBegin(GL_LINE_STRIP);
508
509         v[0] = x1; v[1] = y1;
510         glVertex2fv(v);
511         v[0] = x1; v[1] = y2;
512         glVertex2fv(v);
513         v[0] = x2; v[1] = y2;
514         glVertex2fv(v);
515         v[0] = x2; v[1] = y1;
516         glVertex2fv(v);
517         v[0] = x1; v[1] = y1;
518         glVertex2fv(v);
519
520         glEnd();
521 }
522
523 void sdrawline(short x1, short y1, short x2, short y2)
524 {
525         short v[2];
526
527         glBegin(GL_LINE_STRIP);
528         v[0] = x1; v[1] = y1;
529         glVertex2sv(v);
530         v[0] = x2; v[1] = y2;
531         glVertex2sv(v);
532         glEnd();
533 }
534
535 void sdrawbox(short x1, short y1, short x2, short y2)
536 {
537         short v[2];
538
539         glBegin(GL_LINE_STRIP);
540
541         v[0] = x1; v[1] = y1;
542         glVertex2sv(v);
543         v[0] = x1; v[1] = y2;
544         glVertex2sv(v);
545         v[0] = x2; v[1] = y2;
546         glVertex2sv(v);
547         v[0] = x2; v[1] = y1;
548         glVertex2sv(v);
549         v[0] = x1; v[1] = y1;
550         glVertex2sv(v);
551
552         glEnd();
553 }
554
555 /* the central math in this function was copied from trackball.cpp, sample code from the 
556    Developers Toolbox series by SGI. */
557
558 /* trackball: better one than a full spherical solution */
559
560 void calctrackballvecfirst(rcti *area, short *mval, float *vec)
561 {
562         float x, y, radius, d, z, t;
563         
564         radius= TRACKBALLSIZE;
565         
566         /* normalize x and y */
567         x= (area->xmax + area->xmin)/2 -mval[0];
568         x/= (float)((area->xmax - area->xmin)/2);
569         y= (area->ymax + area->ymin)/2 -mval[1];
570         y/= (float)((area->ymax - area->ymin)/2);
571         
572         d = sqrt(x*x + y*y);
573         if (d < radius*M_SQRT1_2)       /* Inside sphere */
574                 z = sqrt(radius*radius - d*d);
575         else
576         {                       /* On hyperbola */
577                 t = radius / M_SQRT2;
578                 z = t*t / d;
579         }
580
581         vec[0]= x;
582         vec[1]= y;
583         vec[2]= -z;             /* yah yah! */
584
585         if( fabs(vec[2])>fabs(vec[1]) && fabs(vec[2])>fabs(vec[0]) ) {
586                 vec[0]= 0.0;
587                 vec[1]= 0.0;
588                 if(vec[2]>0.0) vec[2]= 1.0; else vec[2]= -1.0;
589         }
590         else if( fabs(vec[1])>fabs(vec[0]) && fabs(vec[1])>fabs(vec[2]) ) {
591                 vec[0]= 0.0;
592                 vec[2]= 0.0;
593                 if(vec[1]>0.0) vec[1]= 1.0; else vec[1]= -1.0;
594         }
595         else  {
596                 vec[1]= 0.0;
597                 vec[2]= 0.0;
598                 if(vec[0]>0.0) vec[0]= 1.0; else vec[0]= -1.0;
599         }
600 }
601
602 void calctrackballvec(rcti *area, short *mval, float *vec)
603 {
604         float x, y, radius, d, z, t;
605         
606         radius= TRACKBALLSIZE;
607         
608         /* x en y normalizeren */
609         x= (area->xmax + area->xmin)/2 -mval[0];
610         x/= (float)((area->xmax - area->xmin)/4);
611         y= (area->ymax + area->ymin)/2 -mval[1];
612         y/= (float)((area->ymax - area->ymin)/2);
613         
614         d = sqrt(x*x + y*y);
615         if (d < radius*M_SQRT1_2)       /* Inside sphere */
616                 z = sqrt(radius*radius - d*d);
617         else
618         {                       /* On hyperbola */
619                 t = radius / M_SQRT2;
620                 z = t*t / d;
621         }
622
623         vec[0]= x;
624         vec[1]= y;
625         vec[2]= -z;             /* yah yah! */
626
627 }
628
629
630 // ndof scaling will be moved to user setting.
631 // In the mean time this is just a place holder.
632
633 // Note: scaling in the plugin and ghostwinlay.c
634 // should be removed. With driver default setting,
635 // each axis returns approx. +-200 max deflection.
636
637 // The values I selected are based on the older
638 // polling i/f. With event i/f, the sensistivity
639 // can be increased for improved response from
640 // small deflections of the device input.
641
642
643 // lukep notes : i disagree on the range.
644 // the normal 3Dconnection driver give +/-400
645 // on defaut range in other applications
646 // and up to +/- 1000 if set to maximum
647 // because i remove the scaling by delta,
648 // which was a bad idea as it depend of the system
649 // speed and os, i changed the scaling values, but 
650 // those are still not ok
651
652
653 float ndof_axis_scale[6] = {
654         +0.01,  // Tx
655         +0.01,  // Tz
656         +0.01,  // Ty
657         +0.0015,        // Rx
658         +0.0015,        // Rz
659         +0.0015 // Ry
660 };
661
662 // statics for controlling G.vd->dist corrections.
663 // viewmoveNDOF zeros and adjusts G.vd->ofs.
664 // viewmove restores based on dz_flag state.
665
666 int dz_flag = 0;
667 float m_dist;
668
669 void viewmoveNDOFfly(int mode)
670 {
671     int i;
672     float phi;
673     float dval[7];
674         // static fval[6] for low pass filter; device input vector is dval[6]
675         static float fval[6];
676     float tvec[3],rvec[3];
677     float q1[4];
678         float mat[3][3];
679         float upvec[3];
680
681
682     /*----------------------------------------------------
683          * sometimes this routine is called from headerbuttons
684      * viewmove needs to refresh the screen
685      */
686         areawinset(curarea->win);
687
688
689         // fetch the current state of the ndof device
690         getndof(dval);
691
692         if (G.vd->ndoffilter)
693                 filterNDOFvalues(fval);
694
695         // Scale input values
696
697 //      if(dval[6] == 0) return; // guard against divide by zero
698
699         for(i=0;i<6;i++) {
700
701                 // user scaling
702                 dval[i] = dval[i] * ndof_axis_scale[i];
703         }
704
705
706         // low pass filter with zero crossing reset
707
708         for(i=0;i<6;i++) {
709                 if((dval[i] * fval[i]) >= 0)
710                         dval[i] = (fval[i] * 15 + dval[i]) / 16;
711                 else
712                         fval[i] = 0;
713         }
714
715
716         // force perspective mode. This is a hack and is
717         // incomplete. It doesn't actually effect the view
718         // until the first draw and doesn't update the menu
719         // to reflect persp mode.
720
721         G.vd->persp = V3D_PERSP;
722
723
724         // Correct the distance jump if G.vd->dist != 0
725
726         // This is due to a side effect of the original
727         // mouse view rotation code. The rotation point is
728         // set a distance in front of the viewport to
729         // make rotating with the mouse look better.
730         // The distance effect is written at a low level
731         // in the view management instead of the mouse
732         // view function. This means that all other view
733         // movement devices must subtract this from their
734         // view transformations.
735
736         if(G.vd->dist != 0.0) {
737                 dz_flag = 1;
738                 m_dist = G.vd->dist;
739                 upvec[0] = upvec[1] = 0;
740                 upvec[2] = G.vd->dist;
741                 Mat3CpyMat4(mat, G.vd->viewinv);
742                 Mat3MulVecfl(mat, upvec);
743                 VecSubf(G.vd->ofs, G.vd->ofs, upvec);
744                 G.vd->dist = 0.0;
745         }
746
747
748         // Apply rotation
749         // Rotations feel relatively faster than translations only in fly mode, so
750         // we have no choice but to fix that here (not in the plugins)
751         rvec[0] = -0.5 * dval[3];
752         rvec[1] = -0.5 * dval[4];
753         rvec[2] = -0.5 * dval[5];
754
755         // rotate device x and y by view z
756
757         Mat3CpyMat4(mat, G.vd->viewinv);
758         mat[2][2] = 0.0f;
759         Mat3MulVecfl(mat, rvec);
760
761         // rotate the view
762
763         phi = Normalize(rvec);
764         if(phi != 0) {
765                 VecRotToQuat(rvec,phi,q1);
766                 QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
767         }
768
769
770         // Apply translation
771
772         tvec[0] = dval[0];
773         tvec[1] = dval[1];
774         tvec[2] = -dval[2];
775
776         // the next three lines rotate the x and y translation coordinates
777         // by the current z axis angle
778
779         Mat3CpyMat4(mat, G.vd->viewinv);
780         mat[2][2] = 0.0f;
781         Mat3MulVecfl(mat, tvec);
782
783         // translate the view
784
785         VecSubf(G.vd->ofs, G.vd->ofs, tvec);
786
787
788         /*----------------------------------------------------
789      * refresh the screen
790      */
791     scrarea_do_windraw(curarea);
792     screen_swapbuffers();
793
794         // update render preview window
795
796         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
797 }
798
799 int view_autodist( float mouse_worldloc[3] ) //, float *autodist )
800 {
801         View3D *v3d = G.vd;
802         
803         /* Zooms in on a border drawn by the user */
804         short mval[2];
805         rcti rect;
806         
807         /* ZBuffer depth vars */
808         bglMats mats;
809         float depth, depth_close= MAXFLOAT;
810         int had_depth = 0;
811         double cent[2],  p[3];
812         int xs, ys;
813         
814         getmouseco_areawin(mval);
815         
816         persp(PERSP_VIEW);
817         
818         rect.xmax = mval[0] + 4;
819         rect.ymax = mval[1] + 4;
820         
821         rect.xmin = mval[0] - 4;
822         rect.ymin = mval[1] - 4;
823         
824         /* Get Z Depths, needed for perspective, nice for ortho */
825         bgl_get_mats(&mats);
826         draw_depth(curarea, (void *)v3d, NULL);
827         
828         /* force updating */
829         if (v3d->depths) {
830                 had_depth = 1;
831                 v3d->depths->damaged = 1;
832         }
833         
834         view3d_update_depths(v3d);
835         
836         /* Constrain rect to depth bounds */
837         if (rect.xmin < 0) rect.xmin = 0;
838         if (rect.ymin < 0) rect.ymin = 0;
839         if (rect.xmax >= v3d->depths->w) rect.xmax = v3d->depths->w-1;
840         if (rect.ymax >= v3d->depths->h) rect.ymax = v3d->depths->h-1;          
841         
842         /* Find the closest Z pixel */
843         for (xs=rect.xmin; xs < rect.xmax; xs++) {
844                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
845                         depth= v3d->depths->depths[ys*v3d->depths->w+xs];
846                         if(depth < v3d->depths->depth_range[1] && depth > v3d->depths->depth_range[0]) {
847                                 if (depth_close > depth) {
848                                         depth_close = depth;
849                                 }
850                         }
851                 }
852         }
853         
854         if (depth_close==MAXFLOAT)
855                 return 0;
856                 
857         if (had_depth==0) {
858                 MEM_freeN(v3d->depths->depths);
859                 v3d->depths->depths = NULL;
860         }
861         v3d->depths->damaged = 1;
862         
863         cent[0] = (double)mval[0];
864         cent[1] = (double)mval[1];
865         
866         if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, mats.viewport, &p[0], &p[1], &p[2]))
867                 return 0;
868
869         mouse_worldloc[0] = (float)p[0];
870         mouse_worldloc[1] = (float)p[1];
871         mouse_worldloc[2] = (float)p[2];
872         return 1;
873 }
874
875 void viewmove(int mode)
876 {
877         static float lastofs[3] = {0,0,0};
878         Object *ob = OBACT;
879         float firstvec[3], newvec[3], dvec[3];
880         float reverse, oldquat[4], q1[4], si, phi, dist0;
881         float ofs[3], obofs[3]= {0.0f, 0.0f, 0.0f};
882         int firsttime=1;
883         short mvalball[2], mval[2], mvalo[2], mval_area[2], mvali[2];
884         short use_sel = 0;
885         short preview3d_event= 1;
886         
887         // locals for dist correction
888         float mat[3][3];
889         float upvec[3];
890
891                 /* 3D window may not be defined */
892         if( !G.vd ) {
893                 fprintf( stderr, "G.vd == NULL in viewmove()\n" );
894                 return;
895         }
896         
897         // dist correction from other movement devices  
898         if((dz_flag)||G.vd->dist==0) {
899                 dz_flag = 0;
900                 G.vd->dist = m_dist;
901                 upvec[0] = upvec[1] = 0;
902                 upvec[2] = G.vd->dist;
903                 Mat3CpyMat4(mat, G.vd->viewinv);
904                 Mat3MulVecfl(mat, upvec);
905                 VecAddf(G.vd->ofs, G.vd->ofs, upvec);
906         }
907                 
908         /* sometimes this routine is called from headerbuttons */
909
910         areawinset(curarea->win);
911         
912         QUATCOPY(oldquat, G.vd->viewquat);
913         
914         getmouseco_areawin(mval_area);  /* for zoom to mouse loc */
915         getmouseco_sc(mvali);           /* work with screen coordinates because of trackball function */
916         mvalball[0]= mvalo[0] = mvali[0];                       /* needed for turntable to work */
917         mvalball[1]= mvalo[1] = mvali[1];
918         dist0= G.vd->dist;
919         
920         calctrackballvec(&curarea->winrct, mvalo, firstvec);
921
922         /* cumultime(0); */
923
924         if(!G.obedit && (G.f & G_SCULPTMODE) && ob && G.vd->pivot_last) {
925                 use_sel= 1;
926                 VecCopyf(ofs, G.vd->ofs);
927
928                 VecCopyf(obofs, sculpt_data()->pivot);
929                 Mat4MulVecfl(ob->obmat, obofs);
930                 obofs[0]= -obofs[0];
931                 obofs[1]= -obofs[1];
932                 obofs[2]= -obofs[2];
933         }
934         else if (U.uiflag & USER_ORBIT_SELECTION) {
935                 use_sel = 1;
936                 
937                 VECCOPY(ofs, G.vd->ofs);
938                 
939                 /* If there's no selection, lastofs is unmodified and last value since static */
940                 calculateTransformCenter(V3D_CENTROID, lastofs);
941                 
942                 VECCOPY(obofs, lastofs);
943                 VecMulf(obofs, -1.0f);
944         }
945         else if (U.uiflag & USER_ORBIT_ZBUF) {
946                 if ((use_sel=view_autodist(obofs))) {
947                         if (G.vd->persp==V3D_PERSP) {
948                                 float my_origin[3]; /* original G.vd->ofs */
949                                 float my_pivot[3]; /* view */
950                                 
951                                 VECCOPY(my_origin, G.vd->ofs);
952                                 VecMulf(my_origin, -1.0f);                              /* ofs is flipped */
953                                 
954                                 /* Set the dist value to be the distance from this 3d point */
955                                 /* this means youll always be able to zoom into it and panning wont go bad when dist was zero */
956                                 
957                                 /* remove dist value */                 
958                                 upvec[0] = upvec[1] = 0;
959                                 upvec[2] = G.vd->dist;
960                                 Mat3CpyMat4(mat, G.vd->viewinv);
961                                 Mat3MulVecfl(mat, upvec);
962                                 VecSubf(my_pivot, G.vd->ofs, upvec);
963                                 VecMulf(my_pivot, -1.0f);                               /* ofs is flipped */
964                                 
965                                 /* find a new ofs value that is allong the view axis (rather then the mouse location) */
966                                 lambda_cp_line_ex(obofs, my_pivot, my_origin, dvec);
967                                 dist0 = G.vd->dist = VecLenf(my_pivot, dvec);
968                                 
969                                 VecMulf(dvec, -1.0f);
970                                 VECCOPY(G.vd->ofs, dvec);
971                         }
972                         VecMulf(obofs, -1.0f);
973                         VECCOPY(ofs, G.vd->ofs);
974                 } else {
975                         ofs[0] = ofs[1] = ofs[2] = 0.0f;
976                 }
977         }
978         else
979                 ofs[0] = ofs[1] = ofs[2] = 0.0f;
980         
981         initgrabz(-G.vd->ofs[0], -G.vd->ofs[1], -G.vd->ofs[2]);
982         
983         reverse= 1.0f;
984         if (G.vd->persmat[2][1] < 0.0f)
985                 reverse= -1.0f;
986
987         while(TRUE) {
988                 getmouseco_sc(mval);
989                 
990                 // if playanim = alt+A, screenhandlers are for animated UI, python, etc
991                 if(             (mode==2 && U.viewzoom==USER_ZOOM_CONT) || /* continues zoom always update */
992                                 mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || /* mouse moved, so update */
993                                 (G.f & G_PLAYANIM) || do_screenhandlers(G.curscreen)
994                         ) {
995                         
996                         if(firsttime) {
997                                 
998                                 firsttime= 0;
999                                 /* are we translating, rotating or zooming? */
1000                                 if(mode==0) {
1001                                         if(G.vd->view!=0) scrarea_queue_headredraw(curarea);    /*for button */
1002                                 }
1003                                 if(G.vd->persp==V3D_CAMOB && mode!=1 && G.vd->camera) {
1004                                         G.vd->persp= V3D_PERSP;
1005                                         scrarea_do_windraw(curarea);
1006                                         scrarea_queue_headredraw(curarea);
1007                                 }
1008                         }
1009
1010                         if(mode==0) {   /* view rotate */
1011                                 G.vd->view= 0; /* need to reset everytime because of view snapping */
1012                 
1013                                 if (U.uiflag & USER_AUTOPERSP) G.vd->persp= V3D_PERSP;
1014
1015                                 if (U.flag & USER_TRACKBALL) mvalball[0]= mval[0];
1016                                 mvalball[1]= mval[1];
1017                                 
1018                                 calctrackballvec(&curarea->winrct, mvalball, newvec);
1019                                 
1020                                 VecSubf(dvec, newvec, firstvec);
1021                                 
1022                                 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
1023                                 si/= (2.0*TRACKBALLSIZE);
1024                         
1025                                 if (U.flag & USER_TRACKBALL) {
1026                                         Crossf(q1+1, firstvec, newvec);
1027         
1028                                         Normalize(q1+1);
1029         
1030                                         /* Allow for rotation beyond the interval
1031                                          * [-pi, pi] */
1032                                         while (si > 1.0)
1033                                                 si -= 2.0;
1034                 
1035                                         /* This relation is used instead of
1036                                          * phi = asin(si) so that the angle
1037                                          * of rotation is linearly proportional
1038                                          * to the distance that the mouse is
1039                                          * dragged. */
1040                                         phi = si * M_PI / 2.0;
1041                 
1042                                         si= sin(phi);
1043                                         q1[0]= cos(phi);
1044                                         q1[1]*= si;
1045                                         q1[2]*= si;
1046                                         q1[3]*= si;     
1047                                         QuatMul(G.vd->viewquat, q1, oldquat);
1048
1049                                         if (use_sel) {
1050                                                 /* compute the post multiplication quat, to rotate the offset correctly */
1051                                                 QUATCOPY(q1, oldquat);
1052                                                 QuatConj(q1);
1053                                                 QuatMul(q1, q1, G.vd->viewquat);
1054
1055                                                 QuatConj(q1); /* conj == inv for unit quat */
1056                                                 VECCOPY(G.vd->ofs, ofs);
1057                                                 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
1058                                                 QuatMulVecf(q1, G.vd->ofs);
1059                                                 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
1060                                         }
1061                                 } else {
1062                                         /* New turntable view code by John Aughey */
1063
1064                                         float m[3][3];
1065                                         float m_inv[3][3];
1066                                         float xvec[3] = {1,0,0};
1067                                         /* Sensitivity will control how fast the viewport rotates.  0.0035 was
1068                                            obtained experimentally by looking at viewport rotation sensitivities
1069                                            on other modeling programs. */
1070                                         /* Perhaps this should be a configurable user parameter. */
1071                                         const float sensitivity = 0.0035;
1072
1073                                         /* Get the 3x3 matrix and its inverse from the quaternion */
1074                                         QuatToMat3(G.vd->viewquat, m);
1075                                         Mat3Inv(m_inv,m);
1076
1077                                         /* Determine the direction of the x vector (for rotating up and down) */
1078                                         /* This can likely be compuated directly from the quaternion. */
1079                                         Mat3MulVecfl(m_inv,xvec);
1080
1081                                         /* Perform the up/down rotation */
1082                                         phi = sensitivity * -(mval[1] - mvalo[1]);
1083                                         si = sin(phi);
1084                                         q1[0] = cos(phi);
1085                                         q1[1] = si * xvec[0];
1086                                         q1[2] = si * xvec[1];
1087                                         q1[3] = si * xvec[2];
1088                                         QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
1089
1090                                         if (use_sel) {
1091                                                 QuatConj(q1); /* conj == inv for unit quat */
1092                                                 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
1093                                                 QuatMulVecf(q1, G.vd->ofs);
1094                                                 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
1095                                         }
1096
1097                                         /* Perform the orbital rotation */
1098                                         phi = sensitivity * reverse * (mval[0] - mvalo[0]);
1099                                         q1[0] = cos(phi);
1100                                         q1[1] = q1[2] = 0.0;
1101                                         q1[3] = sin(phi);
1102                                         QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
1103
1104                                         if (use_sel) {
1105                                                 QuatConj(q1);
1106                                                 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
1107                                                 QuatMulVecf(q1, G.vd->ofs);
1108                                                 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
1109                                         }
1110                                 }
1111                                 
1112                                 /* check for view snap */
1113                                 if (G.qual==LR_CTRLKEY){
1114                                         int i;
1115                                         float viewmat[3][3];
1116
1117                                         static const float thres = 0.93f; //cos(20 deg);
1118                                         
1119                                         static float snapquats[39][6] = {
1120                                                 /*{q0, q1, q3, q4, view, oposite_direction}*/
1121                                                 {COS45, -SIN45, 0.0, 0.0, 1, 0},  //front
1122                                                 {0.0, 0.0, -SIN45, -SIN45, 1, 1}, //back
1123                                                 {1.0, 0.0, 0.0, 0.0, 7, 0},       //top
1124                                                 {0.0, -1.0, 0.0, 0.0, 7, 1},      //bottom
1125                                                 {0.5, -0.5, -0.5, -0.5, 3, 0},    //left
1126                                                 {0.5, -0.5, 0.5, 0.5, 3, 1},      //right
1127                                                 
1128                                                 /* some more 45 deg snaps */
1129                                                 {0.65328145027160645, -0.65328145027160645, 0.27059805393218994, 0.27059805393218994, 0, 0},
1130                                                 {0.92387950420379639, 0.0, 0.0, 0.38268342614173889, 0, 0},
1131                                                 {0.0, -0.92387950420379639, 0.38268342614173889, 0.0, 0, 0},
1132                                                 {0.35355335474014282, -0.85355335474014282, 0.35355338454246521, 0.14644660055637360, 0, 0},
1133                                                 {0.85355335474014282, -0.35355335474014282, 0.14644660055637360, 0.35355338454246521, 0, 0},
1134                                                 {0.49999994039535522, -0.49999994039535522, 0.49999997019767761, 0.49999997019767761, 0, 0},
1135                                                 {0.27059802412986755, -0.65328145027160645, 0.65328145027160645, 0.27059802412986755, 0, 0},
1136                                                 {0.65328145027160645, -0.27059802412986755, 0.27059802412986755, 0.65328145027160645, 0, 0},
1137                                                 {0.27059799432754517, -0.27059799432754517, 0.65328139066696167, 0.65328139066696167, 0, 0},
1138                                                 {0.38268336653709412, 0.0, 0.0, 0.92387944459915161, 0, 0},
1139                                                 {0.0, -0.38268336653709412, 0.92387944459915161, 0.0, 0, 0},
1140                                                 {0.14644658565521240, -0.35355335474014282, 0.85355335474014282, 0.35355335474014282, 0, 0},
1141                                                 {0.35355335474014282, -0.14644658565521240, 0.35355335474014282, 0.85355335474014282, 0, 0},
1142                                                 {0.0, 0.0, 0.92387944459915161, 0.38268336653709412, 0, 0},
1143                                                 {-0.0, 0.0, 0.38268336653709412, 0.92387944459915161, 0, 0},
1144                                                 {-0.27059802412986755, 0.27059802412986755, 0.65328133106231689, 0.65328133106231689, 0, 0},
1145                                                 {-0.38268339633941650, 0.0, 0.0, 0.92387938499450684, 0, 0},
1146                                                 {0.0, 0.38268339633941650, 0.92387938499450684, 0.0, 0, 0},
1147                                                 {-0.14644658565521240, 0.35355338454246521, 0.85355329513549805, 0.35355332493782043, 0, 0},
1148                                                 {-0.35355338454246521, 0.14644658565521240, 0.35355332493782043, 0.85355329513549805, 0, 0},
1149                                                 {-0.49999991059303284, 0.49999991059303284, 0.49999985098838806, 0.49999985098838806, 0, 0},
1150                                                 {-0.27059799432754517, 0.65328145027160645, 0.65328139066696167, 0.27059799432754517, 0, 0},
1151                                                 {-0.65328145027160645, 0.27059799432754517, 0.27059799432754517, 0.65328139066696167, 0, 0},
1152                                                 {-0.65328133106231689, 0.65328133106231689, 0.27059793472290039, 0.27059793472290039, 0, 0},
1153                                                 {-0.92387932538986206, 0.0, 0.0, 0.38268333673477173, 0, 0},
1154                                                 {0.0, 0.92387932538986206, 0.38268333673477173, 0.0, 0, 0},
1155                                                 {-0.35355329513549805, 0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0, 0},
1156                                                 {-0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0.35355329513549805, 0, 0},
1157                                                 {-0.38268330693244934, 0.92387938499450684, 0.0, 0.0, 0, 0},
1158                                                 {-0.92387938499450684, 0.38268330693244934, 0.0, 0.0, 0, 0},
1159                                                 {-COS45, 0.0, 0.0, SIN45, 0, 0},
1160                                                 {COS45, 0.0, 0.0, SIN45, 0, 0},
1161                                                 {0.0, 0.0, 0.0, 1.0, 0, 0}
1162                                         };
1163
1164                                         QuatToMat3(G.vd->viewquat, viewmat);
1165
1166                                         for (i = 0 ; i < 39; i++){
1167                                                 float snapmat[3][3];
1168                                                 float view = (int)snapquats[i][4];
1169                                                 float oposite_dir = (int)snapquats[i][5];
1170                                                 
1171                                                 QuatToMat3(snapquats[i], snapmat);
1172                                                 
1173                                                 if ((Inpf(snapmat[0], viewmat[0]) > thres) &&
1174                                                         (Inpf(snapmat[1], viewmat[1]) > thres) &&
1175                                                         (Inpf(snapmat[2], viewmat[2]) > thres)){
1176                                                         
1177                                                         QUATCOPY(G.vd->viewquat, snapquats[i]);
1178                                                         
1179                                                         G.vd->view = view;
1180                                                         if (view){
1181                                                                 if (oposite_dir){
1182                                                                         G.vd->flag2 |= V3D_OPP_DIRECTION_NAME;
1183                                                                 }else{
1184                                                                         G.vd->flag2 &= ~V3D_OPP_DIRECTION_NAME;
1185                                                                 }
1186                                                         }
1187                                                         
1188                                                         break;
1189                                                 }
1190                                         }
1191                                 }
1192                         }
1193                         else if(mode==1) {      /* translate */
1194                                 if(G.vd->persp==V3D_CAMOB) {
1195                                         float max= (float)MAX2(curarea->winx, curarea->winy);
1196
1197                                         G.vd->camdx += (mvalo[0]-mval[0])/(max);
1198                                         G.vd->camdy += (mvalo[1]-mval[1])/(max);
1199                                         CLAMP(G.vd->camdx, -1.0f, 1.0f);
1200                                         CLAMP(G.vd->camdy, -1.0f, 1.0f);
1201                                         preview3d_event= 0;
1202                                 }
1203                                 else {
1204                                         window_to_3d(dvec, mval[0]-mvalo[0], mval[1]-mvalo[1]);
1205                                         VecAddf(G.vd->ofs, G.vd->ofs, dvec);
1206                                 }
1207                         }
1208                         else if(mode==2) {
1209                                 float zfac=1.0;
1210
1211                                 /* use initial value (do not use mvalo (that is used to detect mouse moviments)) */
1212                                 mvalo[0] = mvali[0];
1213                                 mvalo[1] = mvali[1];
1214                                 
1215                                 if(U.viewzoom==USER_ZOOM_CONT) {
1216                                         // oldstyle zoom
1217                                         zfac = 1.0+(float)(mvalo[0]-mval[0]+mvalo[1]-mval[1])/1000.0;
1218                                 }
1219                                 else if(U.viewzoom==USER_ZOOM_SCALE) {
1220                                         int ctr[2], len1, len2;
1221                                         // method which zooms based on how far you move the mouse
1222                                         
1223                                         ctr[0] = (curarea->winrct.xmax + curarea->winrct.xmin)/2;
1224                                         ctr[1] = (curarea->winrct.ymax + curarea->winrct.ymin)/2;
1225                                         
1226                                         len1 = (int)sqrt((ctr[0] - mval[0])*(ctr[0] - mval[0]) + (ctr[1] - mval[1])*(ctr[1] - mval[1])) + 5;
1227                                         len2 = (int)sqrt((ctr[0] - mvalo[0])*(ctr[0] - mvalo[0]) + (ctr[1] - mvalo[1])*(ctr[1] - mvalo[1])) + 5;
1228                                         
1229                                         zfac = dist0 * ((float)len2/len1) / G.vd->dist;
1230                                 }
1231                                 else {  /* USER_ZOOM_DOLLY */
1232                                         float len1 = (curarea->winrct.ymax - mval[1]) + 5;
1233                                         float len2 = (curarea->winrct.ymax - mvalo[1]) + 5;
1234                                         zfac = dist0 * (2.0*((len2/len1)-1.0) + 1.0) / G.vd->dist;
1235                                 }
1236
1237                                 if(zfac != 1.0 && zfac*G.vd->dist > 0.001*G.vd->grid && 
1238                                         zfac*G.vd->dist < 10.0*G.vd->far)
1239                                         view_zoom_mouseloc(zfac, mval_area);
1240                                 
1241                                 
1242                                 if ((U.uiflag & USER_ORBIT_ZBUF) && (U.viewzoom==USER_ZOOM_CONT) && (G.vd->persp==V3D_PERSP)) {
1243                                         /* Secret apricot feature, translate the view when in continues mode */
1244                                         upvec[0] = upvec[1] = 0;
1245                                         upvec[2] = (dist0 - G.vd->dist) * G.vd->grid;
1246                                         G.vd->dist = dist0;
1247                                         Mat3CpyMat4(mat, G.vd->viewinv);
1248                                         Mat3MulVecfl(mat, upvec);
1249                                         VecAddf(G.vd->ofs, G.vd->ofs, upvec);
1250                                 } else {
1251                                         /* these limits are in toets.c too */
1252                                         if(G.vd->dist<0.001*G.vd->grid) G.vd->dist= 0.001*G.vd->grid;
1253                                         if(G.vd->dist>10.0*G.vd->far) G.vd->dist=10.0*G.vd->far;
1254                                 }
1255                                 
1256                                 if(G.vd->persp==V3D_ORTHO || G.vd->persp==V3D_CAMOB) preview3d_event= 0;
1257                         }
1258                         
1259                         
1260                         
1261                         mvalo[0]= mval[0];
1262                         mvalo[1]= mval[1];
1263
1264                         if(G.f & G_PLAYANIM) inner_play_anim_loop(0, 0);
1265
1266                         /* If in retopo paint mode, update lines */
1267                         if(retopo_mesh_paint_check() && G.vd->retopo_view_data) {
1268                                 G.vd->retopo_view_data->queue_matrix_update= 1;
1269                                 retopo_paint_view_update(G.vd);
1270                         }
1271
1272                         scrarea_do_windraw(curarea);
1273                         screen_swapbuffers();
1274                 }
1275                 else {
1276                         short val;
1277                         unsigned short event;
1278                         /* we need to empty the queue... when you do this very long it overflows */
1279                         while(qtest()) event= extern_qread(&val);
1280                         
1281                         BIF_wait_for_statechange();
1282                 }
1283                 
1284                 /* this in the end, otherwise get_mbut does not work on a PC... */
1285                 if( !(get_mbut() & (L_MOUSE|M_MOUSE))) break;
1286         }
1287
1288         if(G.vd->depths) G.vd->depths->damaged= 1;
1289         retopo_queue_updates(G.vd);
1290         allqueue(REDRAWVIEW3D, 0);
1291
1292         if(preview3d_event) 
1293                 BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1294         else
1295                 BIF_view3d_previewrender_signal(curarea, PR_PROJECTED);
1296
1297 }
1298  
1299 void view_zoom_mouseloc(float dfac, short *mouseloc)
1300 {
1301         if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
1302                 short vb[2];
1303                 float dvec[3];
1304                 float tvec[3];
1305                 float tpos[3];
1306                 float new_dist;
1307
1308                 /* find the current window width and height */
1309                 vb[0] = G.vd->area->winx;
1310                 vb[1] = G.vd->area->winy;
1311                 
1312                 tpos[0] = -G.vd->ofs[0];
1313                 tpos[1] = -G.vd->ofs[1];
1314                 tpos[2] = -G.vd->ofs[2];
1315
1316                 /* Project cursor position into 3D space */
1317                 initgrabz(tpos[0], tpos[1], tpos[2]);
1318                 window_to_3d(dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2);
1319
1320                 /* Calculate view target position for dolly */
1321                 tvec[0] = -(tpos[0] + dvec[0]);
1322                 tvec[1] = -(tpos[1] + dvec[1]);
1323                 tvec[2] = -(tpos[2] + dvec[2]);
1324
1325                 /* Offset to target position and dolly */
1326                 new_dist = G.vd->dist * dfac;
1327                 
1328                 VECCOPY(G.vd->ofs, tvec);
1329                 G.vd->dist = new_dist;
1330                 
1331                 /* Calculate final offset */
1332                 dvec[0] = tvec[0] + dvec[0] * dfac;
1333                 dvec[1] = tvec[1] + dvec[1] * dfac;
1334                 dvec[2] = tvec[2] + dvec[2] * dfac;
1335                 
1336                 VECCOPY(G.vd->ofs, dvec);
1337         } else {
1338                 G.vd->dist *= dfac;
1339         }
1340 }
1341
1342 void viewmoveNDOF(int mode)
1343 {
1344     float fval[7];
1345     float dvec[3];
1346     float sbadjust = 1.0f;
1347     float len;
1348         short use_sel = 0;
1349         Object *ob = OBACT;
1350     float m[3][3];
1351     float m_inv[3][3];
1352     float xvec[3] = {1,0,0};
1353     float yvec[3] = {0,-1,0};
1354     float zvec[3] = {0,0,1};
1355         float phi, si;
1356     float q1[4];
1357     float obofs[3];
1358     float reverse;
1359     //float diff[4];
1360     float d, curareaX, curareaY;
1361     float mat[3][3];
1362     float upvec[3];
1363
1364     /* Sensitivity will control how fast the view rotates.  The value was
1365      * obtained experimentally by tweaking until the author didn't get dizzy watching.
1366      * Perhaps this should be a configurable user parameter. 
1367      */
1368     float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
1369     float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
1370     float zsens = 0.3f;   /* zoom sensitivity */
1371
1372     const float minZoom = -30.0f;
1373     const float maxZoom = 300.0f;
1374
1375         //reset view type
1376         G.vd->view = 0;
1377 //printf("passing here \n");
1378 //
1379         if (G.obedit==NULL && ob && !(ob->flag & OB_POSEMODE)) {
1380                 use_sel = 1;
1381         }
1382
1383     if((dz_flag)||G.vd->dist==0) {
1384                 dz_flag = 0;
1385                 G.vd->dist = m_dist;
1386                 upvec[0] = upvec[1] = 0;
1387                 upvec[2] = G.vd->dist;
1388                 Mat3CpyMat4(mat, G.vd->viewinv);
1389                 Mat3MulVecfl(mat, upvec);
1390                 VecAddf(G.vd->ofs, G.vd->ofs, upvec);
1391         }
1392
1393     /*----------------------------------------------------
1394          * sometimes this routine is called from headerbuttons
1395      * viewmove needs to refresh the screen
1396      */
1397         areawinset(curarea->win);
1398
1399     /*----------------------------------------------------
1400      * record how much time has passed. clamp at 10 Hz
1401      * pretend the previous frame occured at the clamped time 
1402      */
1403 //    now = PIL_check_seconds_timer();
1404  //   frametime = (now - prevTime);
1405  //   if (frametime > 0.1f){        /* if more than 1/10s */
1406  //       frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
1407 //    }
1408 //    prevTime = now;
1409  //   sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
1410
1411     /* fetch the current state of the ndof device & enforce dominant mode if selected */
1412     getndof(fval);
1413         if (G.vd->ndoffilter)
1414                 filterNDOFvalues(fval);
1415         
1416         
1417     // put scaling back here, was previously in ghostwinlay
1418     fval[0] = fval[0] * (1.0f/600.0f);
1419     fval[1] = fval[1] * (1.0f/600.0f);
1420     fval[2] = fval[2] * (1.0f/1100.0f);
1421     fval[3] = fval[3] * 0.00005f;
1422     fval[4] =-fval[4] * 0.00005f;
1423     fval[5] = fval[5] * 0.00005f;
1424     fval[6] = fval[6] / 1000000.0f;
1425                         
1426     // scale more if not in perspective mode
1427     if (G.vd->persp == V3D_ORTHO) {
1428         fval[0] = fval[0] * 0.05f;
1429         fval[1] = fval[1] * 0.05f;
1430         fval[2] = fval[2] * 0.05f;
1431         fval[3] = fval[3] * 0.9f;
1432         fval[4] = fval[4] * 0.9f;
1433         fval[5] = fval[5] * 0.9f;
1434         zsens *= 8;
1435     }
1436                         
1437         
1438     /* set object offset */
1439         if (ob) {
1440                 obofs[0] = -ob->obmat[3][0];
1441                 obofs[1] = -ob->obmat[3][1];
1442                 obofs[2] = -ob->obmat[3][2];
1443         }
1444         else {
1445                 VECCOPY(obofs, G.vd->ofs);
1446         }
1447
1448     /* calc an adjustment based on distance from camera
1449        disabled per patch 14402 */
1450      d = 1.0f;
1451
1452 /*    if (ob) {
1453         VecSubf(diff, obofs, G.vd->ofs);
1454         d = VecLength(diff);
1455     }
1456 */
1457
1458     reverse = (G.vd->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
1459
1460     /*----------------------------------------------------
1461      * ndof device pan 
1462      */
1463     psens *= 1.0f + d;
1464     curareaX = sbadjust * psens * fval[0];
1465     curareaY = sbadjust * psens * fval[1];
1466     dvec[0] = curareaX * G.vd->persinv[0][0] + curareaY * G.vd->persinv[1][0];
1467     dvec[1] = curareaX * G.vd->persinv[0][1] + curareaY * G.vd->persinv[1][1];
1468     dvec[2] = curareaX * G.vd->persinv[0][2] + curareaY * G.vd->persinv[1][2];
1469     VecAddf(G.vd->ofs, G.vd->ofs, dvec);
1470
1471     /*----------------------------------------------------
1472      * ndof device dolly 
1473      */
1474     len = zsens * sbadjust * fval[2];
1475
1476     if (G.vd->persp==V3D_CAMOB) {
1477         if(G.vd->persp==V3D_CAMOB) { /* This is stupid, please fix - TODO */
1478             G.vd->camzoom+= 10.0f * -len;
1479         }
1480         if (G.vd->camzoom < minZoom) G.vd->camzoom = minZoom;
1481         else if (G.vd->camzoom > maxZoom) G.vd->camzoom = maxZoom;
1482     }
1483     else if ((G.vd->dist> 0.001*G.vd->grid) && (G.vd->dist<10.0*G.vd->far)) {
1484         G.vd->dist*=(1.0 + len);
1485     }
1486
1487
1488     /*----------------------------------------------------
1489      * ndof device turntable
1490      * derived from the turntable code in viewmove
1491      */
1492
1493     /* Get the 3x3 matrix and its inverse from the quaternion */
1494     QuatToMat3(G.vd->viewquat, m);
1495     Mat3Inv(m_inv,m);
1496
1497     /* Determine the direction of the x vector (for rotating up and down) */
1498     /* This can likely be compuated directly from the quaternion. */
1499     Mat3MulVecfl(m_inv,xvec);
1500     Mat3MulVecfl(m_inv,yvec);
1501     Mat3MulVecfl(m_inv,zvec);
1502
1503     /* Perform the up/down rotation */
1504     phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
1505     si = sin(phi);
1506     q1[0] = cos(phi);
1507     q1[1] = si * xvec[0];
1508     q1[2] = si * xvec[1];
1509     q1[3] = si * xvec[2];
1510     QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
1511
1512     if (use_sel) {
1513         QuatConj(q1); /* conj == inv for unit quat */
1514         VecSubf(G.vd->ofs, G.vd->ofs, obofs);
1515         QuatMulVecf(q1, G.vd->ofs);
1516         VecAddf(G.vd->ofs, G.vd->ofs, obofs);
1517     }
1518
1519     /* Perform the orbital rotation */
1520     /* Perform the orbital rotation 
1521        If the seen Up axis is parallel to the zoom axis, rotation should be
1522        achieved with a pure Roll motion (no Spin) on the device. When you start 
1523        to tilt, moving from Top to Side view, Spinning will increasingly become 
1524        more relevant while the Roll component will decrease. When a full 
1525        Side view is reached, rotations around the world's Up axis are achieved
1526        with a pure Spin-only motion.  In other words the control of the spinning
1527        around the world's Up axis should move from the device's Spin axis to the
1528        device's Roll axis depending on the orientation of the world's Up axis 
1529        relative to the screen. */
1530     //phi = sbadjust * rsens * reverse * fval[4];  /* spin the knob, y axis */
1531     phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
1532     q1[0] = cos(phi);
1533     q1[1] = q1[2] = 0.0;
1534     q1[3] = sin(phi);
1535     QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
1536
1537     if (use_sel) {
1538         QuatConj(q1);
1539         VecSubf(G.vd->ofs, G.vd->ofs, obofs);
1540         QuatMulVecf(q1, G.vd->ofs);
1541         VecAddf(G.vd->ofs, G.vd->ofs, obofs);
1542     }
1543
1544     /*----------------------------------------------------
1545      * refresh the screen
1546      */
1547     scrarea_do_windraw(curarea);
1548     screen_swapbuffers();
1549 }
1550
1551
1552 /* Gets the lens and clipping values from a camera of lamp type object */
1553 void object_view_settings(Object *ob, float *lens, float *clipsta, float *clipend)
1554 {       
1555         if (!ob) return;
1556         
1557         if(ob->type==OB_LAMP ) {
1558                 Lamp *la = ob->data;
1559                 if (lens) {
1560                         float x1, fac;
1561                         fac= cos( M_PI*la->spotsize/360.0);
1562                         x1= saacos(fac);
1563                         *lens= 16.0*fac/sin(x1);
1564                 }
1565                 if (clipsta)    *clipsta= la->clipsta;
1566                 if (clipend)    *clipend= la->clipend;
1567         }
1568         else if(ob->type==OB_CAMERA) {
1569                 Camera *cam= ob->data;
1570                 if (lens)               *lens= cam->lens;
1571                 if (clipsta)    *clipsta= cam->clipsta;
1572                 if (clipend)    *clipend= cam->clipend;
1573         }
1574 }
1575
1576
1577 int get_view3d_viewplane(int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
1578 {
1579         Camera *cam=NULL;
1580         float lens, fac, x1, y1, x2, y2;
1581         float winx= (float)winxi, winy= (float)winyi;
1582         int orth= 0;
1583         
1584         lens= G.vd->lens;       
1585         
1586         *clipsta= G.vd->near;
1587         *clipend= G.vd->far;
1588
1589 /*      
1590  * Cant use this since we need the fac and x1 values set
1591  * if(G.vd->persp==V3D_CAMOB)
1592                 object_view_settings(G.vd->camera, &lens, &(*clipsta), &(*clipend));*/
1593         
1594         if(G.vd->persp==V3D_CAMOB) {
1595                 if(G.vd->camera) {
1596                         if(G.vd->camera->type==OB_LAMP ) {
1597                                 Lamp *la;
1598                                 
1599                                 la= G.vd->camera->data;
1600                                 fac= cos( M_PI*la->spotsize/360.0);
1601                                 
1602                                 x1= saacos(fac);
1603                                 lens= 16.0*fac/sin(x1);
1604                 
1605                                 *clipsta= la->clipsta;
1606                                 *clipend= la->clipend;
1607                         }
1608                         else if(G.vd->camera->type==OB_CAMERA) {
1609                                 cam= G.vd->camera->data;
1610                                 lens= cam->lens;
1611                                 *clipsta= cam->clipsta;
1612                                 *clipend= cam->clipend;
1613                         }
1614                 }
1615         }
1616         
1617         if(G.vd->persp==V3D_ORTHO) {
1618                 if(winx>winy) x1= -G.vd->dist;
1619                 else x1= -winx*G.vd->dist/winy;
1620                 x2= -x1;
1621
1622                 if(winx>winy) y1= -winy*G.vd->dist/winx;
1623                 else y1= -G.vd->dist;
1624                 y2= -y1;
1625                 
1626                 *clipend *= 0.5;        // otherwise too extreme low zbuffer quality
1627                 *clipsta= - *clipend;
1628                 orth= 1;
1629         }
1630         else {
1631                 /* fac for zoom, also used for camdx */
1632                 if(G.vd->persp==V3D_CAMOB) {
1633                         fac= (1.41421+( (float)G.vd->camzoom )/50.0);
1634                         fac*= fac;
1635                 }
1636                 else fac= 2.0;
1637                 
1638                 /* viewplane size depends... */
1639                 if(cam && cam->type==CAM_ORTHO) {
1640                         /* ortho_scale == 1 means exact 1 to 1 mapping */
1641                         float dfac= 2.0*cam->ortho_scale/fac;
1642                         
1643                         if(winx>winy) x1= -dfac;
1644                         else x1= -winx*dfac/winy;
1645                         x2= -x1;
1646                         
1647                         if(winx>winy) y1= -winy*dfac/winx;
1648                         else y1= -dfac;
1649                         y2= -y1;
1650                         orth= 1;
1651                 }
1652                 else {
1653                         float dfac;
1654                         
1655                         if(winx>winy) dfac= 64.0/(fac*winx*lens);
1656                         else dfac= 64.0/(fac*winy*lens);
1657                         
1658                         x1= - *clipsta * winx*dfac;
1659                         x2= -x1;
1660                         y1= - *clipsta * winy*dfac;
1661                         y2= -y1;
1662                         orth= 0;
1663                 }
1664                 /* cam view offset */
1665                 if(cam) {
1666                         float dx= 0.5*fac*G.vd->camdx*(x2-x1);
1667                         float dy= 0.5*fac*G.vd->camdy*(y2-y1);
1668                         x1+= dx;
1669                         x2+= dx;
1670                         y1+= dy;
1671                         y2+= dy;
1672                 }
1673         }
1674
1675         if(pixsize) {
1676                 float viewfac;
1677
1678                 if(orth) {
1679                         viewfac= (winx >= winy)? winx: winy;
1680                         *pixsize= 1.0f/viewfac;
1681                 }
1682                 else {
1683                         viewfac= (((winx >= winy)? winx: winy)*lens)/32.0;
1684                         *pixsize= *clipsta/viewfac;
1685                 }
1686         }
1687         
1688         viewplane->xmin= x1;
1689         viewplane->ymin= y1;
1690         viewplane->xmax= x2;
1691         viewplane->ymax= y2;
1692         
1693         return orth;
1694 }
1695
1696 /* important to not set windows active in here, can be renderwin for example */
1697 void setwinmatrixview3d(int winx, int winy, rctf *rect)         /* rect: for picking */
1698 {
1699         rctf viewplane;
1700         float clipsta, clipend, x1, y1, x2, y2;
1701         int orth;
1702         
1703         orth= get_view3d_viewplane(winx, winy, &viewplane, &clipsta, &clipend, NULL);
1704 //      printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
1705         x1= viewplane.xmin;
1706         y1= viewplane.ymin;
1707         x2= viewplane.xmax;
1708         y2= viewplane.ymax;
1709         
1710         if(rect) {              /* picking */
1711                 rect->xmin/= (float)curarea->winx;
1712                 rect->xmin= x1+rect->xmin*(x2-x1);
1713                 rect->ymin/= (float)curarea->winy;
1714                 rect->ymin= y1+rect->ymin*(y2-y1);
1715                 rect->xmax/= (float)curarea->winx;
1716                 rect->xmax= x1+rect->xmax*(x2-x1);
1717                 rect->ymax/= (float)curarea->winy;
1718                 rect->ymax= y1+rect->ymax*(y2-y1);
1719                 
1720                 if(orth) myortho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
1721                 else mywindow(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
1722                 
1723         }
1724         else {
1725                 if(orth) myortho(x1, x2, y1, y2, clipsta, clipend);
1726                 else mywindow(x1, x2, y1, y2, clipsta, clipend);
1727         }
1728
1729         /* not sure what this was for? (ton) */
1730         glMatrixMode(GL_PROJECTION);
1731         mygetmatrix(curarea->winmat);
1732         glMatrixMode(GL_MODELVIEW);
1733 }
1734
1735 void obmat_to_viewmat(Object *ob, short smooth)
1736 {
1737         float bmat[4][4];
1738         float tmat[3][3];
1739
1740         G.vd->view= 0; /* dont show the grid */
1741
1742         Mat4CpyMat4(bmat, ob->obmat);
1743         Mat4Ortho(bmat);
1744         Mat4Invert(G.vd->viewmat, bmat);
1745         
1746         /* view quat calculation, needed for add object */
1747         Mat3CpyMat4(tmat, G.vd->viewmat);
1748         if (smooth) {
1749                 float new_quat[4];
1750                 if (G.vd->persp==V3D_CAMOB && G.vd->camera) {
1751                         /* were from a camera view */
1752                         
1753                         float orig_ofs[3];
1754                         float orig_dist= G.vd->dist;
1755                         float orig_lens= G.vd->lens;
1756                         VECCOPY(orig_ofs, G.vd->ofs);
1757                         
1758                         /* Switch from camera view */
1759                         Mat3ToQuat(tmat, new_quat);
1760                         
1761                         G.vd->persp=V3D_PERSP;
1762                         G.vd->dist= 0.0;
1763                         
1764                         view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
1765                         smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
1766                         
1767                         G.vd->persp=V3D_CAMOB; /* just to be polite, not needed */
1768                         
1769                 } else {
1770                         Mat3ToQuat(tmat, new_quat);
1771                         smooth_view(G.vd, NULL, new_quat, NULL, NULL);
1772                 }
1773         } else {
1774                 Mat3ToQuat(tmat, G.vd->viewquat);
1775         }
1776 }
1777
1778 /* dont set windows active in in here, is used by renderwin too */
1779 void setviewmatrixview3d()
1780 {
1781         if(G.vd->persp==V3D_CAMOB) {        /* obs/camera */
1782                 if(G.vd->camera) {
1783                         where_is_object(G.vd->camera);  
1784                         obmat_to_viewmat(G.vd->camera, 0);
1785                 }
1786                 else {
1787                         QuatToMat4(G.vd->viewquat, G.vd->viewmat);
1788                         G.vd->viewmat[3][2]-= G.vd->dist;
1789                 }
1790         }
1791         else {
1792                 
1793                 QuatToMat4(G.vd->viewquat, G.vd->viewmat);
1794                 if(G.vd->persp==V3D_PERSP) G.vd->viewmat[3][2]-= G.vd->dist;
1795                 if(G.vd->ob_centre) {
1796                         Object *ob= G.vd->ob_centre;
1797                         float vec[3];
1798                         
1799                         VECCOPY(vec, ob->obmat[3]);
1800                         if(ob->type==OB_ARMATURE && G.vd->ob_centre_bone[0]) {
1801                                 bPoseChannel *pchan= get_pose_channel(ob->pose, G.vd->ob_centre_bone);
1802                                 if(pchan) {
1803                                         VECCOPY(vec, pchan->pose_mat[3]);
1804                                         Mat4MulVecfl(ob->obmat, vec);
1805                                 }
1806                         }
1807                         i_translate(-vec[0], -vec[1], -vec[2], G.vd->viewmat);
1808                 }
1809                 else i_translate(G.vd->ofs[0], G.vd->ofs[1], G.vd->ofs[2], G.vd->viewmat);
1810         }
1811 }
1812
1813 void setcameratoview3d(void)
1814 {
1815         Object *ob;
1816         float dvec[3];
1817
1818         ob= G.vd->camera;
1819         dvec[0]= G.vd->dist*G.vd->viewinv[2][0];
1820         dvec[1]= G.vd->dist*G.vd->viewinv[2][1];
1821         dvec[2]= G.vd->dist*G.vd->viewinv[2][2];                                        
1822         VECCOPY(ob->loc, dvec);
1823         VecSubf(ob->loc, ob->loc, G.vd->ofs);
1824         G.vd->viewquat[0]= -G.vd->viewquat[0];
1825         /*  */
1826         /*if (ob->transflag & OB_QUAT) {
1827                 QUATCOPY(ob->quat, G.vd->viewquat);
1828         } else {*/
1829                 QuatToEul(G.vd->viewquat, ob->rot);
1830         /*}*/
1831         G.vd->viewquat[0]= -G.vd->viewquat[0];
1832 }
1833
1834 /* IGLuint-> GLuint*/
1835 /* Warning: be sure to account for a negative return value
1836  *   This is an error, "Too many objects in select buffer"
1837  *   and no action should be taken (can crash blender) if this happens
1838  */
1839 short  view3d_opengl_select(unsigned int *buffer, unsigned int bufsize, short x1, short y1, short x2, short y2)
1840 {
1841         rctf rect;
1842         short mval[2], code, hits;
1843
1844         G.f |= G_PICKSEL;
1845         
1846         if(x1==0 && x2==0 && y1==0 && y2==0) {
1847                 getmouseco_areawin(mval);
1848                 rect.xmin= mval[0]-12;  // seems to be default value for bones only now
1849                 rect.xmax= mval[0]+12;
1850                 rect.ymin= mval[1]-12;
1851                 rect.ymax= mval[1]+12;
1852         }
1853         else {
1854                 rect.xmin= x1;
1855                 rect.xmax= x2;
1856                 rect.ymin= y1;
1857                 rect.ymax= y2;
1858         }
1859         /* get rid of overlay button matrix */
1860         persp(PERSP_VIEW);
1861         setwinmatrixview3d(curarea->winx, curarea->winy, &rect);
1862         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
1863         
1864         if(G.vd->drawtype > OB_WIRE) {
1865                 G.vd->zbuf= TRUE;
1866                 glEnable(GL_DEPTH_TEST);
1867         }
1868
1869         if(G.vd->flag & V3D_CLIPPING)
1870                 view3d_set_clipping(G.vd);
1871         
1872         glSelectBuffer( bufsize, (GLuint *)buffer);
1873         glRenderMode(GL_SELECT);
1874         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1875         glPushName(-1);
1876         code= 1;
1877         
1878         if(G.obedit && G.obedit->type==OB_MBALL) {
1879                 draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1880         }
1881         else if ((G.obedit && G.obedit->type==OB_ARMATURE)) {
1882                 draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1883         }
1884         else {
1885                 Base *base;
1886                 
1887                 G.vd->xray= TRUE;       // otherwise it postpones drawing
1888                 for(base= G.scene->base.first; base; base= base->next) {
1889                         if(base->lay & G.vd->lay) {
1890                                 
1891                                 if (base->object->restrictflag & OB_RESTRICT_SELECT)
1892                                         base->selcol= 0;
1893                                 else {
1894                                         base->selcol= code;
1895                                         glLoadName(code);
1896                                         draw_object(base, DRAW_PICKING|DRAW_CONSTCOLOR);
1897                                         
1898                                         /* we draw group-duplicators for selection too */
1899                                         if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1900                                                 ListBase *lb;
1901                                                 DupliObject *dob;
1902                                                 Base tbase;
1903                                                 
1904                                                 tbase.flag= OB_FROMDUPLI;
1905                                                 lb= object_duplilist(G.scene, base->object);
1906                                                 
1907                                                 for(dob= lb->first; dob; dob= dob->next) {
1908                                                         tbase.object= dob->ob;
1909                                                         Mat4CpyMat4(dob->ob->obmat, dob->mat);
1910                                                         
1911                                                         draw_object(&tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1912                                                         
1913                                                         Mat4CpyMat4(dob->ob->obmat, dob->omat);
1914                                                 }
1915                                                 free_object_duplilist(lb);
1916                                         }
1917                                         code++;
1918                                 }                               
1919                         }
1920                 }
1921                 G.vd->xray= FALSE;      // restore
1922         }
1923         
1924         glPopName();    /* see above (pushname) */
1925         hits= glRenderMode(GL_RENDER);
1926
1927         G.f &= ~G_PICKSEL;
1928         setwinmatrixview3d(curarea->winx, curarea->winy, NULL);
1929         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
1930         
1931         if(G.vd->drawtype > OB_WIRE) {
1932                 G.vd->zbuf= 0;
1933                 glDisable(GL_DEPTH_TEST);
1934         }
1935         persp(PERSP_WIN);
1936         
1937         if(G.vd->flag & V3D_CLIPPING)
1938                 view3d_clr_clipping();
1939         
1940         if(hits<0) error("Too many objects in select buffer");
1941         
1942         return hits;
1943 }
1944
1945 float *give_cursor()
1946 {
1947         if(G.vd && G.vd->localview) return G.vd->cursor;
1948         else return G.scene->cursor;
1949 }
1950
1951 unsigned int free_localbit()
1952 {
1953         unsigned int lay;
1954         ScrArea *sa;
1955         bScreen *sc;
1956         
1957         lay= 0;
1958         
1959         /* sometimes we loose a localview: when an area is closed */
1960         /* check all areas: which localviews are in use? */
1961         sc= G.main->screen.first;
1962         while(sc) {
1963                 sa= sc->areabase.first;
1964                 while(sa) {
1965                         SpaceLink *sl= sa->spacedata.first;
1966                         while(sl) {
1967                                 if(sl->spacetype==SPACE_VIEW3D) {
1968                                         View3D *v3d= (View3D*) sl;
1969                                         lay |= v3d->lay;
1970                                 }
1971                                 sl= sl->next;
1972                         }
1973                         sa= sa->next;
1974                 }
1975                 sc= sc->id.next;
1976         }
1977         
1978         if( (lay & 0x01000000)==0) return 0x01000000;
1979         if( (lay & 0x02000000)==0) return 0x02000000;
1980         if( (lay & 0x04000000)==0) return 0x04000000;
1981         if( (lay & 0x08000000)==0) return 0x08000000;
1982         if( (lay & 0x10000000)==0) return 0x10000000;
1983         if( (lay & 0x20000000)==0) return 0x20000000;
1984         if( (lay & 0x40000000)==0) return 0x40000000;
1985         if( (lay & 0x80000000)==0) return 0x80000000;
1986         
1987         return 0;
1988 }
1989
1990
1991 void initlocalview()
1992 {
1993         Base *base;
1994         float size = 0.0, min[3], max[3], afm[3];
1995         unsigned int locallay;
1996         int ok=0;
1997
1998         if(G.vd->localvd) return;
1999
2000         INIT_MINMAX(min, max);
2001
2002         locallay= free_localbit();
2003
2004         if(locallay==0) {
2005                 error("Sorry,  no more than 8 localviews");
2006                 ok= 0;
2007         }
2008         else {
2009                 if(G.obedit) {
2010                         minmax_object(G.obedit, min, max);
2011                         
2012                         ok= 1;
2013                 
2014                         BASACT->lay |= locallay;
2015                         G.obedit->lay= BASACT->lay;
2016                 }
2017                 else {
2018                         base= FIRSTBASE;
2019                         while(base) {
2020                                 if TESTBASE(base)  {
2021                                         minmax_object(base->object, min, max);
2022                                         base->lay |= locallay;
2023                                         base->object->lay= base->lay;
2024                                         ok= 1;
2025                                 }
2026                                 base= base->next;
2027                         }
2028                 }
2029                 
2030                 afm[0]= (max[0]-min[0]);
2031                 afm[1]= (max[1]-min[1]);
2032                 afm[2]= (max[2]-min[2]);
2033                 size= 0.7*MAX3(afm[0], afm[1], afm[2]);
2034                 if(size<=0.01) size= 0.01;
2035         }
2036         
2037         if(ok) {
2038                 G.vd->localvd= MEM_mallocN(sizeof(View3D), "localview");
2039                 memcpy(G.vd->localvd, G.vd, sizeof(View3D));
2040
2041                 G.vd->ofs[0]= -(min[0]+max[0])/2.0;
2042                 G.vd->ofs[1]= -(min[1]+max[1])/2.0;
2043                 G.vd->ofs[2]= -(min[2]+max[2])/2.0;
2044
2045                 G.vd->dist= size;
2046
2047                 // correction for window aspect ratio
2048                 if(curarea->winy>2 && curarea->winx>2) {
2049                         size= (float)curarea->winx/(float)curarea->winy;
2050                         if(size<1.0) size= 1.0/size;
2051                         G.vd->dist*= size;
2052                 }
2053                 
2054                 if (G.vd->persp==V3D_CAMOB) G.vd->persp= V3D_PERSP;
2055                 if (G.vd->near> 0.1) G.vd->near= 0.1;
2056                 
2057                 G.vd->cursor[0]= -G.vd->ofs[0];
2058                 G.vd->cursor[1]= -G.vd->ofs[1];
2059                 G.vd->cursor[2]= -G.vd->ofs[2];
2060
2061                 G.vd->lay= locallay;
2062                 
2063                 countall();
2064                 scrarea_queue_winredraw(curarea);
2065         }
2066         else {
2067                 /* clear flags */ 
2068                 base= FIRSTBASE;
2069                 while(base) {
2070                         if( base->lay & locallay ) {
2071                                 base->lay-= locallay;
2072                                 if(base->lay==0) base->lay= G.vd->layact;
2073                                 if(base->object != G.obedit) base->flag |= SELECT;
2074                                 base->object->lay= base->lay;
2075                         }
2076                         base= base->next;
2077                 }
2078                 scrarea_queue_headredraw(curarea);
2079                 
2080                 G.vd->localview= 0;
2081         }
2082         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
2083 }
2084
2085 void centerview()       /* like a localview without local! */
2086 {
2087         Object *ob= OBACT;
2088         float size, min[3], max[3], afm[3];
2089         int ok=0;
2090         
2091         /* SMOOTHVIEW */
2092         float new_ofs[3];
2093         float new_dist;
2094         
2095         INIT_MINMAX(min, max);
2096
2097         if (G.f & G_WEIGHTPAINT) {
2098                 /* hardcoded exception, we look for the one selected armature */
2099                 /* this is weak code this way, we should make a generic active/selection callback interface once... */
2100                 Base *base;
2101                 for(base=FIRSTBASE; base; base= base->next) {
2102                         if(TESTBASELIB(base)) {
2103                                 if(base->object->type==OB_ARMATURE)
2104                                         if(base->object->flag & OB_POSEMODE)
2105                                                 break;
2106                         }
2107                 }
2108                 if(base)
2109                         ob= base->object;
2110         }
2111         
2112         
2113         if(G.obedit) {
2114                 ok = minmax_verts(min, max);    /* only selected */
2115         }
2116         else if(ob && (ob->flag & OB_POSEMODE)) {
2117                 if(ob->pose) {
2118                         bArmature *arm= ob->data;
2119                         bPoseChannel *pchan;
2120                         float vec[3];
2121                         
2122                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
2123                                 if(pchan->bone->flag & BONE_SELECTED) {
2124                                         if(pchan->bone->layer & arm->layer) {
2125                                                 ok= 1;
2126                                                 VECCOPY(vec, pchan->pose_head);
2127                                                 Mat4MulVecfl(ob->obmat, vec);
2128                                                 DO_MINMAX(vec, min, max);
2129                                                 VECCOPY(vec, pchan->pose_tail);
2130                                                 Mat4MulVecfl(ob->obmat, vec);
2131                                                 DO_MINMAX(vec, min, max);
2132                                         }
2133                                 }
2134                         }
2135                 }
2136         }
2137         else if (FACESEL_PAINT_TEST) {
2138                 ok= minmax_tface(min, max);
2139         }
2140         else if (G.f & G_PARTICLEEDIT) {
2141                 ok= PE_minmax(min, max);
2142         }
2143         else {
2144                 Base *base= FIRSTBASE;
2145                 while(base) {
2146                         if TESTBASE(base)  {
2147                                 minmax_object(base->object, min, max);
2148                                 /* account for duplis */
2149                                 minmax_object_duplis(base->object, min, max);
2150                                 
2151                                 ok= 1;
2152                         }
2153                         base= base->next;
2154                 }
2155         }
2156         
2157         if(ok==0) return;
2158         
2159         afm[0]= (max[0]-min[0]);
2160         afm[1]= (max[1]-min[1]);
2161         afm[2]= (max[2]-min[2]);
2162         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
2163         
2164         if(size <= G.vd->near*1.5f) size= G.vd->near*1.5f;
2165         
2166         new_ofs[0]= -(min[0]+max[0])/2.0f;
2167         new_ofs[1]= -(min[1]+max[1])/2.0f;
2168         new_ofs[2]= -(min[2]+max[2])/2.0f;
2169         
2170         new_dist = size;
2171
2172         /* correction for window aspect ratio */
2173         if(curarea->winy>2 && curarea->winx>2) {
2174                 size= (float)curarea->winx/(float)curarea->winy;
2175                 if(size<1.0f) size= 1.0f/size;
2176                 new_dist*= size;
2177         }
2178         
2179         G.vd->cursor[0]= -new_ofs[0];
2180         G.vd->cursor[1]= -new_ofs[1];
2181         G.vd->cursor[2]= -new_ofs[2];
2182         
2183         if (G.vd->persp==V3D_CAMOB && G.vd->camera) {
2184                 float orig_lens= G.vd->lens;
2185                 
2186                 G.vd->persp=V3D_PERSP;
2187                 G.vd->dist= 0.0f;
2188                 view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
2189                 smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
2190         } else {
2191                 if(G.vd->persp==V3D_CAMOB)
2192                         G.vd->persp= V3D_PERSP;
2193                 
2194                 smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
2195         }
2196         scrarea_queue_winredraw(curarea);
2197         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
2198
2199 }
2200
2201
2202 void restore_localviewdata(View3D *vd)
2203 {
2204         if(vd->localvd==0) return;
2205         
2206         VECCOPY(vd->ofs, vd->localvd->ofs);
2207         vd->dist= vd->localvd->dist;
2208         vd->persp= vd->localvd->persp;
2209         vd->view= vd->localvd->view;
2210         vd->near= vd->localvd->near;
2211         vd->far= vd->localvd->far;
2212         vd->lay= vd->localvd->lay;
2213         vd->layact= vd->localvd->layact;
2214         vd->drawtype= vd->localvd->drawtype;
2215         vd->camera= vd->localvd->camera;
2216         QUATCOPY(vd->viewquat, vd->localvd->viewquat);
2217         
2218 }
2219
2220 void endlocalview(ScrArea *sa)
2221 {
2222         View3D *v3d;
2223         struct Base *base;
2224         unsigned int locallay;
2225         
2226         if(sa->spacetype!=SPACE_VIEW3D) return;
2227         v3d= sa->spacedata.first;
2228         
2229         if(v3d->localvd) {
2230                 
2231                 locallay= v3d->lay & 0xFF000000;
2232                 
2233                 restore_localviewdata(v3d);
2234                 
2235                 MEM_freeN(v3d->localvd);
2236                 v3d->localvd= 0;
2237                 v3d->localview= 0;
2238
2239                 /* for when in other window the layers have changed */
2240                 if(v3d->scenelock) v3d->lay= G.scene->lay;
2241                 
2242                 base= FIRSTBASE;
2243                 while(base) {
2244                         if( base->lay & locallay ) {
2245                                 base->lay-= locallay;
2246                                 if(base->lay==0) base->lay= v3d->layact;
2247                                 if(base->object != G.obedit) {
2248                                         base->flag |= SELECT;
2249                                         base->object->flag |= SELECT;
2250                                 }
2251                                 base->object->lay= base->lay;
2252                         }
2253                         base= base->next;
2254                 }
2255
2256                 countall();
2257                 allqueue(REDRAWVIEW3D, 0);      /* because of select */
2258                 allqueue(REDRAWOOPS, 0);        /* because of select */
2259                 BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
2260         } 
2261 }
2262
2263 void view3d_home(int center)
2264 {
2265         Base *base;
2266         float size, min[3], max[3], afm[3];
2267         int ok= 1, onedone=0;
2268
2269         if(center) {
2270                 min[0]= min[1]= min[2]= 0.0f;
2271                 max[0]= max[1]= max[2]= 0.0f;
2272         }
2273         else {
2274                 INIT_MINMAX(min, max);
2275         }
2276         
2277         for(base= FIRSTBASE; base; base= base->next) {
2278                 if(base->lay & G.vd->lay) {
2279                         onedone= 1;
2280                         minmax_object(base->object, min, max);
2281                 }
2282         }
2283         if(!onedone) return;
2284         
2285         afm[0]= (max[0]-min[0]);
2286         afm[1]= (max[1]-min[1]);
2287         afm[2]= (max[2]-min[2]);
2288         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
2289         if(size==0.0) ok= 0;
2290                 
2291         if(ok) {
2292                 float new_dist;
2293                 float new_ofs[3];
2294                 
2295                 new_dist = size;
2296                 new_ofs[0]= -(min[0]+max[0])/2.0f;
2297                 new_ofs[1]= -(min[1]+max[1])/2.0f;
2298                 new_ofs[2]= -(min[2]+max[2])/2.0f;
2299                 
2300                 // correction for window aspect ratio
2301                 if(curarea->winy>2 && curarea->winx>2) {
2302                         size= (float)curarea->winx/(float)curarea->winy;
2303                         if(size<1.0) size= 1.0f/size;
2304                         new_dist*= size;
2305                 }
2306                 
2307                 if (G.vd->persp==V3D_CAMOB && G.vd->camera) {
2308                         /* switch out of camera view */
2309                         float orig_lens= G.vd->lens;
2310                         
2311                         G.vd->persp= V3D_PERSP;
2312                         G.vd->dist= 0.0;
2313                         view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
2314                         smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
2315                         
2316                 } else {
2317                         if(G.vd->persp==V3D_CAMOB) G.vd->persp= V3D_PERSP;
2318                         smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
2319                 }
2320                 scrarea_queue_winredraw(curarea);
2321         }
2322         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
2323
2324 }
2325
2326
2327 void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3])
2328 {
2329         float alignaxis[3] = {0.0, 0.0, 0.0};
2330         float norm[3], axis[3], angle, new_quat[4];
2331
2332         if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
2333         else alignaxis[-axisidx-1]= -1.0;
2334
2335         VECCOPY(norm, vec);
2336         Normalize(norm);
2337
2338         angle= (float)acos(Inpf(alignaxis, norm));
2339         Crossf(axis, alignaxis, norm);
2340         VecRotToQuat(axis, -angle, new_quat);
2341
2342         v3d->view= 0;
2343         
2344         if (v3d->persp==V3D_CAMOB && v3d->camera) {
2345                 /* switch out of camera view */
2346                 float orig_ofs[3];
2347                 float orig_dist= v3d->dist;
2348                 float orig_lens= v3d->lens;
2349
2350                 VECCOPY(orig_ofs, v3d->ofs);
2351                 G.vd->persp= V3D_PERSP;
2352                 G.vd->dist= 0.0;
2353                 view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens);
2354                 smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
2355         } else {
2356                 if (v3d->persp==V3D_CAMOB) v3d->persp= V3D_PERSP; /* switch out of camera mode */
2357                 smooth_view(v3d, NULL, new_quat, NULL, NULL);
2358         }
2359 }
2360
2361
2362
2363 /* SMOOTHVIEW */
2364 void smooth_view(View3D *v3d, float *ofs, float *quat, float *dist, float *lens)
2365 {
2366         /* View Animation enabled */
2367         if (U.smooth_viewtx) {
2368                 int i;
2369                 char changed = 0;
2370                 float step = 0.0, step_inv;
2371                 float orig_dist;
2372                 float orig_lens;
2373                 float orig_quat[4];
2374                 float orig_ofs[3];
2375                 
2376                 double time_allowed, time_current, time_start;
2377                 
2378                 /* if there is no difference, return */
2379                 changed = 0; /* zero means no difference */
2380                 if (dist) {
2381                         if ((*dist) != v3d->dist)
2382                                 changed = 1;
2383                 }
2384                 
2385                 if (lens) {
2386                         if ((*lens) != v3d->lens)
2387                                 changed = 1;
2388                 }
2389                 
2390                 if (!changed && ofs) {
2391                         if ((ofs[0]!=v3d->ofs[0]) ||
2392                                 (ofs[1]!=v3d->ofs[1]) ||
2393                                 (ofs[2]!=v3d->ofs[2]) )
2394                                 changed = 1;
2395                 }
2396                 
2397                 if (!changed && quat ) {
2398                         if ((quat[0]!=v3d->viewquat[0]) ||
2399                                 (quat[1]!=v3d->viewquat[1]) ||
2400                                 (quat[2]!=v3d->viewquat[2]) ||
2401                                 (quat[3]!=v3d->viewquat[3]) )
2402                                 changed = 1;
2403                 }
2404                 
2405                 /* The new view is different from the old one
2406                  * so animate the view */
2407                 if (changed) {
2408                         
2409                         /* store original values */
2410                         VECCOPY(orig_ofs,       v3d->ofs);
2411                         QUATCOPY(orig_quat,     v3d->viewquat);
2412                         orig_dist =                     v3d->dist;
2413                         orig_lens =                     v3d->lens;
2414                         
2415                         time_allowed= (float)U.smooth_viewtx / 1000.0;
2416                         time_current = time_start = PIL_check_seconds_timer();
2417                         
2418                         /* if this is view rotation only
2419                          * we can decrease the time allowed by
2420                          * the angle between quats 
2421                          * this means small rotations wont lag */
2422                          if (quat && !ofs && !dist) {
2423                                 float vec1[3], vec2[3];
2424                                 VECCOPY(vec1, quat);
2425                                 VECCOPY(vec2, v3d->viewquat);
2426                                 Normalize(vec1);
2427                                 Normalize(vec2);
2428                                 /* scale the time allowed by the rotation */
2429                                 time_allowed *= NormalizedVecAngle2(vec1, vec2)/(M_PI/2); 
2430                          }
2431                         
2432                         while (time_start + time_allowed > time_current) {
2433                                 
2434                                 step =  (float)((time_current-time_start) / time_allowed);
2435                                 
2436                                 /* ease in/out */
2437                                 if (step < 0.5) step = (float)pow(step*2, 2)/2;
2438                                 else                    step = (float)1-(pow(2*(1-step),2)/2);
2439                                 
2440                                 step_inv = 1-step;
2441                                 
2442                                 if (ofs)
2443                                         for (i=0; i<3; i++)
2444                                                 v3d->ofs[i] = ofs[i]*step + orig_ofs[i]*step_inv;
2445                                 
2446                                 
2447                                 if (quat)
2448                                         QuatInterpol(v3d->viewquat, orig_quat, quat, step);
2449                                         
2450                                 if (dist)
2451                                         v3d->dist = ((*dist)*step) + (orig_dist*step_inv);
2452                                 
2453                                 if (lens)
2454                                         v3d->lens = ((*lens)*step) + (orig_lens*step_inv);
2455                                 
2456                                 /*redraw the view*/
2457                                 scrarea_do_windraw(curarea);
2458                                 screen_swapbuffers();
2459                                 
2460                                 time_current= PIL_check_seconds_timer();
2461                         }
2462                 }
2463         }
2464         
2465         /* set these values even if animation is enabled because flaot
2466          * error will make then not quite accurate */
2467         if (ofs)
2468                 VECCOPY(v3d->ofs, ofs);
2469         if (quat)
2470                 QUATCOPY(v3d->viewquat, quat);
2471         if (dist)
2472                 v3d->dist = *dist;
2473         if (lens)
2474                 v3d->lens = *lens;
2475         
2476 }
2477
2478
2479
2480 /* Gets the view trasnformation from a camera
2481  * currently dosnt take camzoom into account
2482  * 
2483  * The dist is not modified for this function, if NULL its assimed zero
2484  * */
2485 void view_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens)
2486 {       
2487         float bmat[4][4];
2488         float imat[4][4];
2489         float tmat[3][3];
2490         
2491         if (!ob) return;
2492         
2493         /* Offset */
2494         if (ofs) {
2495                 where_is_object(ob);
2496                 VECCOPY(ofs, ob->obmat[3]);
2497                 VecMulf(ofs, -1.0f); /*flip the vector*/
2498         }
2499         
2500         /* Quat */
2501         if (quat) {
2502                 Mat4CpyMat4(bmat, ob->obmat);
2503                 Mat4Ortho(bmat);
2504                 Mat4Invert(imat, bmat);
2505                 Mat3CpyMat4(tmat, imat);
2506                 Mat3ToQuat(tmat, quat);
2507         }
2508         
2509         if (dist) {
2510                 float vec[3];
2511                 Mat3CpyMat4(tmat, ob->obmat);
2512                 
2513                 vec[0]= vec[1] = 0.0;
2514                 vec[2]= -(*dist);
2515                 Mat3MulVecfl(tmat, vec);
2516                 VecSubf(ofs, ofs, vec);
2517         }
2518         
2519         /* Lens */
2520         if (lens)
2521                 object_view_settings(ob, lens, NULL, NULL);
2522 }
2523
2524 /* For use with smooth view
2525  * 
2526  * the current view is unchanged, blend between the current view and the
2527  * camera view
2528  * */
2529 void smooth_view_to_camera(View3D *v3d)
2530 {
2531         if (!U.smooth_viewtx || !v3d->camera || G.vd->persp != V3D_CAMOB) {
2532                 return;
2533         } else {
2534                 Object *ob = v3d->camera;
2535                 
2536                 float orig_ofs[3];
2537                 float orig_dist=v3d->dist;
2538                 float orig_lens=v3d->lens;
2539                 float new_dist=0.0;
2540                 float new_lens=35.0;
2541                 float new_quat[4];
2542                 float new_ofs[3];
2543                 
2544                 VECCOPY(orig_ofs, v3d->ofs);
2545                 
2546                 view_settings_from_ob(ob, new_ofs, new_quat, NULL, &new_lens);
2547                 
2548                 G.vd->persp= V3D_PERSP;
2549                 smooth_view(v3d, new_ofs, new_quat, &new_dist, &new_lens);
2550                 VECCOPY(v3d->ofs, orig_ofs);
2551                 v3d->lens= orig_lens;
2552                 v3d->dist = orig_dist; /* restore the dist */
2553                 
2554                 v3d->camera = ob;
2555                 v3d->persp= V3D_CAMOB;
2556         }
2557 }
2558