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