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