merge trunk 17122:17213
[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 int view_autodist( float mouse_worldloc[3] ) //, float *autodist )
802 {
803         View3D *v3d = G.vd;
804         
805         /* Zooms in on a border drawn by the user */
806         short mval[2];
807         rcti rect;
808         
809         /* ZBuffer depth vars */
810         bglMats mats;
811         float depth, depth_close= MAXFLOAT;
812         int had_depth = 0;
813         double cent[2],  p[3];
814         int xs, ys;
815         
816         getmouseco_areawin(mval);
817         
818         persp(PERSP_VIEW);
819         
820         rect.xmax = mval[0] + 4;
821         rect.ymax = mval[1] + 4;
822         
823         rect.xmin = mval[0] - 4;
824         rect.ymin = mval[1] - 4;
825         
826         /* Get Z Depths, needed for perspective, nice for ortho */
827         bgl_get_mats(&mats);
828         draw_depth(curarea, (void *)v3d, NULL);
829         
830         /* force updating */
831         if (v3d->depths) {
832                 had_depth = 1;
833                 v3d->depths->damaged = 1;
834         }
835         
836         view3d_update_depths(v3d);
837         
838         /* Constrain rect to depth bounds */
839         if (rect.xmin < 0) rect.xmin = 0;
840         if (rect.ymin < 0) rect.ymin = 0;
841         if (rect.xmax >= v3d->depths->w) rect.xmax = v3d->depths->w-1;
842         if (rect.ymax >= v3d->depths->h) rect.ymax = v3d->depths->h-1;          
843         
844         /* Find the closest Z pixel */
845         for (xs=rect.xmin; xs < rect.xmax; xs++) {
846                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
847                         depth= v3d->depths->depths[ys*v3d->depths->w+xs];
848                         if(depth < v3d->depths->depth_range[1] && depth > v3d->depths->depth_range[0]) {
849                                 if (depth_close > depth) {
850                                         depth_close = depth;
851                                 }
852                         }
853                 }
854         }
855         
856         if (depth_close==MAXFLOAT)
857                 return 0;
858                 
859         if (had_depth==0) {
860                 MEM_freeN(v3d->depths->depths);
861                 v3d->depths->depths = NULL;
862         }
863         v3d->depths->damaged = 1;
864         
865         cent[0] = (double)mval[0];
866         cent[1] = (double)mval[1];
867         
868         if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, mats.viewport, &p[0], &p[1], &p[2]))
869                 return 0;
870
871         mouse_worldloc[0] = (float)p[0];
872         mouse_worldloc[1] = (float)p[1];
873         mouse_worldloc[2] = (float)p[2];
874         return 1;
875 }
876
877 void viewmove(int mode)
878 {
879         static float lastofs[3] = {0,0,0};
880         Object *ob = OBACT;
881         float firstvec[3], newvec[3], dvec[3];
882         float reverse, oldquat[4], q1[4], si, phi, dist0;
883         float ofs[3], obofs[3]= {0.0f, 0.0f, 0.0f};
884         int firsttime=1;
885         short mvalball[2], mval[2], mvalo[2], mval_area[2], mvali[2];
886         short use_sel = 0;
887         short preview3d_event= 1;
888         
889         // locals for dist correction
890         float mat[3][3];
891         float upvec[3];
892
893                 /* 3D window may not be defined */
894         if( !G.vd ) {
895                 fprintf( stderr, "G.vd == NULL in viewmove()\n" );
896                 return;
897         }
898         
899         // dist correction from other movement devices  
900         if((dz_flag)||G.vd->dist==0) {
901                 dz_flag = 0;
902                 G.vd->dist = m_dist;
903                 upvec[0] = upvec[1] = 0;
904                 upvec[2] = G.vd->dist;
905                 Mat3CpyMat4(mat, G.vd->viewinv);
906                 Mat3MulVecfl(mat, upvec);
907                 VecAddf(G.vd->ofs, G.vd->ofs, upvec);
908         }
909                 
910         /* sometimes this routine is called from headerbuttons */
911
912         areawinset(curarea->win);
913         
914         QUATCOPY(oldquat, G.vd->viewquat);
915         
916         getmouseco_areawin(mval_area);  /* for zoom to mouse loc */
917         getmouseco_sc(mvali);           /* work with screen coordinates because of trackball function */
918         mvalball[0]= mvalo[0] = mvali[0];                       /* needed for turntable to work */
919         mvalball[1]= mvalo[1] = mvali[1];
920         dist0= G.vd->dist;
921         
922         calctrackballvec(&curarea->winrct, mvalo, firstvec);
923
924         /* cumultime(0); */
925
926         if(!G.obedit && (G.f & G_SCULPTMODE) && ob && G.vd->pivot_last) {
927                 use_sel= 1;
928                 VecCopyf(ofs, G.vd->ofs);
929
930                 VecCopyf(obofs, sculpt_data()->pivot);
931                 Mat4MulVecfl(ob->obmat, obofs);
932                 obofs[0]= -obofs[0];
933                 obofs[1]= -obofs[1];
934                 obofs[2]= -obofs[2];
935         }
936         else if (U.uiflag & USER_ORBIT_SELECTION) {
937                 use_sel = 1;
938                 
939                 VECCOPY(ofs, G.vd->ofs);
940                 
941                 /* If there's no selection, lastofs is unmodified and last value since static */
942                 calculateTransformCenter(V3D_CENTROID, lastofs);
943                 
944                 VECCOPY(obofs, lastofs);
945                 VecMulf(obofs, -1.0f);
946         }
947         else if (U.uiflag & USER_ORBIT_ZBUF) {
948                 if ((use_sel=view_autodist(obofs))) {
949                         if (G.vd->persp==V3D_PERSP) {
950                                 float my_origin[3]; /* original G.vd->ofs */
951                                 float my_pivot[3]; /* view */
952                                 
953                                 VECCOPY(my_origin, G.vd->ofs);
954                                 VecMulf(my_origin, -1.0f);                              /* ofs is flipped */
955                                 
956                                 /* Set the dist value to be the distance from this 3d point */
957                                 /* this means youll always be able to zoom into it and panning wont go bad when dist was zero */
958                                 
959                                 /* remove dist value */                 
960                                 upvec[0] = upvec[1] = 0;
961                                 upvec[2] = G.vd->dist;
962                                 Mat3CpyMat4(mat, G.vd->viewinv);
963                                 Mat3MulVecfl(mat, upvec);
964                                 VecSubf(my_pivot, G.vd->ofs, upvec);
965                                 VecMulf(my_pivot, -1.0f);                               /* ofs is flipped */
966                                 
967                                 /* find a new ofs value that is allong the view axis (rather then the mouse location) */
968                                 lambda_cp_line_ex(obofs, my_pivot, my_origin, dvec);
969                                 dist0 = G.vd->dist = VecLenf(my_pivot, dvec);
970                                 
971                                 VecMulf(dvec, -1.0f);
972                                 VECCOPY(G.vd->ofs, dvec);
973                         }
974                         VecMulf(obofs, -1.0f);
975                         VECCOPY(ofs, G.vd->ofs);
976                 } else {
977                         ofs[0] = ofs[1] = ofs[2] = 0.0f;
978                 }
979         }
980         else
981                 ofs[0] = ofs[1] = ofs[2] = 0.0f;
982         
983         initgrabz(-G.vd->ofs[0], -G.vd->ofs[1], -G.vd->ofs[2]);
984         
985         reverse= 1.0f;
986         if (G.vd->persmat[2][1] < 0.0f)
987                 reverse= -1.0f;
988
989         while(TRUE) {
990                 getmouseco_sc(mval);
991                 
992                 // if playanim = alt+A, screenhandlers are for animated UI, python, etc
993                 if(             (mode==2 && U.viewzoom==USER_ZOOM_CONT) || /* continues zoom always update */
994                                 mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || /* mouse moved, so update */
995                                 (G.f & G_PLAYANIM) || do_screenhandlers(G.curscreen)
996                         ) {
997                         
998                         if(firsttime) {
999                                 
1000                                 firsttime= 0;
1001                                 /* are we translating, rotating or zooming? */
1002                                 if(mode==0) {
1003                                         if(G.vd->view!=0) scrarea_queue_headredraw(curarea);    /*for button */
1004                                 }
1005                                 if(G.vd->persp==V3D_CAMOB && mode!=1 && G.vd->camera) {
1006                                         G.vd->persp= V3D_PERSP;
1007                                         scrarea_do_windraw(curarea);
1008                                         scrarea_queue_headredraw(curarea);
1009                                 }
1010                         }
1011
1012                         if(mode==0) {   /* view rotate */
1013                                 G.vd->view= 0; /* need to reset everytime because of view snapping */
1014                 
1015                                 if (U.uiflag & USER_AUTOPERSP) G.vd->persp= V3D_PERSP;
1016
1017                                 if (U.flag & USER_TRACKBALL) mvalball[0]= mval[0];
1018                                 mvalball[1]= mval[1];
1019                                 
1020                                 calctrackballvec(&curarea->winrct, mvalball, newvec);
1021                                 
1022                                 VecSubf(dvec, newvec, firstvec);
1023                                 
1024                                 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
1025                                 si/= (2.0*TRACKBALLSIZE);
1026                         
1027                                 if (U.flag & USER_TRACKBALL) {
1028                                         Crossf(q1+1, firstvec, newvec);
1029         
1030                                         Normalize(q1+1);
1031         
1032                                         /* Allow for rotation beyond the interval
1033                                          * [-pi, pi] */
1034                                         while (si > 1.0)
1035                                                 si -= 2.0;
1036                 
1037                                         /* This relation is used instead of
1038                                          * phi = asin(si) so that the angle
1039                                          * of rotation is linearly proportional
1040                                          * to the distance that the mouse is
1041                                          * dragged. */
1042                                         phi = si * M_PI / 2.0;
1043                 
1044                                         si= sin(phi);
1045                                         q1[0]= cos(phi);
1046                                         q1[1]*= si;
1047                                         q1[2]*= si;
1048                                         q1[3]*= si;     
1049                                         QuatMul(G.vd->viewquat, q1, oldquat);
1050
1051                                         if (use_sel) {
1052                                                 /* compute the post multiplication quat, to rotate the offset correctly */
1053                                                 QUATCOPY(q1, oldquat);
1054                                                 QuatConj(q1);
1055                                                 QuatMul(q1, q1, G.vd->viewquat);
1056
1057                                                 QuatConj(q1); /* conj == inv for unit quat */
1058                                                 VECCOPY(G.vd->ofs, ofs);
1059                                                 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
1060                                                 QuatMulVecf(q1, G.vd->ofs);
1061                                                 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
1062                                         }
1063                                 } else {
1064                                         /* New turntable view code by John Aughey */
1065
1066                                         float m[3][3];
1067                                         float m_inv[3][3];
1068                                         float xvec[3] = {1,0,0};
1069                                         /* Sensitivity will control how fast the viewport rotates.  0.0035 was
1070                                            obtained experimentally by looking at viewport rotation sensitivities
1071                                            on other modeling programs. */
1072                                         /* Perhaps this should be a configurable user parameter. */
1073                                         const float sensitivity = 0.0035;
1074
1075                                         /* Get the 3x3 matrix and its inverse from the quaternion */
1076                                         QuatToMat3(G.vd->viewquat, m);
1077                                         Mat3Inv(m_inv,m);
1078
1079                                         /* Determine the direction of the x vector (for rotating up and down) */
1080                                         /* This can likely be compuated directly from the quaternion. */
1081                                         Mat3MulVecfl(m_inv,xvec);
1082
1083                                         /* Perform the up/down rotation */
1084                                         phi = sensitivity * -(mval[1] - mvalo[1]);
1085                                         si = sin(phi);
1086                                         q1[0] = cos(phi);
1087                                         q1[1] = si * xvec[0];
1088                                         q1[2] = si * xvec[1];
1089                                         q1[3] = si * xvec[2];
1090                                         QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
1091
1092                                         if (use_sel) {
1093                                                 QuatConj(q1); /* conj == inv for unit quat */
1094                                                 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
1095                                                 QuatMulVecf(q1, G.vd->ofs);
1096                                                 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
1097                                         }
1098
1099                                         /* Perform the orbital rotation */
1100                                         phi = sensitivity * reverse * (mval[0] - mvalo[0]);
1101                                         q1[0] = cos(phi);
1102                                         q1[1] = q1[2] = 0.0;
1103                                         q1[3] = sin(phi);
1104                                         QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
1105
1106                                         if (use_sel) {
1107                                                 QuatConj(q1);
1108                                                 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
1109                                                 QuatMulVecf(q1, G.vd->ofs);
1110                                                 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
1111                                         }
1112                                 }
1113                                 
1114                                 /* check for view snap */
1115                                 if (G.qual==LR_CTRLKEY){
1116                                         int i;
1117                                         float viewmat[3][3];
1118
1119                                         static const float thres = 0.93f; //cos(20 deg);
1120                                         
1121                                         static float snapquats[39][6] = {
1122                                                 /*{q0, q1, q3, q4, view, oposite_direction}*/
1123                                                 {COS45, -SIN45, 0.0, 0.0, 1, 0},  //front
1124                                                 {0.0, 0.0, -SIN45, -SIN45, 1, 1}, //back
1125                                                 {1.0, 0.0, 0.0, 0.0, 7, 0},       //top
1126                                                 {0.0, -1.0, 0.0, 0.0, 7, 1},      //bottom
1127                                                 {0.5, -0.5, -0.5, -0.5, 3, 0},    //left
1128                                                 {0.5, -0.5, 0.5, 0.5, 3, 1},      //right
1129                                                 
1130                                                 /* some more 45 deg snaps */
1131                                                 {0.65328145027160645, -0.65328145027160645, 0.27059805393218994, 0.27059805393218994, 0, 0},
1132                                                 {0.92387950420379639, 0.0, 0.0, 0.38268342614173889, 0, 0},
1133                                                 {0.0, -0.92387950420379639, 0.38268342614173889, 0.0, 0, 0},
1134                                                 {0.35355335474014282, -0.85355335474014282, 0.35355338454246521, 0.14644660055637360, 0, 0},
1135                                                 {0.85355335474014282, -0.35355335474014282, 0.14644660055637360, 0.35355338454246521, 0, 0},
1136                                                 {0.49999994039535522, -0.49999994039535522, 0.49999997019767761, 0.49999997019767761, 0, 0},
1137                                                 {0.27059802412986755, -0.65328145027160645, 0.65328145027160645, 0.27059802412986755, 0, 0},
1138                                                 {0.65328145027160645, -0.27059802412986755, 0.27059802412986755, 0.65328145027160645, 0, 0},
1139                                                 {0.27059799432754517, -0.27059799432754517, 0.65328139066696167, 0.65328139066696167, 0, 0},
1140                                                 {0.38268336653709412, 0.0, 0.0, 0.92387944459915161, 0, 0},
1141                                                 {0.0, -0.38268336653709412, 0.92387944459915161, 0.0, 0, 0},
1142                                                 {0.14644658565521240, -0.35355335474014282, 0.85355335474014282, 0.35355335474014282, 0, 0},
1143                                                 {0.35355335474014282, -0.14644658565521240, 0.35355335474014282, 0.85355335474014282, 0, 0},
1144                                                 {0.0, 0.0, 0.92387944459915161, 0.38268336653709412, 0, 0},
1145                                                 {-0.0, 0.0, 0.38268336653709412, 0.92387944459915161, 0, 0},
1146                                                 {-0.27059802412986755, 0.27059802412986755, 0.65328133106231689, 0.65328133106231689, 0, 0},
1147                                                 {-0.38268339633941650, 0.0, 0.0, 0.92387938499450684, 0, 0},
1148                                                 {0.0, 0.38268339633941650, 0.92387938499450684, 0.0, 0, 0},
1149                                                 {-0.14644658565521240, 0.35355338454246521, 0.85355329513549805, 0.35355332493782043, 0, 0},
1150                                                 {-0.35355338454246521, 0.14644658565521240, 0.35355332493782043, 0.85355329513549805, 0, 0},
1151                                                 {-0.49999991059303284, 0.49999991059303284, 0.49999985098838806, 0.49999985098838806, 0, 0},
1152                                                 {-0.27059799432754517, 0.65328145027160645, 0.65328139066696167, 0.27059799432754517, 0, 0},
1153                                                 {-0.65328145027160645, 0.27059799432754517, 0.27059799432754517, 0.65328139066696167, 0, 0},
1154                                                 {-0.65328133106231689, 0.65328133106231689, 0.27059793472290039, 0.27059793472290039, 0, 0},
1155                                                 {-0.92387932538986206, 0.0, 0.0, 0.38268333673477173, 0, 0},
1156                                                 {0.0, 0.92387932538986206, 0.38268333673477173, 0.0, 0, 0},
1157                                                 {-0.35355329513549805, 0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0, 0},
1158                                                 {-0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0.35355329513549805, 0, 0},
1159                                                 {-0.38268330693244934, 0.92387938499450684, 0.0, 0.0, 0, 0},
1160                                                 {-0.92387938499450684, 0.38268330693244934, 0.0, 0.0, 0, 0},
1161                                                 {-COS45, 0.0, 0.0, SIN45, 0, 0},
1162                                                 {COS45, 0.0, 0.0, SIN45, 0, 0},
1163                                                 {0.0, 0.0, 0.0, 1.0, 0, 0}
1164                                         };
1165
1166                                         QuatToMat3(G.vd->viewquat, viewmat);
1167
1168                                         for (i = 0 ; i < 39; i++){
1169                                                 float snapmat[3][3];
1170                                                 float view = (int)snapquats[i][4];
1171                                                 float oposite_dir = (int)snapquats[i][5];
1172                                                 
1173                                                 QuatToMat3(snapquats[i], snapmat);
1174                                                 
1175                                                 if ((Inpf(snapmat[0], viewmat[0]) > thres) &&
1176                                                         (Inpf(snapmat[1], viewmat[1]) > thres) &&
1177                                                         (Inpf(snapmat[2], viewmat[2]) > thres)){
1178                                                         
1179                                                         QUATCOPY(G.vd->viewquat, snapquats[i]);
1180                                                         
1181                                                         G.vd->view = view;
1182                                                         if (view){
1183                                                                 if (oposite_dir){
1184                                                                         G.vd->flag2 |= V3D_OPP_DIRECTION_NAME;
1185                                                                 }else{
1186                                                                         G.vd->flag2 &= ~V3D_OPP_DIRECTION_NAME;
1187                                                                 }
1188                                                         }
1189                                                         
1190                                                         break;
1191                                                 }
1192                                         }
1193                                 }
1194                         }
1195                         else if(mode==1) {      /* translate */
1196                                 if(G.vd->persp==V3D_CAMOB) {
1197                                         float max= (float)MAX2(curarea->winx, curarea->winy);
1198
1199                                         G.vd->camdx += (mvalo[0]-mval[0])/(max);
1200                                         G.vd->camdy += (mvalo[1]-mval[1])/(max);
1201                                         CLAMP(G.vd->camdx, -1.0f, 1.0f);
1202                                         CLAMP(G.vd->camdy, -1.0f, 1.0f);
1203                                         preview3d_event= 0;
1204                                 }
1205                                 else {
1206                                         window_to_3d(dvec, mval[0]-mvalo[0], mval[1]-mvalo[1]);
1207                                         VecAddf(G.vd->ofs, G.vd->ofs, dvec);
1208                                 }
1209                         }
1210                         else if(mode==2) {
1211                                 float zfac=1.0;
1212
1213                                 /* use initial value (do not use mvalo (that is used to detect mouse moviments)) */
1214                                 mvalo[0] = mvali[0];
1215                                 mvalo[1] = mvali[1];
1216                                 
1217                                 if(U.viewzoom==USER_ZOOM_CONT) {
1218                                         // oldstyle zoom
1219                                         zfac = 1.0+(float)(mvalo[0]-mval[0]+mvalo[1]-mval[1])/1000.0;
1220                                 }
1221                                 else if(U.viewzoom==USER_ZOOM_SCALE) {
1222                                         int ctr[2], len1, len2;
1223                                         // method which zooms based on how far you move the mouse
1224                                         
1225                                         ctr[0] = (curarea->winrct.xmax + curarea->winrct.xmin)/2;
1226                                         ctr[1] = (curarea->winrct.ymax + curarea->winrct.ymin)/2;
1227                                         
1228                                         len1 = (int)sqrt((ctr[0] - mval[0])*(ctr[0] - mval[0]) + (ctr[1] - mval[1])*(ctr[1] - mval[1])) + 5;
1229                                         len2 = (int)sqrt((ctr[0] - mvalo[0])*(ctr[0] - mvalo[0]) + (ctr[1] - mvalo[1])*(ctr[1] - mvalo[1])) + 5;
1230                                         
1231                                         zfac = dist0 * ((float)len2/len1) / G.vd->dist;
1232                                 }
1233                                 else {  /* USER_ZOOM_DOLLY */
1234                                         float len1 = (curarea->winrct.ymax - mval[1]) + 5;
1235                                         float len2 = (curarea->winrct.ymax - mvalo[1]) + 5;
1236                                         zfac = dist0 * (2.0*((len2/len1)-1.0) + 1.0) / G.vd->dist;
1237                                 }
1238
1239                                 if(zfac != 1.0 && zfac*G.vd->dist > 0.001*G.vd->grid && 
1240                                         zfac*G.vd->dist < 10.0*G.vd->far)
1241                                         view_zoom_mouseloc(zfac, mval_area);
1242                                 
1243                                 
1244                                 if ((U.uiflag & USER_ORBIT_ZBUF) && (U.viewzoom==USER_ZOOM_CONT) && (G.vd->persp==V3D_PERSP)) {
1245                                         /* Secret apricot feature, translate the view when in continues mode */
1246                                         upvec[0] = upvec[1] = 0;
1247                                         upvec[2] = (dist0 - G.vd->dist) * G.vd->grid;
1248                                         G.vd->dist = dist0;
1249                                         Mat3CpyMat4(mat, G.vd->viewinv);
1250                                         Mat3MulVecfl(mat, upvec);
1251                                         VecAddf(G.vd->ofs, G.vd->ofs, upvec);
1252                                 } else {
1253                                         /* these limits are in toets.c too */
1254                                         if(G.vd->dist<0.001*G.vd->grid) G.vd->dist= 0.001*G.vd->grid;
1255                                         if(G.vd->dist>10.0*G.vd->far) G.vd->dist=10.0*G.vd->far;
1256                                 }
1257                                 
1258                                 if(G.vd->persp==V3D_ORTHO || G.vd->persp==V3D_CAMOB) preview3d_event= 0;
1259                         }
1260                         
1261                         
1262                         
1263                         mvalo[0]= mval[0];
1264                         mvalo[1]= mval[1];
1265
1266                         if(G.f & G_PLAYANIM) inner_play_anim_loop(0, 0);
1267
1268                         /* If in retopo paint mode, update lines */
1269                         if(retopo_mesh_paint_check() && G.vd->retopo_view_data) {
1270                                 G.vd->retopo_view_data->queue_matrix_update= 1;
1271                                 retopo_paint_view_update(G.vd);
1272                         }
1273
1274                         scrarea_do_windraw(curarea);
1275                         screen_swapbuffers();
1276                 }
1277                 else {
1278                         short val;
1279                         unsigned short event;
1280                         /* we need to empty the queue... when you do this very long it overflows */
1281                         while(qtest()) event= extern_qread(&val);
1282                         
1283                         BIF_wait_for_statechange();
1284                 }
1285                 
1286                 /* this in the end, otherwise get_mbut does not work on a PC... */
1287                 if( !(get_mbut() & (L_MOUSE|M_MOUSE))) break;
1288         }
1289
1290         if(G.vd->depths) G.vd->depths->damaged= 1;
1291         retopo_queue_updates(G.vd);
1292         allqueue(REDRAWVIEW3D, 0);
1293
1294         if(preview3d_event) 
1295                 BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1296         else
1297                 BIF_view3d_previewrender_signal(curarea, PR_PROJECTED);
1298
1299 }
1300  
1301 void view_zoom_mouseloc(float dfac, short *mouseloc)
1302 {
1303         if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
1304                 short vb[2];
1305                 float dvec[3];
1306                 float tvec[3];
1307                 float tpos[3];
1308                 float new_dist;
1309
1310                 /* find the current window width and height */
1311                 vb[0] = G.vd->area->winx;
1312                 vb[1] = G.vd->area->winy;
1313                 
1314                 tpos[0] = -G.vd->ofs[0];
1315                 tpos[1] = -G.vd->ofs[1];
1316                 tpos[2] = -G.vd->ofs[2];
1317
1318                 /* Project cursor position into 3D space */
1319                 initgrabz(tpos[0], tpos[1], tpos[2]);
1320                 window_to_3d(dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2);
1321
1322                 /* Calculate view target position for dolly */
1323                 tvec[0] = -(tpos[0] + dvec[0]);
1324                 tvec[1] = -(tpos[1] + dvec[1]);
1325                 tvec[2] = -(tpos[2] + dvec[2]);
1326
1327                 /* Offset to target position and dolly */
1328                 new_dist = G.vd->dist * dfac;
1329                 
1330                 VECCOPY(G.vd->ofs, tvec);
1331                 G.vd->dist = new_dist;
1332                 
1333                 /* Calculate final offset */
1334                 dvec[0] = tvec[0] + dvec[0] * dfac;
1335                 dvec[1] = tvec[1] + dvec[1] * dfac;
1336                 dvec[2] = tvec[2] + dvec[2] * dfac;
1337                 
1338                 VECCOPY(G.vd->ofs, dvec);
1339         } else {
1340                 G.vd->dist *= dfac;
1341         }
1342 }
1343
1344 void viewmoveNDOF(int mode)
1345 {
1346     float fval[7];
1347     float dvec[3];
1348     float sbadjust = 1.0f;
1349     float len;
1350         short use_sel = 0;
1351         Object *ob = OBACT;
1352     float m[3][3];
1353     float m_inv[3][3];
1354     float xvec[3] = {1,0,0};
1355     float yvec[3] = {0,-1,0};
1356     float zvec[3] = {0,0,1};
1357         float phi, si;
1358     float q1[4];
1359     float obofs[3];
1360     float reverse;
1361     //float diff[4];
1362     float d, curareaX, curareaY;
1363     float mat[3][3];
1364     float upvec[3];
1365
1366     /* Sensitivity will control how fast the view rotates.  The value was
1367      * obtained experimentally by tweaking until the author didn't get dizzy watching.
1368      * Perhaps this should be a configurable user parameter. 
1369      */
1370     float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
1371     float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
1372     float zsens = 0.3f;   /* zoom sensitivity */
1373
1374     const float minZoom = -30.0f;
1375     const float maxZoom = 300.0f;
1376
1377         //reset view type
1378         G.vd->view = 0;
1379 //printf("passing here \n");
1380 //
1381         if (G.obedit==NULL && ob && !(ob->flag & OB_POSEMODE)) {
1382                 use_sel = 1;
1383         }
1384
1385     if((dz_flag)||G.vd->dist==0) {
1386                 dz_flag = 0;
1387                 G.vd->dist = m_dist;
1388                 upvec[0] = upvec[1] = 0;
1389                 upvec[2] = G.vd->dist;
1390                 Mat3CpyMat4(mat, G.vd->viewinv);
1391                 Mat3MulVecfl(mat, upvec);
1392                 VecAddf(G.vd->ofs, G.vd->ofs, upvec);
1393         }
1394
1395     /*----------------------------------------------------
1396          * sometimes this routine is called from headerbuttons
1397      * viewmove needs to refresh the screen
1398      */
1399         areawinset(curarea->win);
1400
1401     /*----------------------------------------------------
1402      * record how much time has passed. clamp at 10 Hz
1403      * pretend the previous frame occured at the clamped time 
1404      */
1405 //    now = PIL_check_seconds_timer();
1406  //   frametime = (now - prevTime);
1407  //   if (frametime > 0.1f){        /* if more than 1/10s */
1408  //       frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
1409 //    }
1410 //    prevTime = now;
1411  //   sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
1412
1413     /* fetch the current state of the ndof device & enforce dominant mode if selected */
1414     getndof(fval);
1415         if (G.vd->ndoffilter)
1416                 filterNDOFvalues(fval);
1417         
1418         
1419     // put scaling back here, was previously in ghostwinlay
1420     fval[0] = fval[0] * (1.0f/600.0f);
1421     fval[1] = fval[1] * (1.0f/600.0f);
1422     fval[2] = fval[2] * (1.0f/1100.0f);
1423     fval[3] = fval[3] * 0.00005f;
1424     fval[4] =-fval[4] * 0.00005f;
1425     fval[5] = fval[5] * 0.00005f;
1426     fval[6] = fval[6] / 1000000.0f;
1427                         
1428     // scale more if not in perspective mode
1429     if (G.vd->persp == V3D_ORTHO) {
1430         fval[0] = fval[0] * 0.05f;
1431         fval[1] = fval[1] * 0.05f;
1432         fval[2] = fval[2] * 0.05f;
1433         fval[3] = fval[3] * 0.9f;
1434         fval[4] = fval[4] * 0.9f;
1435         fval[5] = fval[5] * 0.9f;
1436         zsens *= 8;
1437     }
1438                         
1439         
1440     /* set object offset */
1441         if (ob) {
1442                 obofs[0] = -ob->obmat[3][0];
1443                 obofs[1] = -ob->obmat[3][1];
1444                 obofs[2] = -ob->obmat[3][2];
1445         }
1446         else {
1447                 VECCOPY(obofs, G.vd->ofs);
1448         }
1449
1450     /* calc an adjustment based on distance from camera
1451        disabled per patch 14402 */
1452      d = 1.0f;
1453
1454 /*    if (ob) {
1455         VecSubf(diff, obofs, G.vd->ofs);
1456         d = VecLength(diff);
1457     }
1458 */
1459
1460     reverse = (G.vd->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
1461
1462     /*----------------------------------------------------
1463      * ndof device pan 
1464      */
1465     psens *= 1.0f + d;
1466     curareaX = sbadjust * psens * fval[0];
1467     curareaY = sbadjust * psens * fval[1];
1468     dvec[0] = curareaX * G.vd->persinv[0][0] + curareaY * G.vd->persinv[1][0];
1469     dvec[1] = curareaX * G.vd->persinv[0][1] + curareaY * G.vd->persinv[1][1];
1470     dvec[2] = curareaX * G.vd->persinv[0][2] + curareaY * G.vd->persinv[1][2];
1471     VecAddf(G.vd->ofs, G.vd->ofs, dvec);
1472
1473     /*----------------------------------------------------
1474      * ndof device dolly 
1475      */
1476     len = zsens * sbadjust * fval[2];
1477
1478     if (G.vd->persp==V3D_CAMOB) {
1479         if(G.vd->persp==V3D_CAMOB) { /* This is stupid, please fix - TODO */
1480             G.vd->camzoom+= 10.0f * -len;
1481         }
1482         if (G.vd->camzoom < minZoom) G.vd->camzoom = minZoom;
1483         else if (G.vd->camzoom > maxZoom) G.vd->camzoom = maxZoom;
1484     }
1485     else if ((G.vd->dist> 0.001*G.vd->grid) && (G.vd->dist<10.0*G.vd->far)) {
1486         G.vd->dist*=(1.0 + len);
1487     }
1488
1489
1490     /*----------------------------------------------------
1491      * ndof device turntable
1492      * derived from the turntable code in viewmove
1493      */
1494
1495     /* Get the 3x3 matrix and its inverse from the quaternion */
1496     QuatToMat3(G.vd->viewquat, m);
1497     Mat3Inv(m_inv,m);
1498
1499     /* Determine the direction of the x vector (for rotating up and down) */
1500     /* This can likely be compuated directly from the quaternion. */
1501     Mat3MulVecfl(m_inv,xvec);
1502     Mat3MulVecfl(m_inv,yvec);
1503     Mat3MulVecfl(m_inv,zvec);
1504
1505     /* Perform the up/down rotation */
1506     phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
1507     si = sin(phi);
1508     q1[0] = cos(phi);
1509     q1[1] = si * xvec[0];
1510     q1[2] = si * xvec[1];
1511     q1[3] = si * xvec[2];
1512     QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
1513
1514     if (use_sel) {
1515         QuatConj(q1); /* conj == inv for unit quat */
1516         VecSubf(G.vd->ofs, G.vd->ofs, obofs);
1517         QuatMulVecf(q1, G.vd->ofs);
1518         VecAddf(G.vd->ofs, G.vd->ofs, obofs);
1519     }
1520
1521     /* Perform the orbital rotation */
1522     /* Perform the orbital rotation 
1523        If the seen Up axis is parallel to the zoom axis, rotation should be
1524        achieved with a pure Roll motion (no Spin) on the device. When you start 
1525        to tilt, moving from Top to Side view, Spinning will increasingly become 
1526        more relevant while the Roll component will decrease. When a full 
1527        Side view is reached, rotations around the world's Up axis are achieved
1528        with a pure Spin-only motion.  In other words the control of the spinning
1529        around the world's Up axis should move from the device's Spin axis to the
1530        device's Roll axis depending on the orientation of the world's Up axis 
1531        relative to the screen. */
1532     //phi = sbadjust * rsens * reverse * fval[4];  /* spin the knob, y axis */
1533     phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
1534     q1[0] = cos(phi);
1535     q1[1] = q1[2] = 0.0;
1536     q1[3] = sin(phi);
1537     QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
1538
1539     if (use_sel) {
1540         QuatConj(q1);
1541         VecSubf(G.vd->ofs, G.vd->ofs, obofs);
1542         QuatMulVecf(q1, G.vd->ofs);
1543         VecAddf(G.vd->ofs, G.vd->ofs, obofs);
1544     }
1545
1546     /*----------------------------------------------------
1547      * refresh the screen
1548      */
1549     scrarea_do_windraw(curarea);
1550     screen_swapbuffers();
1551 }
1552
1553
1554 /* Gets the lens and clipping values from a camera of lamp type object */
1555 void object_view_settings(Object *ob, float *lens, float *clipsta, float *clipend)
1556 {       
1557         if (!ob) return;
1558         
1559         if(ob->type==OB_LAMP ) {
1560                 Lamp *la = ob->data;
1561                 if (lens) {
1562                         float x1, fac;
1563                         fac= cos( M_PI*la->spotsize/360.0);
1564                         x1= saacos(fac);
1565                         *lens= 16.0*fac/sin(x1);
1566                 }
1567                 if (clipsta)    *clipsta= la->clipsta;
1568                 if (clipend)    *clipend= la->clipend;
1569         }
1570         else if(ob->type==OB_CAMERA) {
1571                 Camera *cam= ob->data;
1572                 if (lens)               *lens= cam->lens;
1573                 if (clipsta)    *clipsta= cam->clipsta;
1574                 if (clipend)    *clipend= cam->clipend;
1575         }
1576 }
1577
1578
1579 int get_view3d_viewplane(int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
1580 {
1581         Camera *cam=NULL;
1582         float lens, fac, x1, y1, x2, y2;
1583         float winx= (float)winxi, winy= (float)winyi;
1584         int orth= 0;
1585         
1586         lens= G.vd->lens;       
1587         
1588         *clipsta= G.vd->near;
1589         *clipend= G.vd->far;
1590
1591 /*      
1592  * Cant use this since we need the fac and x1 values set
1593  * if(G.vd->persp==V3D_CAMOB)
1594                 object_view_settings(G.vd->camera, &lens, &(*clipsta), &(*clipend));*/
1595         
1596         if(G.vd->persp==V3D_CAMOB) {
1597                 if(G.vd->camera) {
1598                         if(G.vd->camera->type==OB_LAMP ) {
1599                                 Lamp *la;
1600                                 
1601                                 la= G.vd->camera->data;
1602                                 fac= cos( M_PI*la->spotsize/360.0);
1603                                 
1604                                 x1= saacos(fac);
1605                                 lens= 16.0*fac/sin(x1);
1606                 
1607                                 *clipsta= la->clipsta;
1608                                 *clipend= la->clipend;
1609                         }
1610                         else if(G.vd->camera->type==OB_CAMERA) {
1611                                 cam= G.vd->camera->data;
1612                                 lens= cam->lens;
1613                                 *clipsta= cam->clipsta;
1614                                 *clipend= cam->clipend;
1615                         }
1616                 }
1617         }
1618         
1619         if(G.vd->persp==V3D_ORTHO) {
1620                 if(winx>winy) x1= -G.vd->dist;
1621                 else x1= -winx*G.vd->dist/winy;
1622                 x2= -x1;
1623
1624                 if(winx>winy) y1= -winy*G.vd->dist/winx;
1625                 else y1= -G.vd->dist;
1626                 y2= -y1;
1627                 
1628                 *clipend *= 0.5;        // otherwise too extreme low zbuffer quality
1629                 *clipsta= - *clipend;
1630                 orth= 1;
1631         }
1632         else {
1633                 /* fac for zoom, also used for camdx */
1634                 if(G.vd->persp==V3D_CAMOB) {
1635                         fac= (1.41421+( (float)G.vd->camzoom )/50.0);
1636                         fac*= fac;
1637                 }
1638                 else fac= 2.0;
1639                 
1640                 /* viewplane size depends... */
1641                 if(cam && cam->type==CAM_ORTHO) {
1642                         /* ortho_scale == 1 means exact 1 to 1 mapping */
1643                         float dfac= 2.0*cam->ortho_scale/fac;
1644                         
1645                         if(winx>winy) x1= -dfac;
1646                         else x1= -winx*dfac/winy;
1647                         x2= -x1;
1648                         
1649                         if(winx>winy) y1= -winy*dfac/winx;
1650                         else y1= -dfac;
1651                         y2= -y1;
1652                         orth= 1;
1653                 }
1654                 else {
1655                         float dfac;
1656                         
1657                         if(winx>winy) dfac= 64.0/(fac*winx*lens);
1658                         else dfac= 64.0/(fac*winy*lens);
1659                         
1660                         x1= - *clipsta * winx*dfac;
1661                         x2= -x1;
1662                         y1= - *clipsta * winy*dfac;
1663                         y2= -y1;
1664                         orth= 0;
1665                 }
1666                 /* cam view offset */
1667                 if(cam) {
1668                         float dx= 0.5*fac*G.vd->camdx*(x2-x1);
1669                         float dy= 0.5*fac*G.vd->camdy*(y2-y1);
1670                         x1+= dx;
1671                         x2+= dx;
1672                         y1+= dy;
1673                         y2+= dy;
1674                 }
1675         }
1676
1677         if(pixsize) {
1678                 float viewfac;
1679
1680                 if(orth) {
1681                         viewfac= (winx >= winy)? winx: winy;
1682                         *pixsize= 1.0f/viewfac;
1683                 }
1684                 else {
1685                         viewfac= (((winx >= winy)? winx: winy)*lens)/32.0;
1686                         *pixsize= *clipsta/viewfac;
1687                 }
1688         }
1689         
1690         viewplane->xmin= x1;
1691         viewplane->ymin= y1;
1692         viewplane->xmax= x2;
1693         viewplane->ymax= y2;
1694         
1695         return orth;
1696 }
1697
1698 /* important to not set windows active in here, can be renderwin for example */
1699 void setwinmatrixview3d(int winx, int winy, rctf *rect)         /* rect: for picking */
1700 {
1701         rctf viewplane;
1702         float clipsta, clipend, x1, y1, x2, y2;
1703         int orth;
1704         
1705         orth= get_view3d_viewplane(winx, winy, &viewplane, &clipsta, &clipend, NULL);
1706 //      printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
1707         x1= viewplane.xmin;
1708         y1= viewplane.ymin;
1709         x2= viewplane.xmax;
1710         y2= viewplane.ymax;
1711         
1712         if(rect) {              /* picking */
1713                 rect->xmin/= (float)curarea->winx;
1714                 rect->xmin= x1+rect->xmin*(x2-x1);
1715                 rect->ymin/= (float)curarea->winy;
1716                 rect->ymin= y1+rect->ymin*(y2-y1);
1717                 rect->xmax/= (float)curarea->winx;
1718                 rect->xmax= x1+rect->xmax*(x2-x1);
1719                 rect->ymax/= (float)curarea->winy;
1720                 rect->ymax= y1+rect->ymax*(y2-y1);
1721                 
1722                 if(orth) myortho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
1723                 else mywindow(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
1724                 
1725         }
1726         else {
1727                 if(orth) myortho(x1, x2, y1, y2, clipsta, clipend);
1728                 else mywindow(x1, x2, y1, y2, clipsta, clipend);
1729         }
1730
1731         /* not sure what this was for? (ton) */
1732         glMatrixMode(GL_PROJECTION);
1733         mygetmatrix(curarea->winmat);
1734         glMatrixMode(GL_MODELVIEW);
1735 }
1736
1737 void obmat_to_viewmat(Object *ob, short smooth)
1738 {
1739         float bmat[4][4];
1740         float tmat[3][3];
1741
1742         G.vd->view= 0; /* dont show the grid */
1743
1744         Mat4CpyMat4(bmat, ob->obmat);
1745         Mat4Ortho(bmat);
1746         Mat4Invert(G.vd->viewmat, bmat);
1747         
1748         /* view quat calculation, needed for add object */
1749         Mat3CpyMat4(tmat, G.vd->viewmat);
1750         if (smooth) {
1751                 float new_quat[4];
1752                 if (G.vd->persp==V3D_CAMOB && G.vd->camera) {
1753                         /* were from a camera view */
1754                         
1755                         float orig_ofs[3];
1756                         float orig_dist= G.vd->dist;
1757                         float orig_lens= G.vd->lens;
1758                         VECCOPY(orig_ofs, G.vd->ofs);
1759                         
1760                         /* Switch from camera view */
1761                         Mat3ToQuat(tmat, new_quat);
1762                         
1763                         G.vd->persp=V3D_PERSP;
1764                         G.vd->dist= 0.0;
1765                         
1766                         view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
1767                         smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
1768                         
1769                         G.vd->persp=V3D_CAMOB; /* just to be polite, not needed */
1770                         
1771                 } else {
1772                         Mat3ToQuat(tmat, new_quat);
1773                         smooth_view(G.vd, NULL, new_quat, NULL, NULL);
1774                 }
1775         } else {
1776                 Mat3ToQuat(tmat, G.vd->viewquat);
1777         }
1778 }
1779
1780 /* dont set windows active in in here, is used by renderwin too */
1781 void setviewmatrixview3d()
1782 {
1783         if(G.vd->persp==V3D_CAMOB) {        /* obs/camera */
1784                 if(G.vd->camera) {
1785                         where_is_object(G.vd->camera);  
1786                         obmat_to_viewmat(G.vd->camera, 0);
1787                 }
1788                 else {
1789                         QuatToMat4(G.vd->viewquat, G.vd->viewmat);
1790                         G.vd->viewmat[3][2]-= G.vd->dist;
1791                 }
1792         }
1793         else {
1794                 
1795                 QuatToMat4(G.vd->viewquat, G.vd->viewmat);
1796                 if(G.vd->persp==V3D_PERSP) G.vd->viewmat[3][2]-= G.vd->dist;
1797                 if(G.vd->ob_centre) {
1798                         Object *ob= G.vd->ob_centre;
1799                         float vec[3];
1800                         
1801                         VECCOPY(vec, ob->obmat[3]);
1802                         if(ob->type==OB_ARMATURE && G.vd->ob_centre_bone[0]) {
1803                                 bPoseChannel *pchan= get_pose_channel(ob->pose, G.vd->ob_centre_bone);
1804                                 if(pchan) {
1805                                         VECCOPY(vec, pchan->pose_mat[3]);
1806                                         Mat4MulVecfl(ob->obmat, vec);
1807                                 }
1808                         }
1809                         i_translate(-vec[0], -vec[1], -vec[2], G.vd->viewmat);
1810                 }
1811                 else i_translate(G.vd->ofs[0], G.vd->ofs[1], G.vd->ofs[2], G.vd->viewmat);
1812         }
1813 }
1814
1815 void setcameratoview3d(void)
1816 {
1817         Object *ob;
1818         float dvec[3];
1819
1820         ob= G.vd->camera;
1821         dvec[0]= G.vd->dist*G.vd->viewinv[2][0];
1822         dvec[1]= G.vd->dist*G.vd->viewinv[2][1];
1823         dvec[2]= G.vd->dist*G.vd->viewinv[2][2];                                        
1824         VECCOPY(ob->loc, dvec);
1825         VecSubf(ob->loc, ob->loc, G.vd->ofs);
1826         G.vd->viewquat[0]= -G.vd->viewquat[0];
1827         /*  */
1828         /*if (ob->transflag & OB_QUAT) {
1829                 QUATCOPY(ob->quat, G.vd->viewquat);
1830         } else {*/
1831                 QuatToEul(G.vd->viewquat, ob->rot);
1832         /*}*/
1833         G.vd->viewquat[0]= -G.vd->viewquat[0];
1834 }
1835
1836 /* IGLuint-> GLuint*/
1837 /* Warning: be sure to account for a negative return value
1838  *   This is an error, "Too many objects in select buffer"
1839  *   and no action should be taken (can crash blender) if this happens
1840  */
1841 short  view3d_opengl_select(unsigned int *buffer, unsigned int bufsize, short x1, short y1, short x2, short y2)
1842 {
1843         rctf rect;
1844         short mval[2], code, hits;
1845
1846         G.f |= G_PICKSEL;
1847         
1848         if(x1==0 && x2==0 && y1==0 && y2==0) {
1849                 getmouseco_areawin(mval);
1850                 rect.xmin= mval[0]-12;  // seems to be default value for bones only now
1851                 rect.xmax= mval[0]+12;
1852                 rect.ymin= mval[1]-12;
1853                 rect.ymax= mval[1]+12;
1854         }
1855         else {
1856                 rect.xmin= x1;
1857                 rect.xmax= x2;
1858                 rect.ymin= y1;
1859                 rect.ymax= y2;
1860         }
1861         /* get rid of overlay button matrix */
1862         persp(PERSP_VIEW);
1863         setwinmatrixview3d(curarea->winx, curarea->winy, &rect);
1864         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
1865         
1866         if(G.vd->drawtype > OB_WIRE) {
1867                 G.vd->zbuf= TRUE;
1868                 glEnable(GL_DEPTH_TEST);
1869         }
1870
1871         if(G.vd->flag & V3D_CLIPPING)
1872                 view3d_set_clipping(G.vd);
1873         
1874         glSelectBuffer( bufsize, (GLuint *)buffer);
1875         glRenderMode(GL_SELECT);
1876         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1877         glPushName(-1);
1878         code= 1;
1879         
1880         if(G.obedit && G.obedit->type==OB_MBALL) {
1881                 draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1882         }
1883         else if ((G.obedit && G.obedit->type==OB_ARMATURE)) {
1884                 if (BIF_fullSketchMode())
1885                 {
1886                         BDR_drawSketchNames();
1887                 }
1888                 else
1889                 {
1890                         draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1891                 }
1892         }
1893         else {
1894                 Base *base;
1895                 
1896                 G.vd->xray= TRUE;       // otherwise it postpones drawing
1897                 for(base= G.scene->base.first; base; base= base->next) {
1898                         if(base->lay & G.vd->lay) {
1899                                 
1900                                 if (base->object->restrictflag & OB_RESTRICT_SELECT)
1901                                         base->selcol= 0;
1902                                 else {
1903                                         base->selcol= code;
1904                                         glLoadName(code);
1905                                         draw_object(base, DRAW_PICKING|DRAW_CONSTCOLOR);
1906                                         
1907                                         /* we draw group-duplicators for selection too */
1908                                         if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1909                                                 ListBase *lb;
1910                                                 DupliObject *dob;
1911                                                 Base tbase;
1912                                                 
1913                                                 tbase.flag= OB_FROMDUPLI;
1914                                                 lb= object_duplilist(G.scene, base->object);
1915                                                 
1916                                                 for(dob= lb->first; dob; dob= dob->next) {
1917                                                         tbase.object= dob->ob;
1918                                                         Mat4CpyMat4(dob->ob->obmat, dob->mat);
1919                                                         
1920                                                         draw_object(&tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1921                                                         
1922                                                         Mat4CpyMat4(dob->ob->obmat, dob->omat);
1923                                                 }
1924                                                 free_object_duplilist(lb);
1925                                         }
1926                                         code++;
1927                                 }                               
1928                         }
1929                 }
1930                 G.vd->xray= FALSE;      // restore
1931         }
1932         
1933         glPopName();    /* see above (pushname) */
1934         hits= glRenderMode(GL_RENDER);
1935
1936         G.f &= ~G_PICKSEL;
1937         setwinmatrixview3d(curarea->winx, curarea->winy, NULL);
1938         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
1939         
1940         if(G.vd->drawtype > OB_WIRE) {
1941                 G.vd->zbuf= 0;
1942                 glDisable(GL_DEPTH_TEST);
1943         }
1944         persp(PERSP_WIN);
1945         
1946         if(G.vd->flag & V3D_CLIPPING)
1947                 view3d_clr_clipping();
1948         
1949         if(hits<0) error("Too many objects in select buffer");
1950         
1951         return hits;
1952 }
1953
1954 float *give_cursor()
1955 {
1956         if(G.vd && G.vd->localview) return G.vd->cursor;
1957         else return G.scene->cursor;
1958 }
1959
1960 unsigned int free_localbit()
1961 {
1962         unsigned int lay;
1963         ScrArea *sa;
1964         bScreen *sc;
1965         
1966         lay= 0;
1967         
1968         /* sometimes we loose a localview: when an area is closed */
1969         /* check all areas: which localviews are in use? */
1970         sc= G.main->screen.first;
1971         while(sc) {
1972                 sa= sc->areabase.first;
1973                 while(sa) {
1974                         SpaceLink *sl= sa->spacedata.first;
1975                         while(sl) {
1976                                 if(sl->spacetype==SPACE_VIEW3D) {
1977                                         View3D *v3d= (View3D*) sl;
1978                                         lay |= v3d->lay;
1979                                 }
1980                                 sl= sl->next;
1981                         }
1982                         sa= sa->next;
1983                 }
1984                 sc= sc->id.next;
1985         }
1986         
1987         if( (lay & 0x01000000)==0) return 0x01000000;
1988         if( (lay & 0x02000000)==0) return 0x02000000;
1989         if( (lay & 0x04000000)==0) return 0x04000000;
1990         if( (lay & 0x08000000)==0) return 0x08000000;
1991         if( (lay & 0x10000000)==0) return 0x10000000;
1992         if( (lay & 0x20000000)==0) return 0x20000000;
1993         if( (lay & 0x40000000)==0) return 0x40000000;
1994         if( (lay & 0x80000000)==0) return 0x80000000;
1995         
1996         return 0;
1997 }
1998
1999
2000 void initlocalview()
2001 {
2002         Base *base;
2003         float size = 0.0, min[3], max[3], afm[3];
2004         unsigned int locallay;
2005         int ok=0;
2006
2007         if(G.vd->localvd) return;
2008
2009         INIT_MINMAX(min, max);
2010
2011         locallay= free_localbit();
2012
2013         if(locallay==0) {
2014                 error("Sorry,  no more than 8 localviews");
2015                 ok= 0;
2016         }
2017         else {
2018                 if(G.obedit) {
2019                         minmax_object(G.obedit, min, max);
2020                         
2021                         ok= 1;
2022                 
2023                         BASACT->lay |= locallay;
2024                         G.obedit->lay= BASACT->lay;
2025                 }
2026                 else {
2027                         base= FIRSTBASE;
2028                         while(base) {
2029                                 if TESTBASE(base)  {
2030                                         minmax_object(base->object, min, max);
2031                                         base->lay |= locallay;
2032                                         base->object->lay= base->lay;
2033                                         ok= 1;
2034                                 }
2035                                 base= base->next;
2036                         }
2037                 }
2038                 
2039                 afm[0]= (max[0]-min[0]);
2040                 afm[1]= (max[1]-min[1]);
2041                 afm[2]= (max[2]-min[2]);
2042                 size= 0.7*MAX3(afm[0], afm[1], afm[2]);
2043                 if(size<=0.01) size= 0.01;
2044         }
2045         
2046         if(ok) {
2047                 G.vd->localvd= MEM_mallocN(sizeof(View3D), "localview");
2048                 memcpy(G.vd->localvd, G.vd, sizeof(View3D));
2049
2050                 G.vd->ofs[0]= -(min[0]+max[0])/2.0;
2051                 G.vd->ofs[1]= -(min[1]+max[1])/2.0;
2052                 G.vd->ofs[2]= -(min[2]+max[2])/2.0;
2053
2054                 G.vd->dist= size;
2055
2056                 // correction for window aspect ratio
2057                 if(curarea->winy>2 && curarea->winx>2) {
2058                         size= (float)curarea->winx/(float)curarea->winy;
2059                         if(size<1.0) size= 1.0/size;
2060                         G.vd->dist*= size;
2061                 }
2062                 
2063                 if (G.vd->persp==V3D_CAMOB) G.vd->persp= V3D_PERSP;
2064                 if (G.vd->near> 0.1) G.vd->near= 0.1;
2065                 
2066                 G.vd->cursor[0]= -G.vd->ofs[0];
2067                 G.vd->cursor[1]= -G.vd->ofs[1];
2068                 G.vd->cursor[2]= -G.vd->ofs[2];
2069
2070                 G.vd->lay= locallay;
2071                 
2072                 countall();
2073                 scrarea_queue_winredraw(curarea);
2074         }
2075         else {
2076                 /* clear flags */ 
2077                 base= FIRSTBASE;
2078                 while(base) {
2079                         if( base->lay & locallay ) {
2080                                 base->lay-= locallay;
2081                                 if(base->lay==0) base->lay= G.vd->layact;
2082                                 if(base->object != G.obedit) base->flag |= SELECT;
2083                                 base->object->lay= base->lay;
2084                         }
2085                         base= base->next;
2086                 }
2087                 scrarea_queue_headredraw(curarea);
2088                 
2089                 G.vd->localview= 0;
2090         }
2091         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
2092 }
2093
2094 void centerview()       /* like a localview without local! */
2095 {
2096         Object *ob= OBACT;
2097         float size, min[3], max[3], afm[3];
2098         int ok=0;
2099         
2100         /* SMOOTHVIEW */
2101         float new_ofs[3];
2102         float new_dist;
2103         
2104         INIT_MINMAX(min, max);
2105
2106         if (G.f & G_WEIGHTPAINT) {
2107                 /* hardcoded exception, we look for the one selected armature */
2108                 /* this is weak code this way, we should make a generic active/selection callback interface once... */
2109                 Base *base;
2110                 for(base=FIRSTBASE; base; base= base->next) {
2111                         if(TESTBASELIB(base)) {
2112                                 if(base->object->type==OB_ARMATURE)
2113                                         if(base->object->flag & OB_POSEMODE)
2114                                                 break;
2115                         }
2116                 }
2117                 if(base)
2118                         ob= base->object;
2119         }
2120         
2121         
2122         if(G.obedit) {
2123                 ok = minmax_verts(min, max);    /* only selected */
2124         }
2125         else if(ob && (ob->flag & OB_POSEMODE)) {
2126                 if(ob->pose) {
2127                         bArmature *arm= ob->data;
2128                         bPoseChannel *pchan;
2129                         float vec[3];
2130                         
2131                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
2132                                 if(pchan->bone->flag & BONE_SELECTED) {
2133                                         if(pchan->bone->layer & arm->layer) {
2134                                                 ok= 1;
2135                                                 VECCOPY(vec, pchan->pose_head);
2136                                                 Mat4MulVecfl(ob->obmat, vec);
2137                                                 DO_MINMAX(vec, min, max);
2138                                                 VECCOPY(vec, pchan->pose_tail);
2139                                                 Mat4MulVecfl(ob->obmat, vec);
2140                                                 DO_MINMAX(vec, min, max);
2141                                         }
2142                                 }
2143                         }
2144                 }
2145         }
2146         else if (FACESEL_PAINT_TEST) {
2147                 ok= minmax_tface(min, max);
2148         }
2149         else if (G.f & G_PARTICLEEDIT) {
2150                 ok= PE_minmax(min, max);
2151         }
2152         else {
2153                 Base *base= FIRSTBASE;
2154                 while(base) {
2155                         if TESTBASE(base)  {
2156                                 minmax_object(base->object, min, max);
2157                                 /* account for duplis */
2158                                 minmax_object_duplis(base->object, min, max);
2159                                 
2160                                 ok= 1;
2161                         }
2162                         base= base->next;
2163                 }
2164         }
2165         
2166         if(ok==0) return;
2167         
2168         afm[0]= (max[0]-min[0]);
2169         afm[1]= (max[1]-min[1]);
2170         afm[2]= (max[2]-min[2]);
2171         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
2172         
2173         if(size <= G.vd->near*1.5f) size= G.vd->near*1.5f;
2174         
2175         new_ofs[0]= -(min[0]+max[0])/2.0f;
2176         new_ofs[1]= -(min[1]+max[1])/2.0f;
2177         new_ofs[2]= -(min[2]+max[2])/2.0f;
2178         
2179         new_dist = size;
2180
2181         /* correction for window aspect ratio */
2182         if(curarea->winy>2 && curarea->winx>2) {
2183                 size= (float)curarea->winx/(float)curarea->winy;
2184                 if(size<1.0f) size= 1.0f/size;
2185                 new_dist*= size;
2186         }
2187         
2188         G.vd->cursor[0]= -new_ofs[0];
2189         G.vd->cursor[1]= -new_ofs[1];
2190         G.vd->cursor[2]= -new_ofs[2];
2191         
2192         if (G.vd->persp==V3D_CAMOB && G.vd->camera) {
2193                 float orig_lens= G.vd->lens;
2194                 
2195                 G.vd->persp=V3D_PERSP;
2196                 G.vd->dist= 0.0f;
2197                 view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
2198                 smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
2199         } else {
2200                 if(G.vd->persp==V3D_CAMOB)
2201                         G.vd->persp= V3D_PERSP;
2202                 
2203                 smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
2204         }
2205         scrarea_queue_winredraw(curarea);
2206         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
2207
2208 }
2209
2210
2211 void restore_localviewdata(View3D *vd)
2212 {
2213         if(vd->localvd==0) return;
2214         
2215         VECCOPY(vd->ofs, vd->localvd->ofs);
2216         vd->dist= vd->localvd->dist;
2217         vd->persp= vd->localvd->persp;
2218         vd->view= vd->localvd->view;
2219         vd->near= vd->localvd->near;
2220         vd->far= vd->localvd->far;
2221         vd->lay= vd->localvd->lay;
2222         vd->layact= vd->localvd->layact;
2223         vd->drawtype= vd->localvd->drawtype;
2224         vd->camera= vd->localvd->camera;
2225         QUATCOPY(vd->viewquat, vd->localvd->viewquat);
2226         
2227 }
2228
2229 void endlocalview(ScrArea *sa)
2230 {
2231         View3D *v3d;
2232         struct Base *base;
2233         unsigned int locallay;
2234         
2235         if(sa->spacetype!=SPACE_VIEW3D) return;
2236         v3d= sa->spacedata.first;
2237         
2238         if(v3d->localvd) {
2239                 
2240                 locallay= v3d->lay & 0xFF000000;
2241                 
2242                 restore_localviewdata(v3d);
2243                 
2244                 MEM_freeN(v3d->localvd);
2245                 v3d->localvd= 0;
2246                 v3d->localview= 0;
2247
2248                 /* for when in other window the layers have changed */
2249                 if(v3d->scenelock) v3d->lay= G.scene->lay;
2250                 
2251                 base= FIRSTBASE;
2252                 while(base) {
2253                         if( base->lay & locallay ) {
2254                                 base->lay-= locallay;
2255                                 if(base->lay==0) base->lay= v3d->layact;
2256                                 if(base->object != G.obedit) {
2257                                         base->flag |= SELECT;
2258                                         base->object->flag |= SELECT;
2259                                 }
2260                                 base->object->lay= base->lay;
2261                         }
2262                         base= base->next;
2263                 }
2264
2265                 countall();
2266                 allqueue(REDRAWVIEW3D, 0);      /* because of select */
2267                 allqueue(REDRAWOOPS, 0);        /* because of select */
2268                 BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
2269         } 
2270 }
2271
2272 void view3d_home(int center)
2273 {
2274         Base *base;
2275         float size, min[3], max[3], afm[3];
2276         int ok= 1, onedone=0;
2277
2278         if(center) {
2279                 min[0]= min[1]= min[2]= 0.0f;
2280                 max[0]= max[1]= max[2]= 0.0f;
2281         }
2282         else {
2283                 INIT_MINMAX(min, max);
2284         }
2285         
2286         for(base= FIRSTBASE; base; base= base->next) {
2287                 if(base->lay & G.vd->lay) {
2288                         onedone= 1;
2289                         minmax_object(base->object, min, max);
2290                 }
2291         }
2292         if(!onedone) return;
2293         
2294         afm[0]= (max[0]-min[0]);
2295         afm[1]= (max[1]-min[1]);
2296         afm[2]= (max[2]-min[2]);
2297         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
2298         if(size==0.0) ok= 0;
2299                 
2300         if(ok) {
2301                 float new_dist;
2302                 float new_ofs[3];
2303                 
2304                 new_dist = size;
2305                 new_ofs[0]= -(min[0]+max[0])/2.0f;
2306                 new_ofs[1]= -(min[1]+max[1])/2.0f;
2307                 new_ofs[2]= -(min[2]+max[2])/2.0f;
2308                 
2309                 // correction for window aspect ratio
2310                 if(curarea->winy>2 && curarea->winx>2) {
2311                         size= (float)curarea->winx/(float)curarea->winy;
2312                         if(size<1.0) size= 1.0f/size;
2313                         new_dist*= size;
2314                 }
2315                 
2316                 if (G.vd->persp==V3D_CAMOB && G.vd->camera) {
2317                         /* switch out of camera view */
2318                         float orig_lens= G.vd->lens;
2319                         
2320                         G.vd->persp= V3D_PERSP;
2321                         G.vd->dist= 0.0;
2322                         view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
2323                         smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
2324                         
2325                 } else {
2326                         if(G.vd->persp==V3D_CAMOB) G.vd->persp= V3D_PERSP;
2327                         smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
2328                 }
2329                 scrarea_queue_winredraw(curarea);
2330         }
2331         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
2332
2333 }
2334
2335
2336 void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3])
2337 {
2338         float alignaxis[3] = {0.0, 0.0, 0.0};
2339         float norm[3], axis[3], angle, new_quat[4];
2340
2341         if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
2342         else alignaxis[-axisidx-1]= -1.0;
2343
2344         VECCOPY(norm, vec);
2345         Normalize(norm);
2346
2347         angle= (float)acos(Inpf(alignaxis, norm));
2348         Crossf(axis, alignaxis, norm);
2349         VecRotToQuat(axis, -angle, new_quat);
2350
2351         v3d->view= 0;
2352         
2353         if (v3d->persp==V3D_CAMOB && v3d->camera) {
2354                 /* switch out of camera view */
2355                 float orig_ofs[3];
2356                 float orig_dist= v3d->dist;
2357                 float orig_lens= v3d->lens;
2358
2359                 VECCOPY(orig_ofs, v3d->ofs);
2360                 G.vd->persp= V3D_PERSP;
2361                 G.vd->dist= 0.0;
2362                 view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens);
2363                 smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
2364         } else {
2365                 if (v3d->persp==V3D_CAMOB) v3d->persp= V3D_PERSP; /* switch out of camera mode */
2366                 smooth_view(v3d, NULL, new_quat, NULL, NULL);
2367         }
2368 }
2369
2370
2371
2372 /* SMOOTHVIEW */
2373 void smooth_view(View3D *v3d, float *ofs, float *quat, float *dist, float *lens)
2374 {
2375         /* View Animation enabled */
2376         if (U.smooth_viewtx) {
2377                 int i;
2378                 char changed = 0;
2379                 float step = 0.0, step_inv;
2380                 float orig_dist;
2381                 float orig_lens;
2382                 float orig_quat[4];
2383                 float orig_ofs[3];
2384                 
2385                 double time_allowed, time_current, time_start;
2386                 
2387                 /* if there is no difference, return */
2388                 changed = 0; /* zero means no difference */
2389                 if (dist) {
2390                         if ((*dist) != v3d->dist)
2391                                 changed = 1;
2392                 }
2393                 
2394                 if (lens) {
2395                         if ((*lens) != v3d->lens)
2396                                 changed = 1;
2397                 }
2398                 
2399                 if (!changed && ofs) {
2400                         if ((ofs[0]!=v3d->ofs[0]) ||
2401                                 (ofs[1]!=v3d->ofs[1]) ||
2402                                 (ofs[2]!=v3d->ofs[2]) )
2403                                 changed = 1;
2404                 }
2405                 
2406                 if (!changed && quat ) {
2407                         if ((quat[0]!=v3d->viewquat[0]) ||
2408                                 (quat[1]!=v3d->viewquat[1]) ||
2409                                 (quat[2]!=v3d->viewquat[2]) ||
2410                                 (quat[3]!=v3d->viewquat[3]) )
2411                                 changed = 1;
2412                 }
2413                 
2414                 /* The new view is different from the old one
2415                  * so animate the view */
2416                 if (changed) {
2417                         
2418                         /* store original values */
2419                         VECCOPY(orig_ofs,       v3d->ofs);
2420                         QUATCOPY(orig_quat,     v3d->viewquat);
2421                         orig_dist =                     v3d->dist;
2422                         orig_lens =                     v3d->lens;
2423                         
2424                         time_allowed= (float)U.smooth_viewtx / 1000.0;
2425                         time_current = time_start = PIL_check_seconds_timer();
2426                         
2427                         /* if this is view rotation only
2428                          * we can decrease the time allowed by
2429                          * the angle between quats 
2430                          * this means small rotations wont lag */
2431                          if (quat && !ofs && !dist) {
2432                                 float vec1[3], vec2[3];
2433                                 VECCOPY(vec1, quat);
2434                                 VECCOPY(vec2, v3d->viewquat);
2435                                 Normalize(vec1);
2436                                 Normalize(vec2);
2437                                 /* scale the time allowed by the rotation */
2438                                 time_allowed *= NormalizedVecAngle2(vec1, vec2)/(M_PI/2); 
2439                          }
2440                         
2441                         while (time_start + time_allowed > time_current) {
2442                                 
2443                                 step =  (float)((time_current-time_start) / time_allowed);
2444                                 
2445                                 /* ease in/out */
2446                                 if (step < 0.5) step = (float)pow(step*2, 2)/2;
2447                                 else                    step = (float)1-(pow(2*(1-step),2)/2);
2448                                 
2449                                 step_inv = 1-step;
2450                                 
2451                                 if (ofs)
2452                                         for (i=0; i<3; i++)
2453                                                 v3d->ofs[i] = ofs[i]*step + orig_ofs[i]*step_inv;
2454                                 
2455                                 
2456                                 if (quat)
2457                                         QuatInterpol(v3d->viewquat, orig_quat, quat, step);
2458                                         
2459                                 if (dist)
2460                                         v3d->dist = ((*dist)*step) + (orig_dist*step_inv);
2461                                 
2462                                 if (lens)
2463                                         v3d->lens = ((*lens)*step) + (orig_lens*step_inv);
2464                                 
2465                                 /*redraw the view*/
2466                                 scrarea_do_windraw(curarea);
2467                                 screen_swapbuffers();
2468                                 
2469                                 time_current= PIL_check_seconds_timer();
2470                         }
2471                 }
2472         }
2473         
2474         /* set these values even if animation is enabled because flaot
2475          * error will make then not quite accurate */
2476         if (ofs)
2477                 VECCOPY(v3d->ofs, ofs);
2478         if (quat)
2479                 QUATCOPY(v3d->viewquat, quat);
2480         if (dist)
2481                 v3d->dist = *dist;
2482         if (lens)
2483                 v3d->lens = *lens;
2484         
2485 }
2486
2487
2488
2489 /* Gets the view trasnformation from a camera
2490  * currently dosnt take camzoom into account
2491  * 
2492  * The dist is not modified for this function, if NULL its assimed zero
2493  * */
2494 void view_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens)
2495 {       
2496         float bmat[4][4];
2497         float imat[4][4];
2498         float tmat[3][3];
2499         
2500         if (!ob) return;
2501         
2502         /* Offset */
2503         if (ofs) {
2504                 where_is_object(ob);
2505                 VECCOPY(ofs, ob->obmat[3]);
2506                 VecMulf(ofs, -1.0f); /*flip the vector*/
2507         }
2508         
2509         /* Quat */
2510         if (quat) {
2511                 Mat4CpyMat4(bmat, ob->obmat);
2512                 Mat4Ortho(bmat);
2513                 Mat4Invert(imat, bmat);
2514                 Mat3CpyMat4(tmat, imat);
2515                 Mat3ToQuat(tmat, quat);
2516         }
2517         
2518         if (dist) {
2519                 float vec[3];
2520                 Mat3CpyMat4(tmat, ob->obmat);
2521                 
2522                 vec[0]= vec[1] = 0.0;
2523                 vec[2]= -(*dist);
2524                 Mat3MulVecfl(tmat, vec);
2525                 VecSubf(ofs, ofs, vec);
2526         }
2527         
2528         /* Lens */
2529         if (lens)
2530                 object_view_settings(ob, lens, NULL, NULL);
2531 }
2532
2533 /* For use with smooth view
2534  * 
2535  * the current view is unchanged, blend between the current view and the
2536  * camera view
2537  * */
2538 void smooth_view_to_camera(View3D *v3d)
2539 {
2540         if (!U.smooth_viewtx || !v3d->camera || G.vd->persp != V3D_CAMOB) {
2541                 return;
2542         } else {
2543                 Object *ob = v3d->camera;
2544                 
2545                 float orig_ofs[3];
2546                 float orig_dist=v3d->dist;
2547                 float orig_lens=v3d->lens;
2548                 float new_dist=0.0;
2549                 float new_lens=35.0;
2550                 float new_quat[4];
2551                 float new_ofs[3];
2552                 
2553                 VECCOPY(orig_ofs, v3d->ofs);
2554                 
2555                 view_settings_from_ob(ob, new_ofs, new_quat, NULL, &new_lens);
2556                 
2557                 G.vd->persp= V3D_PERSP;
2558                 smooth_view(v3d, new_ofs, new_quat, &new_dist, &new_lens);
2559                 VECCOPY(v3d->ofs, orig_ofs);
2560                 v3d->lens= orig_lens;
2561                 v3d->dist = orig_dist; /* restore the dist */
2562                 
2563                 v3d->camera = ob;
2564                 v3d->persp= V3D_CAMOB;
2565         }
2566 }
2567