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