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