3dae0118bf4098e2e3e1a91738293a46c2d67928
[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) {
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         Mat4CpyMat4(bmat, ob->obmat);
1452         Mat4Ortho(bmat);
1453         Mat4Invert(G.vd->viewmat, bmat);
1454         
1455         /* view quat calculation, needed for add object */
1456         Mat3CpyMat4(tmat, G.vd->viewmat);
1457         if (smooth) {
1458                 float new_quat[4];
1459                 if (G.vd->persp==V3D_CAMOB && G.vd->camera) {
1460                         /* were from a camera view */
1461                         
1462                         float orig_ofs[3];
1463                         float orig_dist= G.vd->dist;
1464                         float orig_lens= G.vd->lens;
1465                         VECCOPY(orig_ofs, G.vd->ofs);
1466                         
1467                         /* Switch from camera view */
1468                         Mat3ToQuat(tmat, new_quat);
1469                         
1470                         G.vd->persp=V3D_PERSP;
1471                         G.vd->dist= 0.0;
1472                         
1473                         view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
1474                         smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
1475                         
1476                         G.vd->persp=V3D_CAMOB; /* just to be polite, not needed */
1477                         
1478                 } else {
1479                         Mat3ToQuat(tmat, new_quat);
1480                         smooth_view(G.vd, NULL, new_quat, NULL, NULL);
1481                 }
1482         } else {
1483                 Mat3ToQuat(tmat, G.vd->viewquat);
1484         }
1485 }
1486
1487 /* dont set windows active in in here, is used by renderwin too */
1488 void setviewmatrixview3d()
1489 {
1490         if(G.vd->persp==V3D_CAMOB) {        /* obs/camera */
1491                 if(G.vd->camera) {
1492                         where_is_object(G.vd->camera);  
1493                         obmat_to_viewmat(G.vd->camera, 0);
1494                 }
1495                 else {
1496                         QuatToMat4(G.vd->viewquat, G.vd->viewmat);
1497                         G.vd->viewmat[3][2]-= G.vd->dist;
1498                 }
1499         }
1500         else {
1501                 
1502                 QuatToMat4(G.vd->viewquat, G.vd->viewmat);
1503                 if(G.vd->persp==V3D_PERSP) G.vd->viewmat[3][2]-= G.vd->dist;
1504                 if(G.vd->ob_centre) {
1505                         Object *ob= G.vd->ob_centre;
1506                         float vec[3];
1507                         
1508                         VECCOPY(vec, ob->obmat[3]);
1509                         if(ob->type==OB_ARMATURE && G.vd->ob_centre_bone[0]) {
1510                                 bPoseChannel *pchan= get_pose_channel(ob->pose, G.vd->ob_centre_bone);
1511                                 if(pchan) {
1512                                         VECCOPY(vec, pchan->pose_mat[3]);
1513                                         Mat4MulVecfl(ob->obmat, vec);
1514                                 }
1515                         }
1516                         i_translate(-vec[0], -vec[1], -vec[2], G.vd->viewmat);
1517                 }
1518                 else i_translate(G.vd->ofs[0], G.vd->ofs[1], G.vd->ofs[2], G.vd->viewmat);
1519         }
1520 }
1521
1522 void setcameratoview3d(void)
1523 {
1524         Object *ob;
1525         float dvec[3];
1526
1527         ob= G.vd->camera;
1528         dvec[0]= G.vd->dist*G.vd->viewinv[2][0];
1529         dvec[1]= G.vd->dist*G.vd->viewinv[2][1];
1530         dvec[2]= G.vd->dist*G.vd->viewinv[2][2];                                        
1531         VECCOPY(ob->loc, dvec);
1532         VecSubf(ob->loc, ob->loc, G.vd->ofs);
1533         G.vd->viewquat[0]= -G.vd->viewquat[0];
1534         /*  */
1535         /*if (ob->transflag & OB_QUAT) {
1536                 QUATCOPY(ob->quat, G.vd->viewquat);
1537         } else {*/
1538                 QuatToEul(G.vd->viewquat, ob->rot);
1539         /*}*/
1540         G.vd->viewquat[0]= -G.vd->viewquat[0];
1541 }
1542
1543 /* IGLuint-> GLuint*/
1544 /* Warning: be sure to account for a negative return value
1545  *   This is an error, "Too many objects in select buffer"
1546  *   and no action should be taken (can crash blender) if this happens
1547  */
1548 short  view3d_opengl_select(unsigned int *buffer, unsigned int bufsize, short x1, short y1, short x2, short y2)
1549 {
1550         rctf rect;
1551         short mval[2], code, hits;
1552
1553         G.f |= G_PICKSEL;
1554         
1555         if(x1==0 && x2==0 && y1==0 && y2==0) {
1556                 getmouseco_areawin(mval);
1557                 rect.xmin= mval[0]-12;  // seems to be default value for bones only now
1558                 rect.xmax= mval[0]+12;
1559                 rect.ymin= mval[1]-12;
1560                 rect.ymax= mval[1]+12;
1561         }
1562         else {
1563                 rect.xmin= x1;
1564                 rect.xmax= x2;
1565                 rect.ymin= y1;
1566                 rect.ymax= y2;
1567         }
1568         /* get rid of overlay button matrix */
1569         persp(PERSP_VIEW);
1570         setwinmatrixview3d(curarea->winx, curarea->winy, &rect);
1571         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
1572         
1573         if(G.vd->drawtype > OB_WIRE) {
1574                 G.vd->zbuf= TRUE;
1575                 glEnable(GL_DEPTH_TEST);
1576         }
1577
1578         if(G.vd->flag & V3D_CLIPPING)
1579                 view3d_set_clipping(G.vd);
1580         
1581         glSelectBuffer( bufsize, (GLuint *)buffer);
1582         glRenderMode(GL_SELECT);
1583         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1584         glPushName(-1);
1585         code= 1;
1586         
1587         if(G.obedit && G.obedit->type==OB_MBALL) {
1588                 draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1589         }
1590         else if ((G.obedit && G.obedit->type==OB_ARMATURE)) {
1591                 draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1592         }
1593         else {
1594                 Base *base;
1595                 
1596                 G.vd->xray= TRUE;       // otherwise it postpones drawing
1597                 for(base= G.scene->base.first; base; base= base->next) {
1598                         if(base->lay & G.vd->lay) {
1599                                 
1600                                 if (base->object->restrictflag & OB_RESTRICT_SELECT)
1601                                         base->selcol= 0;
1602                                 else {
1603                                         base->selcol= code;
1604                                         glLoadName(code);
1605                                         draw_object(base, DRAW_PICKING|DRAW_CONSTCOLOR);
1606                                         
1607                                         /* we draw group-duplicators for selection too */
1608                                         if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1609                                                 ListBase *lb;
1610                                                 DupliObject *dob;
1611                                                 Base tbase;
1612                                                 
1613                                                 tbase.flag= OB_FROMDUPLI;
1614                                                 lb= object_duplilist(G.scene, base->object);
1615                                                 
1616                                                 for(dob= lb->first; dob; dob= dob->next) {
1617                                                         tbase.object= dob->ob;
1618                                                         Mat4CpyMat4(dob->ob->obmat, dob->mat);
1619                                                         
1620                                                         draw_object(&tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1621                                                         
1622                                                         Mat4CpyMat4(dob->ob->obmat, dob->omat);
1623                                                 }
1624                                                 free_object_duplilist(lb);
1625                                         }
1626                                         code++;
1627                                 }                               
1628                         }
1629                 }
1630                 G.vd->xray= FALSE;      // restore
1631         }
1632         
1633         glPopName();    /* see above (pushname) */
1634         hits= glRenderMode(GL_RENDER);
1635
1636         G.f &= ~G_PICKSEL;
1637         setwinmatrixview3d(curarea->winx, curarea->winy, NULL);
1638         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
1639         
1640         if(G.vd->drawtype > OB_WIRE) {
1641                 G.vd->zbuf= 0;
1642                 glDisable(GL_DEPTH_TEST);
1643         }
1644         persp(PERSP_WIN);
1645         
1646         if(G.vd->flag & V3D_CLIPPING)
1647                 view3d_clr_clipping();
1648         
1649         if(hits<0) error("Too many objects in select buffer");
1650         
1651         return hits;
1652 }
1653
1654 float *give_cursor()
1655 {
1656         if(G.vd && G.vd->localview) return G.vd->cursor;
1657         else return G.scene->cursor;
1658 }
1659
1660 unsigned int free_localbit()
1661 {
1662         unsigned int lay;
1663         ScrArea *sa;
1664         bScreen *sc;
1665         
1666         lay= 0;
1667         
1668         /* sometimes we loose a localview: when an area is closed */
1669         /* check all areas: which localviews are in use? */
1670         sc= G.main->screen.first;
1671         while(sc) {
1672                 sa= sc->areabase.first;
1673                 while(sa) {
1674                         SpaceLink *sl= sa->spacedata.first;
1675                         while(sl) {
1676                                 if(sl->spacetype==SPACE_VIEW3D) {
1677                                         View3D *v3d= (View3D*) sl;
1678                                         lay |= v3d->lay;
1679                                 }
1680                                 sl= sl->next;
1681                         }
1682                         sa= sa->next;
1683                 }
1684                 sc= sc->id.next;
1685         }
1686         
1687         if( (lay & 0x01000000)==0) return 0x01000000;
1688         if( (lay & 0x02000000)==0) return 0x02000000;
1689         if( (lay & 0x04000000)==0) return 0x04000000;
1690         if( (lay & 0x08000000)==0) return 0x08000000;
1691         if( (lay & 0x10000000)==0) return 0x10000000;
1692         if( (lay & 0x20000000)==0) return 0x20000000;
1693         if( (lay & 0x40000000)==0) return 0x40000000;
1694         if( (lay & 0x80000000)==0) return 0x80000000;
1695         
1696         return 0;
1697 }
1698
1699
1700 void initlocalview()
1701 {
1702         Base *base;
1703         float size = 0.0, min[3], max[3], afm[3];
1704         unsigned int locallay;
1705         int ok=0;
1706
1707         if(G.vd->localvd) return;
1708
1709         INIT_MINMAX(min, max);
1710
1711         locallay= free_localbit();
1712
1713         if(locallay==0) {
1714                 error("Sorry,  no more than 8 localviews");
1715                 ok= 0;
1716         }
1717         else {
1718                 if(G.obedit) {
1719                         minmax_object(G.obedit, min, max);
1720                         
1721                         ok= 1;
1722                 
1723                         BASACT->lay |= locallay;
1724                         G.obedit->lay= BASACT->lay;
1725                 }
1726                 else {
1727                         base= FIRSTBASE;
1728                         while(base) {
1729                                 if TESTBASE(base)  {
1730                                         minmax_object(base->object, min, max);
1731                                         base->lay |= locallay;
1732                                         base->object->lay= base->lay;
1733                                         ok= 1;
1734                                 }
1735                                 base= base->next;
1736                         }
1737                 }
1738                 
1739                 afm[0]= (max[0]-min[0]);
1740                 afm[1]= (max[1]-min[1]);
1741                 afm[2]= (max[2]-min[2]);
1742                 size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1743                 if(size<=0.01) size= 0.01;
1744         }
1745         
1746         if(ok) {
1747                 G.vd->localvd= MEM_mallocN(sizeof(View3D), "localview");
1748                 memcpy(G.vd->localvd, G.vd, sizeof(View3D));
1749
1750                 G.vd->ofs[0]= -(min[0]+max[0])/2.0;
1751                 G.vd->ofs[1]= -(min[1]+max[1])/2.0;
1752                 G.vd->ofs[2]= -(min[2]+max[2])/2.0;
1753
1754                 G.vd->dist= size;
1755
1756                 // correction for window aspect ratio
1757                 if(curarea->winy>2 && curarea->winx>2) {
1758                         size= (float)curarea->winx/(float)curarea->winy;
1759                         if(size<1.0) size= 1.0/size;
1760                         G.vd->dist*= size;
1761                 }
1762                 
1763                 if (G.vd->persp==V3D_CAMOB) G.vd->persp= V3D_PERSP;
1764                 if (G.vd->near> 0.1) G.vd->near= 0.1;
1765                 
1766                 G.vd->cursor[0]= -G.vd->ofs[0];
1767                 G.vd->cursor[1]= -G.vd->ofs[1];
1768                 G.vd->cursor[2]= -G.vd->ofs[2];
1769
1770                 G.vd->lay= locallay;
1771                 
1772                 countall();
1773                 scrarea_queue_winredraw(curarea);
1774         }
1775         else {
1776                 /* clear flags */ 
1777                 base= FIRSTBASE;
1778                 while(base) {
1779                         if( base->lay & locallay ) {
1780                                 base->lay-= locallay;
1781                                 if(base->lay==0) base->lay= G.vd->layact;
1782                                 if(base->object != G.obedit) base->flag |= SELECT;
1783                                 base->object->lay= base->lay;
1784                         }
1785                         base= base->next;
1786                 }
1787                 scrarea_queue_headredraw(curarea);
1788                 
1789                 G.vd->localview= 0;
1790         }
1791         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1792 }
1793
1794 void centerview()       /* like a localview without local! */
1795 {
1796         Object *ob= OBACT;
1797         float size, min[3], max[3], afm[3];
1798         int ok=0;
1799         
1800         /* SMOOTHVIEW */
1801         float new_ofs[3];
1802         float new_dist;
1803         
1804         INIT_MINMAX(min, max);
1805
1806         if (G.f & G_WEIGHTPAINT) {
1807                 /* hardcoded exception, we look for the one selected armature */
1808                 /* this is weak code this way, we should make a generic active/selection callback interface once... */
1809                 Base *base;
1810                 for(base=FIRSTBASE; base; base= base->next) {
1811                         if(TESTBASELIB(base)) {
1812                                 if(base->object->type==OB_ARMATURE)
1813                                         if(base->object->flag & OB_POSEMODE)
1814                                                 break;
1815                         }
1816                 }
1817                 if(base)
1818                         ob= base->object;
1819         }
1820         
1821         
1822         if(G.obedit) {
1823                 ok = minmax_verts(min, max);    /* only selected */
1824         }
1825         else if(ob && (ob->flag & OB_POSEMODE)) {
1826                 if(ob->pose) {
1827                         bArmature *arm= ob->data;
1828                         bPoseChannel *pchan;
1829                         float vec[3];
1830                         
1831                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
1832                                 if(pchan->bone->flag & BONE_SELECTED) {
1833                                         if(pchan->bone->layer & arm->layer) {
1834                                                 ok= 1;
1835                                                 VECCOPY(vec, pchan->pose_head);
1836                                                 Mat4MulVecfl(ob->obmat, vec);
1837                                                 DO_MINMAX(vec, min, max);
1838                                                 VECCOPY(vec, pchan->pose_tail);
1839                                                 Mat4MulVecfl(ob->obmat, vec);
1840                                                 DO_MINMAX(vec, min, max);
1841                                         }
1842                                 }
1843                         }
1844                 }
1845         }
1846         else if (FACESEL_PAINT_TEST) {
1847                 ok= minmax_tface(min, max);
1848         }
1849         else if (G.f & G_PARTICLEEDIT) {
1850                 ok= PE_minmax(min, max);
1851         }
1852         else {
1853                 Base *base= FIRSTBASE;
1854                 while(base) {
1855                         if TESTBASE(base)  {
1856                                 minmax_object(base->object, min, max);
1857                                 /* account for duplis */
1858                                 minmax_object_duplis(base->object, min, max);
1859                                 
1860                                 ok= 1;
1861                         }
1862                         base= base->next;
1863                 }
1864         }
1865         
1866         if(ok==0) return;
1867         
1868         afm[0]= (max[0]-min[0]);
1869         afm[1]= (max[1]-min[1]);
1870         afm[2]= (max[2]-min[2]);
1871         size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1872         
1873         if(size <= G.vd->near*1.5) size= G.vd->near*1.5;
1874         
1875         new_ofs[0]= -(min[0]+max[0])/2.0;
1876         new_ofs[1]= -(min[1]+max[1])/2.0;
1877         new_ofs[2]= -(min[2]+max[2])/2.0;
1878         
1879         new_dist = size;
1880
1881         /* correction for window aspect ratio */
1882         if(curarea->winy>2 && curarea->winx>2) {
1883                 size= (float)curarea->winx/(float)curarea->winy;
1884                 if(size<1.0) size= 1.0/size;
1885                 new_dist*= size;
1886         }
1887         
1888         G.vd->cursor[0]= -new_ofs[0];
1889         G.vd->cursor[1]= -new_ofs[1];
1890         G.vd->cursor[2]= -new_ofs[2];
1891         
1892         if (G.vd->persp==V3D_CAMOB && G.vd->camera) {
1893                 float orig_lens= G.vd->lens;
1894                 
1895                 G.vd->persp=V3D_PERSP;
1896                 G.vd->dist= 0.0;
1897                 view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
1898                 smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
1899         } else {
1900                 if(G.vd->persp==V3D_CAMOB)
1901                         G.vd->persp= V3D_PERSP;
1902                 
1903                 smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
1904         }
1905         scrarea_queue_winredraw(curarea);
1906         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1907
1908 }
1909
1910
1911 void restore_localviewdata(View3D *vd)
1912 {
1913         if(vd->localvd==0) return;
1914         
1915         VECCOPY(vd->ofs, vd->localvd->ofs);
1916         vd->dist= vd->localvd->dist;
1917         vd->persp= vd->localvd->persp;
1918         vd->view= vd->localvd->view;
1919         vd->near= vd->localvd->near;
1920         vd->far= vd->localvd->far;
1921         vd->lay= vd->localvd->lay;
1922         vd->layact= vd->localvd->layact;
1923         vd->drawtype= vd->localvd->drawtype;
1924         vd->camera= vd->localvd->camera;
1925         QUATCOPY(vd->viewquat, vd->localvd->viewquat);
1926         
1927 }
1928
1929 void endlocalview(ScrArea *sa)
1930 {
1931         View3D *v3d;
1932         struct Base *base;
1933         unsigned int locallay;
1934         
1935         if(sa->spacetype!=SPACE_VIEW3D) return;
1936         v3d= sa->spacedata.first;
1937         
1938         if(v3d->localvd) {
1939                 
1940                 locallay= v3d->lay & 0xFF000000;
1941                 
1942                 restore_localviewdata(v3d);
1943                 
1944                 MEM_freeN(v3d->localvd);
1945                 v3d->localvd= 0;
1946                 v3d->localview= 0;
1947
1948                 /* for when in other window the layers have changed */
1949                 if(v3d->scenelock) v3d->lay= G.scene->lay;
1950                 
1951                 base= FIRSTBASE;
1952                 while(base) {
1953                         if( base->lay & locallay ) {
1954                                 base->lay-= locallay;
1955                                 if(base->lay==0) base->lay= v3d->layact;
1956                                 if(base->object != G.obedit) {
1957                                         base->flag |= SELECT;
1958                                         base->object->flag |= SELECT;
1959                                 }
1960                                 base->object->lay= base->lay;
1961                         }
1962                         base= base->next;
1963                 }
1964
1965                 countall();
1966                 allqueue(REDRAWVIEW3D, 0);      /* because of select */
1967                 allqueue(REDRAWOOPS, 0);        /* because of select */
1968                 BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1969         } 
1970 }
1971
1972 void view3d_home(int center)
1973 {
1974         Base *base;
1975         float size, min[3], max[3], afm[3];
1976         int ok= 1, onedone=0;
1977
1978         if(center) {
1979                 min[0]= min[1]= min[2]= 0.0;
1980                 max[0]= max[1]= max[2]= 0.0;
1981         }
1982         else {
1983                 INIT_MINMAX(min, max);
1984         }
1985         
1986         for(base= FIRSTBASE; base; base= base->next) {
1987                 if(base->lay & G.vd->lay) {
1988                         onedone= 1;
1989                         minmax_object(base->object, min, max);
1990                 }
1991         }
1992         if(!onedone) return;
1993         
1994         afm[0]= (max[0]-min[0]);
1995         afm[1]= (max[1]-min[1]);
1996         afm[2]= (max[2]-min[2]);
1997         size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1998         if(size==0.0) ok= 0;
1999                 
2000         if(ok) {
2001                 float new_dist;
2002                 float new_ofs[3];
2003                 
2004                 new_dist = size;
2005                 new_ofs[0]= -(min[0]+max[0])/2.0;
2006                 new_ofs[1]= -(min[1]+max[1])/2.0;
2007                 new_ofs[2]= -(min[2]+max[2])/2.0;
2008                 
2009                 // correction for window aspect ratio
2010                 if(curarea->winy>2 && curarea->winx>2) {
2011                         size= (float)curarea->winx/(float)curarea->winy;
2012                         if(size<1.0) size= 1.0/size;
2013                         new_dist*= size;
2014                 }
2015                 
2016                 if (G.vd->persp==V3D_CAMOB && G.vd->camera) {
2017                         /* switch out of camera view */
2018                         float orig_lens= G.vd->lens;
2019                         
2020                         G.vd->persp= V3D_PERSP;
2021                         G.vd->dist= 0.0;
2022                         view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
2023                         smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
2024                         
2025                 } else {
2026                         if(G.vd->persp==V3D_CAMOB) G.vd->persp= V3D_PERSP;
2027                         smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
2028                 }
2029                 scrarea_queue_winredraw(curarea);
2030         }
2031         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
2032
2033 }
2034
2035
2036 void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3])
2037 {
2038         float alignaxis[3] = {0.0, 0.0, 0.0};
2039         float norm[3], axis[3], angle, new_quat[4];
2040
2041         if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
2042         else alignaxis[-axisidx-1]= -1.0;
2043
2044         VECCOPY(norm, vec);
2045         Normalize(norm);
2046
2047         angle= acos(Inpf(alignaxis, norm));
2048         Crossf(axis, alignaxis, norm);
2049         VecRotToQuat(axis, -angle, new_quat);
2050
2051         v3d->view= 0;
2052         
2053         if (v3d->persp==V3D_CAMOB && v3d->camera) {
2054                 /* switch out of camera view */
2055                 float orig_ofs[3];
2056                 float orig_dist= v3d->dist;
2057                 float orig_lens= v3d->lens;
2058
2059                 VECCOPY(orig_ofs, v3d->ofs);
2060                 G.vd->persp= V3D_PERSP;
2061                 G.vd->dist= 0.0;
2062                 view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens);
2063                 smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
2064         } else {
2065                 if (v3d->persp==V3D_CAMOB) v3d->persp= V3D_PERSP; /* switch out of camera mode */
2066                 smooth_view(v3d, NULL, new_quat, NULL, NULL);
2067         }
2068 }
2069
2070
2071
2072 /* SMOOTHVIEW */
2073 void smooth_view(View3D *v3d, float *ofs, float *quat, float *dist, float *lens)
2074 {
2075         /* View Animation enabled */
2076         if (U.smooth_viewtx) {
2077                 int i;
2078                 char changed = 0;
2079                 float step = 0.0, step_inv;
2080                 float orig_dist;
2081                 float orig_lens;
2082                 float orig_quat[4];
2083                 float orig_ofs[3];
2084                 
2085                 double time_allowed, time_current, time_start;
2086                 
2087                 /* if there is no difference, return */
2088                 changed = 0; /* zero means no difference */
2089                 if (dist) {
2090                         if ((*dist) != v3d->dist)
2091                                 changed = 1;
2092                 }
2093                 
2094                 if (lens) {
2095                         if ((*lens) != v3d->lens)
2096                                 changed = 1;
2097                 }
2098                 
2099                 if (!changed && ofs) {
2100                         if ((ofs[0]!=v3d->ofs[0]) ||
2101                                 (ofs[1]!=v3d->ofs[1]) ||
2102                                 (ofs[2]!=v3d->ofs[2]) )
2103                                 changed = 1;
2104                 }
2105                 
2106                 if (!changed && quat ) {
2107                         if ((quat[0]!=v3d->viewquat[0]) ||
2108                                 (quat[1]!=v3d->viewquat[1]) ||
2109                                 (quat[2]!=v3d->viewquat[2]) ||
2110                                 (quat[3]!=v3d->viewquat[3]) )
2111                                 changed = 1;
2112                 }
2113                 
2114                 /* The new view is different from the old one
2115                  * so animate the view */
2116                 if (changed) {
2117                         
2118                         /* store original values */
2119                         VECCOPY(orig_ofs,       v3d->ofs);
2120                         QUATCOPY(orig_quat,     v3d->viewquat);
2121                         orig_dist =                     v3d->dist;
2122                         orig_lens =                     v3d->lens;
2123                         
2124                         time_allowed= (float)U.smooth_viewtx / 1000.0;
2125                         time_current = time_start = PIL_check_seconds_timer();
2126                         
2127                         /* if this is view rotation only
2128                          * we can decrease the time allowed by
2129                          * the angle between quats 
2130                          * this means small rotations wont lag */
2131                          if (quat && !ofs && !dist) {
2132                                 float vec1[3], vec2[3];
2133                                 VECCOPY(vec1, quat);
2134                                 VECCOPY(vec2, v3d->viewquat);
2135                                 Normalize(vec1);
2136                                 Normalize(vec2);
2137                                 /* scale the time allowed by the rotation */
2138                                 time_allowed *= NormalizedVecAngle2(vec1, vec2)/(M_PI/2); 
2139                          }
2140                         
2141                         while (time_start + time_allowed > time_current) {
2142                                 
2143                                 step =  (float)((time_current-time_start) / time_allowed);
2144                                 
2145                                 /* ease in/out */
2146                                 if (step < 0.5) step = pow(step*2, 2)/2;
2147                                 else                    step = 1-(pow(2*(1-step) ,2)/2);
2148                                 
2149                                 step_inv = 1-step;
2150                                 
2151                                 if (ofs)
2152                                         for (i=0; i<3; i++)
2153                                                 v3d->ofs[i] = ofs[i]*step + orig_ofs[i]*step_inv;
2154                                 
2155                                 
2156                                 if (quat)
2157                                         QuatInterpol(v3d->viewquat, orig_quat, quat, step);
2158                                         
2159                                 if (dist)
2160                                         v3d->dist = ((*dist)*step) + (orig_dist*step_inv);
2161                                 
2162                                 if (lens)
2163                                         v3d->lens = ((*lens)*step) + (orig_lens*step_inv);
2164                                 
2165                                 /*redraw the view*/
2166                                 scrarea_do_windraw(curarea);
2167                                 screen_swapbuffers();
2168                                 
2169                                 time_current= PIL_check_seconds_timer();
2170                         }
2171                 }
2172         }
2173         
2174         /* set these values even if animation is enabled because flaot
2175          * error will make then not quite accurate */
2176         if (ofs)
2177                 VECCOPY(v3d->ofs, ofs);
2178         if (quat)
2179                 QUATCOPY(v3d->viewquat, quat);
2180         if (dist)
2181                 v3d->dist = *dist;
2182         if (lens)
2183                 v3d->lens = *lens;
2184         
2185 }
2186
2187
2188
2189 /* Gets the view trasnformation from a camera
2190  * currently dosnt take camzoom into account
2191  * 
2192  * The dist is not modified for this function, if NULL its assimed zero
2193  * */
2194 void view_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens)
2195 {       
2196         float bmat[4][4];
2197         float imat[4][4];
2198         float tmat[3][3];
2199         
2200         if (!ob) return;
2201         
2202         /* Offset */
2203         if (ofs) {
2204                 where_is_object(ob);
2205                 VECCOPY(ofs, ob->obmat[3]);
2206                 VecMulf(ofs, -1.0f); /*flip the vector*/
2207         }
2208         
2209         /* Quat */
2210         if (quat) {
2211                 Mat4CpyMat4(bmat, ob->obmat);
2212                 Mat4Ortho(bmat);
2213                 Mat4Invert(imat, bmat);
2214                 Mat3CpyMat4(tmat, imat);
2215                 Mat3ToQuat(tmat, quat);
2216         }
2217         
2218         if (dist) {
2219                 float vec[3];
2220                 Mat3CpyMat4(tmat, ob->obmat);
2221                 
2222                 vec[0]= vec[1] = 0.0;
2223                 vec[2]= -(*dist);
2224                 Mat3MulVecfl(tmat, vec);
2225                 VecSubf(ofs, ofs, vec);
2226         }
2227         
2228         /* Lens */
2229         if (lens)
2230                 object_view_settings(ob, lens, NULL, NULL);
2231 }
2232
2233 /* For use with smooth view
2234  * 
2235  * the current view is unchanged, blend between the current view and the
2236  * camera view
2237  * */
2238 void smooth_view_to_camera(View3D *v3d)
2239 {
2240         if (!U.smooth_viewtx || !v3d->camera || G.vd->persp != V3D_CAMOB) {
2241                 return;
2242         } else {
2243                 Object *ob = v3d->camera;
2244                 
2245                 float orig_ofs[3];
2246                 float orig_dist=v3d->dist;
2247                 float orig_lens=v3d->lens;
2248                 float new_dist=0.0;
2249                 float new_lens=35.0;
2250                 float new_quat[4];
2251                 float new_ofs[3];
2252                 
2253                 VECCOPY(orig_ofs, v3d->ofs);
2254                 
2255                 view_settings_from_ob(ob, new_ofs, new_quat, NULL, &new_lens);
2256                 
2257                 G.vd->persp= V3D_PERSP;
2258                 smooth_view(v3d, new_ofs, new_quat, &new_dist, &new_lens);
2259                 VECCOPY(v3d->ofs, orig_ofs);
2260                 v3d->lens= orig_lens;
2261                 v3d->dist = orig_dist; /* restore the dist */
2262                 
2263                 v3d->camera = ob;
2264                 v3d->persp= V3D_CAMOB;
2265         }
2266 }