c501dbb8f73c1301c91cc948439b87e8c21c08d4
[blender.git] / source / blender / src / view.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * Trackball math (in calctrackballvec())  Copyright (C) Silicon Graphics, Inc.
27  *
28  * The Original Code is: all of this file.
29  *
30  * Contributor(s): none yet.
31  *
32  * ***** END GPL/BL DUAL LICENSE BLOCK *****
33  */
34
35 #include <math.h>
36 #include <string.h>
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #ifdef WIN32
43 #include <io.h>
44 #else
45 #include <unistd.h>
46 #endif   
47
48 #include "MEM_guardedalloc.h"
49
50 #include "BLI_blenlib.h"
51 #include "BLI_arithb.h"
52
53 #include "DNA_action_types.h"
54 #include "DNA_armature_types.h"
55 #include "DNA_camera_types.h"
56 #include "DNA_lamp_types.h"
57 #include "DNA_object_types.h"
58 #include "DNA_screen_types.h"
59 #include "DNA_scene_types.h"
60 #include "DNA_space_types.h"
61 #include "DNA_userdef_types.h"
62 #include "DNA_view3d_types.h"
63
64 #include "BKE_action.h"
65 #include "BKE_anim.h"
66 #include "BKE_global.h"
67 #include "BKE_main.h"
68 #include "BKE_object.h"
69 #include "BKE_utildefines.h"
70
71 #include "BIF_gl.h"
72 #include "BIF_space.h"
73 #include "BIF_mywindow.h"
74 #include "BIF_previewrender.h"
75 #include "BIF_retopo.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
90 #include "PIL_time.h" /* smoothview */
91
92 #define TRACKBALLSIZE  (1.1)
93 #define BL_NEAR_CLIP 0.001
94
95
96 /* local prototypes ----------*/
97 void setcameratoview3d(void); /* windows.c & toets.c */
98
99 void persp_general(int a)
100 {
101         /* for all window types, not 3D */
102         
103         if(a== 0) {
104                 glPushMatrix();
105                 glMatrixMode(GL_PROJECTION);
106                 glPushMatrix();
107                 glMatrixMode(GL_MODELVIEW);
108
109                 myortho2(-0.375, ((float)(curarea->winx))-0.375, -0.375, ((float)(curarea->winy))-0.375);
110                 glLoadIdentity();
111         }
112         else if(a== 1) {
113                 glMatrixMode(GL_PROJECTION);
114                 glPopMatrix();
115                 glMatrixMode(GL_MODELVIEW);
116                 glPopMatrix();
117         }
118 }
119
120 void persp(int a)
121 {
122         /* only 3D windows */
123
124         if(curarea->spacetype!=SPACE_VIEW3D) persp_general(a);
125         else if(a == PERSP_STORE) {             // only store
126                 glMatrixMode(GL_PROJECTION);
127                 mygetmatrix(G.vd->winmat1);     
128                 glMatrixMode(GL_MODELVIEW);
129                 mygetmatrix(G.vd->viewmat1); 
130         }
131         else if(a== PERSP_WIN) {                // only set
132                 myortho2(-0.375, (float)(curarea->winx)-0.375, -0.375, (float)(curarea->winy)-0.375);
133                 glLoadIdentity();
134         }
135         else if(a== PERSP_VIEW) {
136                 glMatrixMode(GL_PROJECTION);
137                 myloadmatrix(G.vd->winmat1); // put back
138                 Mat4CpyMat4(curarea->winmat, G.vd->winmat1); // to be sure? 
139                 glMatrixMode(GL_MODELVIEW); 
140                 myloadmatrix(G.vd->viewmat); // put back
141                 
142         }
143 }
144
145
146 void initgrabz(float x, float y, float z)
147 {
148         if(G.vd==NULL) return;
149         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];
150
151         /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that 
152          * (accounting for near zero values)
153          * */
154         if (G.vd->zfac < 1.e-6f && G.vd->zfac > -1.e-6f) G.vd->zfac = 1.0f;
155 }
156
157 void window_to_3d(float *vec, short mx, short my)
158 {
159         /* always call initgrabz */
160         float dx, dy;
161         
162         dx= 2.0f*mx*G.vd->zfac/curarea->winx;
163         dy= 2.0f*my*G.vd->zfac/curarea->winy;
164         
165         vec[0]= (G.vd->persinv[0][0]*dx + G.vd->persinv[1][0]*dy);
166         vec[1]= (G.vd->persinv[0][1]*dx + G.vd->persinv[1][1]*dy);
167         vec[2]= (G.vd->persinv[0][2]*dx + G.vd->persinv[1][2]*dy);
168 }
169
170 void project_short(float *vec, short *adr)      /* clips */
171 {
172         float fx, fy, vec4[4];
173
174         adr[0]= IS_CLIPPED;
175         
176         if(G.vd->flag & V3D_CLIPPING) {
177                 if(view3d_test_clipping(G.vd, vec))
178                         return;
179         }
180
181         VECCOPY(vec4, vec);
182         vec4[3]= 1.0;
183         Mat4MulVec4fl(G.vd->persmat, vec4);
184         
185         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
186                 fx= (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
187                 
188                 if( fx>0 && fx<curarea->winx) {
189                 
190                         fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
191                         
192                         if(fy>0.0 && fy< (float)curarea->winy) {
193                                 adr[0]= floor(fx); 
194                                 adr[1]= floor(fy);
195                         }
196                 }
197         }
198 }
199
200 void project_int(float *vec, int *adr)
201 {
202         float fx, fy, vec4[4];
203
204         adr[0]= 2140000000.0f;
205         VECCOPY(vec4, vec);
206         vec4[3]= 1.0;
207         
208         Mat4MulVec4fl(G.vd->persmat, vec4);
209
210         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
211                 fx= (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
212                 
213                 if( fx>-2140000000.0f && fx<2140000000.0f) {
214                         fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
215                         
216                         if(fy>-2140000000.0f && fy<2140000000.0f) {
217                                 adr[0]= floor(fx); 
218                                 adr[1]= floor(fy);
219                         }
220                 }
221         }
222 }
223
224 void project_short_noclip(float *vec, short *adr)
225 {
226         float fx, fy, vec4[4];
227
228         adr[0]= IS_CLIPPED;
229         VECCOPY(vec4, vec);
230         vec4[3]= 1.0;
231         
232         Mat4MulVec4fl(G.vd->persmat, vec4);
233
234         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
235                 fx= (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
236                 
237                 if( fx>-32700 && fx<32700) {
238                 
239                         fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
240                         
241                         if(fy>-32700.0 && fy<32700.0) {
242                                 adr[0]= floor(fx); 
243                                 adr[1]= floor(fy);
244                         }
245                 }
246         }
247 }
248
249 void project_float(float *vec, float *adr)
250 {
251         float vec4[4];
252         
253         adr[0]= IS_CLIPPED;
254         VECCOPY(vec4, vec);
255         vec4[3]= 1.0;
256         
257         Mat4MulVec4fl(G.vd->persmat, vec4);
258
259         if( vec4[3]>BL_NEAR_CLIP ) {
260                 adr[0]= (curarea->winx/2.0)+(curarea->winx/2.0)*vec4[0]/vec4[3];        
261                 adr[1]= (curarea->winy/2.0)+(curarea->winy/2.0)*vec4[1]/vec4[3];
262         }
263 }
264
265 void view3d_get_object_project_mat(ScrArea *area, Object *ob, float pmat[4][4], float vmat[4][4])
266 {
267         if (area->spacetype!=SPACE_VIEW3D || !area->spacedata.first) {
268                 Mat4One(pmat);
269                 Mat4One(vmat);
270         } else {
271                 View3D *vd = area->spacedata.first;
272
273                 Mat4MulMat4(vmat, ob->obmat, vd->viewmat);
274                 Mat4MulMat4(pmat, vmat, vd->winmat1);
275                 Mat4CpyMat4(vmat, ob->obmat);
276         }
277 }
278
279 /* projectmat brings it to window coords, wmat to rotated world space */
280 void view3d_project_short_clip(ScrArea *area, float *vec, short *adr, float projmat[4][4], float wmat[4][4])
281 {
282         View3D *v3d= area->spacedata.first;
283         float fx, fy, vec4[4];
284
285         adr[0]= IS_CLIPPED;
286         
287         /* clipplanes in eye space */
288         if(v3d->flag & V3D_CLIPPING) {
289                 VECCOPY(vec4, vec);
290                 Mat4MulVecfl(wmat, vec4);
291                 if(view3d_test_clipping(v3d, vec4))
292                         return;
293         }
294         
295         VECCOPY(vec4, vec);
296         vec4[3]= 1.0;
297         
298         Mat4MulVec4fl(projmat, vec4);
299         
300         /* clipplanes in window space */
301         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
302                 fx= (area->winx/2)*(1 + vec4[0]/vec4[3]);
303                 
304                 if( fx>0 && fx<area->winx) {
305                 
306                         fy= (area->winy/2)*(1 + vec4[1]/vec4[3]);
307                         
308                         if(fy>0.0 && fy< (float)area->winy) {
309                                 adr[0]= floor(fx); 
310                                 adr[1]= floor(fy);
311                         }
312                 }
313         }
314 }
315
316 void view3d_project_short_noclip(ScrArea *area, float *vec, short *adr, float mat[4][4])
317 {
318         float fx, fy, vec4[4];
319
320         adr[0]= IS_CLIPPED;
321         
322         VECCOPY(vec4, vec);
323         vec4[3]= 1.0;
324         
325         Mat4MulVec4fl(mat, vec4);
326
327         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
328                 fx= (area->winx/2)*(1 + vec4[0]/vec4[3]);
329                 
330                 if( fx>-32700 && fx<32700) {
331                 
332                         fy= (area->winy/2)*(1 + vec4[1]/vec4[3]);
333                         
334                         if(fy>-32700.0 && fy<32700.0) {
335                                 adr[0]= floor(fx); 
336                                 adr[1]= floor(fy);
337                         }
338                 }
339         }
340 }
341
342 void view3d_project_float(ScrArea *area, float *vec, float *adr, float mat[4][4])
343 {
344         float vec4[4];
345         
346         adr[0]= IS_CLIPPED;
347         VECCOPY(vec4, vec);
348         vec4[3]= 1.0;
349         
350         Mat4MulVec4fl(mat, vec4);
351
352         if( vec4[3]>FLT_EPSILON ) {
353                 adr[0] = (area->winx/2.0)+(area->winx/2.0)*vec4[0]/vec4[3];     
354                 adr[1] = (area->winy/2.0)+(area->winy/2.0)*vec4[1]/vec4[3];
355         } else {
356                 adr[0] = adr[1] = 0.0;
357         }
358 }
359
360 int boundbox_clip(float obmat[][4], BoundBox *bb)
361 {
362         /* return 1: draw */
363         
364         float mat[4][4];
365         float vec[4], min, max;
366         int a, flag= -1, fl;
367         
368         if(bb==NULL) return 1;
369         if(bb->flag & OB_BB_DISABLED) return 1;
370         
371         Mat4MulMat4(mat, obmat, G.vd->persmat);
372
373         for(a=0; a<8; a++) {
374                 VECCOPY(vec, bb->vec[a]);
375                 vec[3]= 1.0;
376                 Mat4MulVec4fl(mat, vec);
377                 max= vec[3];
378                 min= -vec[3];
379
380                 fl= 0;
381                 if(vec[0] < min) fl+= 1;
382                 if(vec[0] > max) fl+= 2;
383                 if(vec[1] < min) fl+= 4;
384                 if(vec[1] > max) fl+= 8;
385                 if(vec[2] < min) fl+= 16;
386                 if(vec[2] > max) fl+= 32;
387                 
388                 flag &= fl;
389                 if(flag==0) return 1;
390         }
391
392         return 0;
393
394 }
395
396 void fdrawline(float x1, float y1, float x2, float y2)
397 {
398         float v[2];
399
400         glBegin(GL_LINE_STRIP);
401         v[0] = x1; v[1] = y1;
402         glVertex2fv(v);
403         v[0] = x2; v[1] = y2;
404         glVertex2fv(v);
405         glEnd();
406 }
407
408 void fdrawbox(float x1, float y1, float x2, float y2)
409 {
410         float v[2];
411
412         glBegin(GL_LINE_STRIP);
413
414         v[0] = x1; v[1] = y1;
415         glVertex2fv(v);
416         v[0] = x1; v[1] = y2;
417         glVertex2fv(v);
418         v[0] = x2; v[1] = y2;
419         glVertex2fv(v);
420         v[0] = x2; v[1] = y1;
421         glVertex2fv(v);
422         v[0] = x1; v[1] = y1;
423         glVertex2fv(v);
424
425         glEnd();
426 }
427
428 void sdrawline(short x1, short y1, short x2, short y2)
429 {
430         short v[2];
431
432         glBegin(GL_LINE_STRIP);
433         v[0] = x1; v[1] = y1;
434         glVertex2sv(v);
435         v[0] = x2; v[1] = y2;
436         glVertex2sv(v);
437         glEnd();
438 }
439
440 void sdrawbox(short x1, short y1, short x2, short y2)
441 {
442         short v[2];
443
444         glBegin(GL_LINE_STRIP);
445
446         v[0] = x1; v[1] = y1;
447         glVertex2sv(v);
448         v[0] = x1; v[1] = y2;
449         glVertex2sv(v);
450         v[0] = x2; v[1] = y2;
451         glVertex2sv(v);
452         v[0] = x2; v[1] = y1;
453         glVertex2sv(v);
454         v[0] = x1; v[1] = y1;
455         glVertex2sv(v);
456
457         glEnd();
458 }
459
460 /* the central math in this function was copied from trackball.cpp, sample code from the 
461    Developers Toolbox series by SGI. */
462
463 /* trackball: better one than a full spherical solution */
464
465 void calctrackballvecfirst(rcti *area, short *mval, float *vec)
466 {
467         float x, y, radius, d, z, t;
468         
469         radius= TRACKBALLSIZE;
470         
471         /* normalize x and y */
472         x= (area->xmax + area->xmin)/2 -mval[0];
473         x/= (float)((area->xmax - area->xmin)/2);
474         y= (area->ymax + area->ymin)/2 -mval[1];
475         y/= (float)((area->ymax - area->ymin)/2);
476         
477         d = sqrt(x*x + y*y);
478         if (d < radius*M_SQRT1_2)       /* Inside sphere */
479                 z = sqrt(radius*radius - d*d);
480         else
481         {                       /* On hyperbola */
482                 t = radius / M_SQRT2;
483                 z = t*t / d;
484         }
485
486         vec[0]= x;
487         vec[1]= y;
488         vec[2]= -z;             /* yah yah! */
489
490         if( fabs(vec[2])>fabs(vec[1]) && fabs(vec[2])>fabs(vec[0]) ) {
491                 vec[0]= 0.0;
492                 vec[1]= 0.0;
493                 if(vec[2]>0.0) vec[2]= 1.0; else vec[2]= -1.0;
494         }
495         else if( fabs(vec[1])>fabs(vec[0]) && fabs(vec[1])>fabs(vec[2]) ) {
496                 vec[0]= 0.0;
497                 vec[2]= 0.0;
498                 if(vec[1]>0.0) vec[1]= 1.0; else vec[1]= -1.0;
499         }
500         else  {
501                 vec[1]= 0.0;
502                 vec[2]= 0.0;
503                 if(vec[0]>0.0) vec[0]= 1.0; else vec[0]= -1.0;
504         }
505 }
506
507 void calctrackballvec(rcti *area, short *mval, float *vec)
508 {
509         float x, y, radius, d, z, t;
510         
511         radius= TRACKBALLSIZE;
512         
513         /* x en y normalizeren */
514         x= (area->xmax + area->xmin)/2 -mval[0];
515         x/= (float)((area->xmax - area->xmin)/4);
516         y= (area->ymax + area->ymin)/2 -mval[1];
517         y/= (float)((area->ymax - area->ymin)/2);
518         
519         d = sqrt(x*x + y*y);
520         if (d < radius*M_SQRT1_2)       /* Inside sphere */
521                 z = sqrt(radius*radius - d*d);
522         else
523         {                       /* On hyperbola */
524                 t = radius / M_SQRT2;
525                 z = t*t / d;
526         }
527
528         vec[0]= x;
529         vec[1]= y;
530         vec[2]= -z;             /* yah yah! */
531
532 }
533
534 void viewmove(int mode)
535 {
536         Object *ob = OBACT;
537         float firstvec[3], newvec[3], dvec[3];
538         float reverse, oldquat[4], q1[4], si, phi, dist0;
539         float ofs[3], obofs[3]= {0.0f, 0.0f, 0.0f};
540         int firsttime=1;
541         short mvalball[2], mval[2], mvalo[2];
542         short use_sel = 0;
543         short preview3d_event= 1;
544         
545         /* 3D window may not be defined */
546         if( !G.vd ) {
547                 fprintf( stderr, "G.vd == NULL in viewmove()\n" );
548                 return;
549         }
550
551         /* sometimes this routine is called from headerbuttons */
552
553         areawinset(curarea->win);
554         
555         initgrabz(-G.vd->ofs[0], -G.vd->ofs[1], -G.vd->ofs[2]);
556         
557         QUATCOPY(oldquat, G.vd->viewquat);
558         
559         getmouseco_sc(mvalo);           /* work with screen coordinates because of trackball function */
560         mvalball[0]= mvalo[0];                  /* needed for turntable to work */
561         mvalball[1]= mvalo[1];
562         dist0= G.vd->dist;
563         
564         calctrackballvec(&curarea->winrct, mvalo, firstvec);
565
566         /* cumultime(0); */
567
568         if(!G.obedit && (G.f & G_SCULPTMODE) && ob && G.vd->pivot_last) {
569                 use_sel= 1;
570                 VecCopyf(ofs, G.vd->ofs);
571
572                 VecCopyf(obofs,&sculpt_session()->pivot.x);
573                 Mat4MulVecfl(ob->obmat, obofs);
574                 obofs[0]= -obofs[0];
575                 obofs[1]= -obofs[1];
576                 obofs[2]= -obofs[2];
577         }
578         else if (ob && (U.uiflag & USER_ORBIT_SELECTION)) {
579                 use_sel = 1;
580                 
581                 VECCOPY(ofs, G.vd->ofs);
582                 
583                 /* If there's no selection, obofs is unmodified, so <0,0,0> */
584                 calculateTransformCenter(V3D_CENTROID, obofs);
585                 VecMulf(obofs, -1.0f);
586         }
587         else
588                 ofs[0] = ofs[1] = ofs[2] = 0.0f;
589
590         reverse= 1.0f;
591         if (G.vd->persmat[2][1] < 0.0f)
592                 reverse= -1.0f;
593
594         while(TRUE) {
595                 getmouseco_sc(mval);
596                 
597                 // if playanim = alt+A, screenhandlers are for animated UI, python, etc
598                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || (G.f & G_PLAYANIM) || do_screenhandlers(G.curscreen)) {
599                         
600                         if(firsttime) {
601                                 
602                                 firsttime= 0;
603                                 /* are we translating, rotating or zooming? */
604                                 if(mode==0) {
605                                         if(G.vd->view!=0) scrarea_queue_headredraw(curarea);    /*for button */
606                                         G.vd->view= 0;
607                                 }
608                                 if(G.vd->persp==2 && mode!=1 && G.vd->camera) {
609                                         G.vd->persp= 1;
610                                         scrarea_do_windraw(curarea);
611                                         scrarea_queue_headredraw(curarea);
612                                 }
613                         }
614
615                         if(mode==0) {   /* view rotate */
616                                 if (U.uiflag & USER_AUTOPERSP) G.vd->persp= 1;
617
618                                 if (U.flag & USER_TRACKBALL) mvalball[0]= mval[0];
619                                 mvalball[1]= mval[1];
620                                 
621                                 calctrackballvec(&curarea->winrct, mvalball, newvec);
622                                 
623                                 VecSubf(dvec, newvec, firstvec);
624                                 
625                                 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
626                                 si/= (2.0*TRACKBALLSIZE);
627                         
628                                 if (U.flag & USER_TRACKBALL) {
629                                         Crossf(q1+1, firstvec, newvec);
630         
631                                         Normalize(q1+1);
632         
633                                         /* Allow for rotation beyond the interval
634                                          * [-pi, pi] */
635                                         while (si > 1.0)
636                                                 si -= 2.0;
637                 
638                                         /* This relation is used instead of
639                                          * phi = asin(si) so that the angle
640                                          * of rotation is linearly proportional
641                                          * to the distance that the mouse is
642                                          * dragged. */
643                                         phi = si * M_PI / 2.0;
644                 
645                                         si= sin(phi);
646                                         q1[0]= cos(phi);
647                                         q1[1]*= si;
648                                         q1[2]*= si;
649                                         q1[3]*= si;     
650                                         QuatMul(G.vd->viewquat, q1, oldquat);
651
652                                         if (use_sel) {
653                                                 /* compute the post multiplication quat, to rotate the offset correctly */
654                                                 QUATCOPY(q1, oldquat);
655                                                 QuatConj(q1);
656                                                 QuatMul(q1, q1, G.vd->viewquat);
657
658                                                 QuatConj(q1); /* conj == inv for unit quat */
659                                                 VECCOPY(G.vd->ofs, ofs);
660                                                 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
661                                                 QuatMulVecf(q1, G.vd->ofs);
662                                                 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
663                                         }
664                                 } else {
665                                         /* New turntable view code by John Aughey */
666
667                                         float m[3][3];
668                                         float m_inv[3][3];
669                                         float xvec[3] = {1,0,0};
670                                         /* Sensitivity will control how fast the viewport rotates.  0.0035 was
671                                            obtained experimentally by looking at viewport rotation sensitivities
672                                            on other modeling programs. */
673                                         /* Perhaps this should be a configurable user parameter. */
674                                         const float sensitivity = 0.0035;
675
676                                         /* Get the 3x3 matrix and its inverse from the quaternion */
677                                         QuatToMat3(G.vd->viewquat, m);
678                                         Mat3Inv(m_inv,m);
679
680                                         /* Determine the direction of the x vector (for rotating up and down) */
681                                         /* This can likely be compuated directly from the quaternion. */
682                                         Mat3MulVecfl(m_inv,xvec);
683
684                                         /* Perform the up/down rotation */
685                                         phi = sensitivity * -(mval[1] - mvalo[1]);
686                                         si = sin(phi);
687                                         q1[0] = cos(phi);
688                                         q1[1] = si * xvec[0];
689                                         q1[2] = si * xvec[1];
690                                         q1[3] = si * xvec[2];
691                                         QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
692
693                                         if (use_sel) {
694                                                 QuatConj(q1); /* conj == inv for unit quat */
695                                                 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
696                                                 QuatMulVecf(q1, G.vd->ofs);
697                                                 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
698                                         }
699
700                                         /* Perform the orbital rotation */
701                                         phi = sensitivity * reverse * (mval[0] - mvalo[0]);
702                                         q1[0] = cos(phi);
703                                         q1[1] = q1[2] = 0.0;
704                                         q1[3] = sin(phi);
705                                         QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
706
707                                         if (use_sel) {
708                                                 QuatConj(q1);
709                                                 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
710                                                 QuatMulVecf(q1, G.vd->ofs);
711                                                 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
712                                         }
713                                 }
714                         }
715                         else if(mode==1) {      /* translate */
716                                 if(G.vd->persp==2) {
717                                         float max= (float)MAX2(curarea->winx, curarea->winy);
718
719                                         G.vd->camdx += (mvalo[0]-mval[0])/(max);
720                                         G.vd->camdy += (mvalo[1]-mval[1])/(max);
721                                         CLAMP(G.vd->camdx, -1.0f, 1.0f);
722                                         CLAMP(G.vd->camdy, -1.0f, 1.0f);
723                                         preview3d_event= 0;
724                                 }
725                                 else {
726                                         window_to_3d(dvec, mval[0]-mvalo[0], mval[1]-mvalo[1]);
727                                         VecAddf(G.vd->ofs, G.vd->ofs, dvec);
728                                 }
729                         }
730                         else if(mode==2) {
731                                 if(U.viewzoom==USER_ZOOM_CONT) {
732                                         // oldstyle zoom
733                                         G.vd->dist*= 1.0+(float)(mvalo[0]-mval[0]+mvalo[1]-mval[1])/1000.0;
734                                 }
735                                 else if(U.viewzoom==USER_ZOOM_SCALE) {
736                                         int ctr[2], len1, len2;
737                                         // method which zooms based on how far you move the mouse
738                                         
739                                         ctr[0] = (curarea->winrct.xmax + curarea->winrct.xmin)/2;
740                                         ctr[1] = (curarea->winrct.ymax + curarea->winrct.ymin)/2;
741                                         
742                                         len1 = (int)sqrt((ctr[0] - mval[0])*(ctr[0] - mval[0]) + (ctr[1] - mval[1])*(ctr[1] - mval[1])) + 5;
743                                         len2 = (int)sqrt((ctr[0] - mvalo[0])*(ctr[0] - mvalo[0]) + (ctr[1] - mvalo[1])*(ctr[1] - mvalo[1])) + 5;
744                                         
745                                         G.vd->dist= dist0 * ((float)len2/len1);
746                                 }
747                                 else {  /* USER_ZOOM_DOLLY */
748                                         float len1 = (curarea->winrct.ymax - mval[1]) + 5;
749                                         float len2 = (curarea->winrct.ymax - mvalo[1]) + 5;
750                                         
751                                         G.vd->dist= dist0 * (2.0*((len2/len1)-1.0) + 1.0);
752                                 }
753                                 
754                                 /* these limits are in toets.c too */
755                                 if(G.vd->dist<0.001*G.vd->grid) G.vd->dist= 0.001*G.vd->grid;
756                                 if(G.vd->dist>10.0*G.vd->far) G.vd->dist=10.0*G.vd->far;
757                                 
758                                 mval[1]= mvalo[1]; /* preserve first value */
759                                 mval[0]= mvalo[0];
760                                 
761                                 if(G.vd->persp==0 || G.vd->persp==2) preview3d_event= 0;
762                         }
763                         
764                         mvalo[0]= mval[0];
765                         mvalo[1]= mval[1];
766
767                         if(G.f & G_PLAYANIM) inner_play_anim_loop(0, 0);
768                         if(G.f & G_SIMULATION) break;
769
770                         /* If in retopo paint mode, update lines */
771                         if(retopo_mesh_paint_check() && G.vd->retopo_view_data) {
772                                 G.vd->retopo_view_data->queue_matrix_update= 1;
773                                 retopo_paint_view_update(G.vd);
774                         }
775
776                         scrarea_do_windraw(curarea);
777                         screen_swapbuffers();
778                 }
779                 else {
780                         short val;
781                         unsigned short event;
782                         /* we need to empty the queue... when you do this very long it overflows */
783                         while(qtest()) event= extern_qread(&val);
784                         
785                         BIF_wait_for_statechange();
786                 }
787                 
788                 /* this in the end, otherwise get_mbut does not work on a PC... */
789                 if( !(get_mbut() & (L_MOUSE|M_MOUSE))) break;
790         }
791
792         if(G.vd->depths) G.vd->depths->damaged= 1;
793         retopo_queue_updates(G.vd);
794         allqueue(REDRAWVIEW3D, 0);
795
796         if(preview3d_event) 
797                 BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
798         else
799                 BIF_view3d_previewrender_signal(curarea, PR_PROJECTED);
800
801 }
802
803 /* Gets the lens and clipping values from a camera of lamp type object */
804 void object_view_settings(Object *ob, float *lens, float *clipsta, float *clipend)
805 {       
806         if (!ob) return;
807         
808         if(ob->type==OB_LAMP ) {
809                 Lamp *la = ob->data;
810                 if (lens) {
811                         float x1, fac;
812                         fac= cos( M_PI*la->spotsize/360.0);
813                         x1= saacos(fac);
814                         *lens= 16.0*fac/sin(x1);
815                 }
816                 if (clipsta)    *clipsta= la->clipsta;
817                 if (clipend)    *clipend= la->clipend;
818         }
819         else if(ob->type==OB_CAMERA) {
820                 Camera *cam= ob->data;
821                 if (lens)               *lens= cam->lens;
822                 if (clipsta)    *clipsta= cam->clipsta;
823                 if (clipend)    *clipend= cam->clipend;
824         }
825 }
826
827
828 int get_view3d_viewplane(int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
829 {
830         Camera *cam=NULL;
831         float lens, fac, x1, y1, x2, y2;
832         float winx= (float)winxi, winy= (float)winyi;
833         int orth= 0;
834         
835         lens= G.vd->lens;       
836         
837         *clipsta= G.vd->near;
838         *clipend= G.vd->far;
839
840 /*      
841  * Cant use this since we need the fac and x1 values set
842  * if(G.vd->persp==2)
843                 object_view_settings(G.vd->camera, &lens, &(*clipsta), &(*clipend));*/
844         
845         if(G.vd->persp==2) {
846                 if(G.vd->camera) {
847                         if(G.vd->camera->type==OB_LAMP ) {
848                                 Lamp *la;
849                                 
850                                 la= G.vd->camera->data;
851                                 fac= cos( M_PI*la->spotsize/360.0);
852                                 
853                                 x1= saacos(fac);
854                                 lens= 16.0*fac/sin(x1);
855                 
856                                 *clipsta= la->clipsta;
857                                 *clipend= la->clipend;
858                         }
859                         else if(G.vd->camera->type==OB_CAMERA) {
860                                 cam= G.vd->camera->data;
861                                 lens= cam->lens;
862                                 *clipsta= cam->clipsta;
863                                 *clipend= cam->clipend;
864                         }
865                 }
866         }
867         
868         if(G.vd->persp==0) {
869                 if(winx>winy) x1= -G.vd->dist;
870                 else x1= -winx*G.vd->dist/winy;
871                 x2= -x1;
872
873                 if(winx>winy) y1= -winy*G.vd->dist/winx;
874                 else y1= -G.vd->dist;
875                 y2= -y1;
876                 
877                 *clipend *= 0.5;        // otherwise too extreme low zbuffer quality
878                 *clipsta= - *clipend;
879                 orth= 1;
880         }
881         else {
882                 /* fac for zoom, also used for camdx */
883                 if(G.vd->persp==2) {
884                         fac= (1.41421+( (float)G.vd->camzoom )/50.0);
885                         fac*= fac;
886                 }
887                 else fac= 2.0;
888                 
889                 /* viewplane size depends... */
890                 if(cam && cam->type==CAM_ORTHO) {
891                         /* ortho_scale == 1 means exact 1 to 1 mapping */
892                         float dfac= 2.0*cam->ortho_scale/fac;
893                         
894                         if(winx>winy) x1= -dfac;
895                         else x1= -winx*dfac/winy;
896                         x2= -x1;
897                         
898                         if(winx>winy) y1= -winy*dfac/winx;
899                         else y1= -dfac;
900                         y2= -y1;
901                         orth= 1;
902                 }
903                 else {
904                         float dfac;
905                         
906                         if(winx>winy) dfac= 64.0/(fac*winx*lens);
907                         else dfac= 64.0/(fac*winy*lens);
908                         
909                         x1= - *clipsta * winx*dfac;
910                         x2= -x1;
911                         y1= - *clipsta * winy*dfac;
912                         y2= -y1;
913                         orth= 0;
914                 }
915                 /* cam view offset */
916                 if(cam) {
917                         float dx= 0.5*fac*G.vd->camdx*(x2-x1);
918                         float dy= 0.5*fac*G.vd->camdy*(y2-y1);
919                         x1+= dx;
920                         x2+= dx;
921                         y1+= dy;
922                         y2+= dy;
923                 }
924         }
925
926         if(pixsize) {
927                 float viewfac;
928
929                 if(orth) {
930                         viewfac= (winx >= winy)? winx: winy;
931                         *pixsize= 1.0f/viewfac;
932                 }
933                 else {
934                         viewfac= (((winx >= winy)? winx: winy)*lens)/32.0;
935                         *pixsize= *clipsta/viewfac;
936                 }
937         }
938         
939         viewplane->xmin= x1;
940         viewplane->ymin= y1;
941         viewplane->xmax= x2;
942         viewplane->ymax= y2;
943         
944         return orth;
945 }
946
947 /* important to not set windows active in here, can be renderwin for example */
948 void setwinmatrixview3d(int winx, int winy, rctf *rect)         /* rect: for picking */
949 {
950         rctf viewplane;
951         float clipsta, clipend, x1, y1, x2, y2;
952         int orth;
953         
954         orth= get_view3d_viewplane(winx, winy, &viewplane, &clipsta, &clipend, NULL);
955 //      printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
956         x1= viewplane.xmin;
957         y1= viewplane.ymin;
958         x2= viewplane.xmax;
959         y2= viewplane.ymax;
960         
961         if(rect) {              /* picking */
962                 rect->xmin/= (float)curarea->winx;
963                 rect->xmin= x1+rect->xmin*(x2-x1);
964                 rect->ymin/= (float)curarea->winy;
965                 rect->ymin= y1+rect->ymin*(y2-y1);
966                 rect->xmax/= (float)curarea->winx;
967                 rect->xmax= x1+rect->xmax*(x2-x1);
968                 rect->ymax/= (float)curarea->winy;
969                 rect->ymax= y1+rect->ymax*(y2-y1);
970                 
971                 if(orth) myortho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
972                 else mywindow(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
973                 
974         }
975         else {
976                 if(orth) myortho(x1, x2, y1, y2, clipsta, clipend);
977                 else mywindow(x1, x2, y1, y2, clipsta, clipend);
978         }
979
980         /* not sure what this was for? (ton) */
981         glMatrixMode(GL_PROJECTION);
982         mygetmatrix(curarea->winmat);
983         glMatrixMode(GL_MODELVIEW);
984 }
985
986 void obmat_to_viewmat(Object *ob, short smooth)
987 {
988         float bmat[4][4];
989         float tmat[3][3];
990
991         Mat4CpyMat4(bmat, ob->obmat);
992         Mat4Ortho(bmat);
993         Mat4Invert(G.vd->viewmat, bmat);
994         
995         /* view quat calculation, needed for add object */
996         Mat3CpyMat4(tmat, G.vd->viewmat);
997         if (smooth) {
998                 float new_quat[4];
999                 if (G.vd->persp==2 && G.vd->camera) {
1000                         /* were from a camera view */
1001                         
1002                         float orig_ofs[3];
1003                         float orig_dist= G.vd->dist;
1004                         float orig_lens= G.vd->lens;
1005                         VECCOPY(orig_ofs, G.vd->ofs);
1006                         
1007                         /* Switch from camera view */
1008                         Mat3ToQuat(tmat, new_quat);
1009                         
1010                         G.vd->persp=1;
1011                         G.vd->dist= 0.0;
1012                         
1013                         view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
1014                         smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
1015                         
1016                         G.vd->persp=2; /* just to be polite, not needed */
1017                         
1018                 } else {
1019                         Mat3ToQuat(tmat, new_quat);
1020                         smooth_view(G.vd, NULL, new_quat, NULL, NULL);
1021                 }
1022         } else {
1023                 Mat3ToQuat(tmat, G.vd->viewquat);
1024         }
1025 }
1026
1027 /* dont set windows active in in here, is used by renderwin too */
1028 void setviewmatrixview3d()
1029 {
1030         Camera *cam;
1031
1032         if(G.vd->persp>=2) {        /* obs/camera */
1033                 if(G.vd->camera) {
1034                         
1035                         where_is_object(G.vd->camera);  
1036                         obmat_to_viewmat(G.vd->camera, 0);
1037                         
1038                         if(G.vd->camera->type==OB_CAMERA) {
1039                                 cam= G.vd->camera->data;
1040                                 //if(cam->type==CAM_ORTHO) G.vd->viewmat[3][2]*= 100.0;
1041                         }
1042                 }
1043                 else {
1044                         QuatToMat4(G.vd->viewquat, G.vd->viewmat);
1045                         G.vd->viewmat[3][2]-= G.vd->dist;
1046                 }
1047         }
1048         else {
1049                 
1050                 QuatToMat4(G.vd->viewquat, G.vd->viewmat);
1051                 if(G.vd->persp==1) G.vd->viewmat[3][2]-= G.vd->dist;
1052                 if(G.vd->ob_centre) {
1053                         Object *ob= G.vd->ob_centre;
1054                         float vec[3];
1055                         
1056                         VECCOPY(vec, ob->obmat[3]);
1057                         if(ob->type==OB_ARMATURE && G.vd->ob_centre_bone[0]) {
1058                                 bPoseChannel *pchan= get_pose_channel(ob->pose, G.vd->ob_centre_bone);
1059                                 if(pchan) {
1060                                         VECCOPY(vec, pchan->pose_mat[3]);
1061                                         Mat4MulVecfl(ob->obmat, vec);
1062                                 }
1063                         }
1064                         i_translate(-vec[0], -vec[1], -vec[2], G.vd->viewmat);
1065                 }
1066                 else i_translate(G.vd->ofs[0], G.vd->ofs[1], G.vd->ofs[2], G.vd->viewmat);
1067         }
1068 }
1069
1070 void setcameratoview3d(void)
1071 {
1072         Object *ob;
1073         float dvec[3];
1074
1075         ob= G.vd->camera;
1076         dvec[0]= G.vd->dist*G.vd->viewinv[2][0];
1077         dvec[1]= G.vd->dist*G.vd->viewinv[2][1];
1078         dvec[2]= G.vd->dist*G.vd->viewinv[2][2];                                        
1079         VECCOPY(ob->loc, dvec);
1080         VecSubf(ob->loc, ob->loc, G.vd->ofs);
1081         G.vd->viewquat[0]= -G.vd->viewquat[0];
1082         if (ob->transflag & OB_QUAT) {
1083                 QUATCOPY(ob->quat, G.vd->viewquat);
1084         } else {
1085                 QuatToEul(G.vd->viewquat, ob->rot);
1086         }
1087         G.vd->viewquat[0]= -G.vd->viewquat[0];
1088 }
1089
1090 /* IGLuint-> GLuint*/
1091 /* Warning: be sure to account for a negative return value
1092  *   This is an error, "Too many objects in select buffer"
1093  *   and no action should be taken (can crash blender) if this happens
1094  */
1095 short  view3d_opengl_select(unsigned int *buffer, unsigned int bufsize, short x1, short y1, short x2, short y2)
1096 {
1097         rctf rect;
1098         short mval[2], code, hits;
1099
1100         G.f |= G_PICKSEL;
1101         
1102         if(x1==0 && x2==0 && y1==0 && y2==0) {
1103                 getmouseco_areawin(mval);
1104                 rect.xmin= mval[0]-12;  // seems to be default value for bones only now
1105                 rect.xmax= mval[0]+12;
1106                 rect.ymin= mval[1]-12;
1107                 rect.ymax= mval[1]+12;
1108         }
1109         else {
1110                 rect.xmin= x1;
1111                 rect.xmax= x2;
1112                 rect.ymin= y1;
1113                 rect.ymax= y2;
1114         }
1115         /* get rid of overlay button matrix */
1116         persp(PERSP_VIEW);
1117         setwinmatrixview3d(curarea->winx, curarea->winy, &rect);
1118         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
1119         
1120         if(G.vd->drawtype > OB_WIRE) {
1121                 G.vd->zbuf= TRUE;
1122                 glEnable(GL_DEPTH_TEST);
1123         }
1124
1125         if(G.vd->flag & V3D_CLIPPING)
1126                 view3d_set_clipping(G.vd);
1127         
1128         glSelectBuffer( bufsize, (GLuint *)buffer);
1129         glRenderMode(GL_SELECT);
1130         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1131         glPushName(-1);
1132         code= 1;
1133         
1134         if(G.obedit && G.obedit->type==OB_MBALL) {
1135                 draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1136         }
1137         else if ((G.obedit && G.obedit->type==OB_ARMATURE)) {
1138                 draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1139         }
1140         else {
1141                 Base *base;
1142                 
1143                 G.vd->xray= TRUE;       // otherwise it postpones drawing
1144                 for(base= G.scene->base.first; base; base= base->next) {
1145                         if(base->lay & G.vd->lay) {
1146                                 
1147                                 if (base->object->restrictflag & OB_RESTRICT_SELECT)
1148                                         base->selcol= 0;
1149                                 else {
1150                                         base->selcol= code;
1151                                         glLoadName(code);
1152                                         draw_object(base, DRAW_PICKING|DRAW_CONSTCOLOR);
1153                                         
1154                                         /* we draw group-duplicators for selection too */
1155                                         if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1156                                                 ListBase *lb;
1157                                                 DupliObject *dob;
1158                                                 Base tbase;
1159                                                 
1160                                                 tbase.flag= OB_FROMDUPLI;
1161                                                 lb= object_duplilist(G.scene, base->object);
1162                                                 
1163                                                 for(dob= lb->first; dob; dob= dob->next) {
1164                                                         tbase.object= dob->ob;
1165                                                         Mat4CpyMat4(dob->ob->obmat, dob->mat);
1166                                                         
1167                                                         draw_object(&tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1168                                                         
1169                                                         Mat4CpyMat4(dob->ob->obmat, dob->omat);
1170                                                 }
1171                                                 free_object_duplilist(lb);
1172                                         }
1173                                         code++;
1174                                 }                               
1175                         }
1176                 }
1177                 G.vd->xray= FALSE;      // restore
1178         }
1179         
1180         glPopName();    /* see above (pushname) */
1181         hits= glRenderMode(GL_RENDER);
1182
1183         G.f &= ~G_PICKSEL;
1184         setwinmatrixview3d(curarea->winx, curarea->winy, NULL);
1185         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
1186         
1187         if(G.vd->drawtype > OB_WIRE) {
1188                 G.vd->zbuf= 0;
1189                 glDisable(GL_DEPTH_TEST);
1190         }
1191         persp(PERSP_WIN);
1192         
1193         if(G.vd->flag & V3D_CLIPPING)
1194                 view3d_clr_clipping();
1195         
1196         if(hits<0) error("Too many objects in select buffer");
1197         
1198         return hits;
1199 }
1200
1201 float *give_cursor()
1202 {
1203         if(G.vd && G.vd->localview) return G.vd->cursor;
1204         else return G.scene->cursor;
1205 }
1206
1207 unsigned int free_localbit()
1208 {
1209         unsigned int lay;
1210         ScrArea *sa;
1211         bScreen *sc;
1212         
1213         lay= 0;
1214         
1215         /* sometimes we loose a localview: when an area is closed */
1216         /* check all areas: which localviews are in use? */
1217         sc= G.main->screen.first;
1218         while(sc) {
1219                 sa= sc->areabase.first;
1220                 while(sa) {
1221                         SpaceLink *sl= sa->spacedata.first;
1222                         while(sl) {
1223                                 if(sl->spacetype==SPACE_VIEW3D) {
1224                                         View3D *v3d= (View3D*) sl;
1225                                         lay |= v3d->lay;
1226                                 }
1227                                 sl= sl->next;
1228                         }
1229                         sa= sa->next;
1230                 }
1231                 sc= sc->id.next;
1232         }
1233         
1234         if( (lay & 0x01000000)==0) return 0x01000000;
1235         if( (lay & 0x02000000)==0) return 0x02000000;
1236         if( (lay & 0x04000000)==0) return 0x04000000;
1237         if( (lay & 0x08000000)==0) return 0x08000000;
1238         if( (lay & 0x10000000)==0) return 0x10000000;
1239         if( (lay & 0x20000000)==0) return 0x20000000;
1240         if( (lay & 0x40000000)==0) return 0x40000000;
1241         if( (lay & 0x80000000)==0) return 0x80000000;
1242         
1243         return 0;
1244 }
1245
1246
1247 void initlocalview()
1248 {
1249         Base *base;
1250         float size = 0.0, min[3], max[3], afm[3];
1251         unsigned int locallay;
1252         int ok=0;
1253
1254         if(G.vd->localvd) return;
1255
1256         min[0]= min[1]= min[2]= 1.0e10;
1257         max[0]= max[1]= max[2]= -1.0e10;
1258
1259         locallay= free_localbit();
1260
1261         if(locallay==0) {
1262                 error("Sorry,  no more than 8 localviews");
1263                 ok= 0;
1264         }
1265         else {
1266                 if(G.obedit) {
1267                         minmax_object(G.obedit, min, max);
1268                         
1269                         ok= 1;
1270                 
1271                         BASACT->lay |= locallay;
1272                         G.obedit->lay= BASACT->lay;
1273                 }
1274                 else {
1275                         base= FIRSTBASE;
1276                         while(base) {
1277                                 if TESTBASE(base)  {
1278                                         minmax_object(base->object, min, max);
1279                                         base->lay |= locallay;
1280                                         base->object->lay= base->lay;
1281                                         ok= 1;
1282                                 }
1283                                 base= base->next;
1284                         }
1285                 }
1286                 
1287                 afm[0]= (max[0]-min[0]);
1288                 afm[1]= (max[1]-min[1]);
1289                 afm[2]= (max[2]-min[2]);
1290                 size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1291                 if(size<=0.01) size= 0.01;
1292         }
1293         
1294         if(ok) {
1295                 G.vd->localvd= MEM_mallocN(sizeof(View3D), "localview");
1296                 memcpy(G.vd->localvd, G.vd, sizeof(View3D));
1297
1298                 G.vd->ofs[0]= -(min[0]+max[0])/2.0;
1299                 G.vd->ofs[1]= -(min[1]+max[1])/2.0;
1300                 G.vd->ofs[2]= -(min[2]+max[2])/2.0;
1301
1302                 G.vd->dist= size;
1303
1304                 // correction for window aspect ratio
1305                 if(curarea->winy>2 && curarea->winx>2) {
1306                         size= (float)curarea->winx/(float)curarea->winy;
1307                         if(size<1.0) size= 1.0/size;
1308                         G.vd->dist*= size;
1309                 }
1310                 
1311                 if (G.vd->persp>1) G.vd->persp= 1;
1312                 if (G.vd->near> 0.1) G.vd->near= 0.1;
1313                 
1314                 G.vd->cursor[0]= -G.vd->ofs[0];
1315                 G.vd->cursor[1]= -G.vd->ofs[1];
1316                 G.vd->cursor[2]= -G.vd->ofs[2];
1317
1318                 G.vd->lay= locallay;
1319                 
1320                 countall();
1321                 scrarea_queue_winredraw(curarea);
1322         }
1323         else {
1324                 /* clear flags */ 
1325                 base= FIRSTBASE;
1326                 while(base) {
1327                         if( base->lay & locallay ) {
1328                                 base->lay-= locallay;
1329                                 if(base->lay==0) base->lay= G.vd->layact;
1330                                 if(base->object != G.obedit) base->flag |= SELECT;
1331                                 base->object->lay= base->lay;
1332                         }
1333                         base= base->next;
1334                 }
1335                 scrarea_queue_headredraw(curarea);
1336                 
1337                 G.vd->localview= 0;
1338         }
1339         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1340 }
1341
1342 void centerview()       /* like a localview without local! */
1343 {
1344         Object *ob= OBACT;
1345         float size, min[3], max[3], afm[3];
1346         int ok=0;
1347         
1348         /* SMOOTHVIEW */
1349         float new_ofs[3];
1350         float new_dist;
1351         
1352         
1353         min[0]= min[1]= min[2]= 1.0e10;
1354         max[0]= max[1]= max[2]= -1.0e10;
1355
1356         if (G.f & G_WEIGHTPAINT) {
1357                 /* hardcoded exception, we look for the one selected armature */
1358                 /* this is weak code this way, we should make a generic active/selection callback interface once... */
1359                 Base *base;
1360                 for(base=FIRSTBASE; base; base= base->next) {
1361                         if(TESTBASELIB(base)) {
1362                                 if(base->object->type==OB_ARMATURE)
1363                                         if(base->object->flag & OB_POSEMODE)
1364                                                 break;
1365                         }
1366                 }
1367                 if(base)
1368                         ob= base->object;
1369         }
1370         
1371         
1372         if(G.obedit) {
1373                 ok = minmax_verts(min, max);    /* only selected */
1374         }
1375         else if(ob && (ob->flag & OB_POSEMODE)) {
1376                 if(ob->pose) {
1377                         bArmature *arm= ob->data;
1378                         bPoseChannel *pchan;
1379                         float vec[3];
1380                         
1381                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
1382                                 if(pchan->bone->flag & BONE_SELECTED) {
1383                                         if(pchan->bone->layer & arm->layer) {
1384                                                 ok= 1;
1385                                                 VECCOPY(vec, pchan->pose_head);
1386                                                 Mat4MulVecfl(ob->obmat, vec);
1387                                                 DO_MINMAX(vec, min, max);
1388                                                 VECCOPY(vec, pchan->pose_tail);
1389                                                 Mat4MulVecfl(ob->obmat, vec);
1390                                                 DO_MINMAX(vec, min, max);
1391                                         }
1392                                 }
1393                         }
1394                 }
1395         }
1396         else if (G.f & G_FACESELECT) {
1397                 ok= minmax_tface(min, max);
1398         }
1399         else {
1400                 Base *base= FIRSTBASE;
1401                 while(base) {
1402                         if TESTBASE(base)  {
1403                                 minmax_object(base->object, min, max);
1404                                 /* account for duplis */
1405                                 minmax_object_duplis(base->object, min, max);
1406                                 
1407                                 ok= 1;
1408                         }
1409                         base= base->next;
1410                 }
1411         }
1412         
1413         if(ok==0) return;
1414         
1415         afm[0]= (max[0]-min[0]);
1416         afm[1]= (max[1]-min[1]);
1417         afm[2]= (max[2]-min[2]);
1418         size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1419         
1420         if(size <= G.vd->near*1.5) size= G.vd->near*1.5;
1421         
1422         new_ofs[0]= -(min[0]+max[0])/2.0;
1423         new_ofs[1]= -(min[1]+max[1])/2.0;
1424         new_ofs[2]= -(min[2]+max[2])/2.0;
1425         
1426         new_dist = size;
1427
1428         /* correction for window aspect ratio */
1429         if(curarea->winy>2 && curarea->winx>2) {
1430                 size= (float)curarea->winx/(float)curarea->winy;
1431                 if(size<1.0) size= 1.0/size;
1432                 new_dist*= size;
1433         }
1434         
1435         G.vd->cursor[0]= -new_ofs[0];
1436         G.vd->cursor[1]= -new_ofs[1];
1437         G.vd->cursor[2]= -new_ofs[2];
1438         
1439         if (G.vd->persp==2 && G.vd->camera) {
1440                 float orig_lens= G.vd->lens;
1441                 
1442                 G.vd->persp=1;
1443                 G.vd->dist= 0.0;
1444                 view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
1445                 smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
1446         } else {
1447                 if(G.vd->persp>=2)
1448                         G.vd->persp= 1;
1449                 
1450                 smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
1451         }
1452         scrarea_queue_winredraw(curarea);
1453         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1454
1455 }
1456
1457
1458 void restore_localviewdata(View3D *vd)
1459 {
1460         if(vd->localvd==0) return;
1461         
1462         VECCOPY(vd->ofs, vd->localvd->ofs);
1463         vd->dist= vd->localvd->dist;
1464         vd->persp= vd->localvd->persp;
1465         vd->view= vd->localvd->view;
1466         vd->near= vd->localvd->near;
1467         vd->far= vd->localvd->far;
1468         vd->lay= vd->localvd->lay;
1469         vd->layact= vd->localvd->layact;
1470         vd->drawtype= vd->localvd->drawtype;
1471         vd->camera= vd->localvd->camera;
1472         QUATCOPY(vd->viewquat, vd->localvd->viewquat);
1473         
1474 }
1475
1476 void endlocalview(ScrArea *sa)
1477 {
1478         View3D *v3d;
1479         struct Base *base;
1480         unsigned int locallay;
1481         
1482         if(sa->spacetype!=SPACE_VIEW3D) return;
1483         v3d= sa->spacedata.first;
1484         
1485         if(v3d->localvd) {
1486                 
1487                 locallay= v3d->lay & 0xFF000000;
1488                 
1489                 restore_localviewdata(v3d);
1490                 
1491                 MEM_freeN(v3d->localvd);
1492                 v3d->localvd= 0;
1493                 v3d->localview= 0;
1494
1495                 /* for when in other window the layers have changed */
1496                 if(v3d->scenelock) v3d->lay= G.scene->lay;
1497                 
1498                 base= FIRSTBASE;
1499                 while(base) {
1500                         if( base->lay & locallay ) {
1501                                 base->lay-= locallay;
1502                                 if(base->lay==0) base->lay= v3d->layact;
1503                                 if(base->object != G.obedit) {
1504                                         base->flag |= SELECT;
1505                                         base->object->flag |= SELECT;
1506                                 }
1507                                 base->object->lay= base->lay;
1508                         }
1509                         base= base->next;
1510                 }
1511
1512                 countall();
1513                 allqueue(REDRAWVIEW3D, 0);      /* because of select */
1514                 allqueue(REDRAWOOPS, 0);        /* because of select */
1515                 BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1516         } 
1517 }
1518
1519 void view3d_home(int center)
1520 {
1521         Base *base;
1522         float size, min[3], max[3], afm[3];
1523         int ok= 1, onedone=0;
1524
1525         if(center) {
1526                 min[0]= min[1]= min[2]= 0.0;
1527                 max[0]= max[1]= max[2]= 0.0;
1528         }
1529         else {
1530                 min[0]= min[1]= min[2]= 1.0e10;
1531                 max[0]= max[1]= max[2]= -1.0e10;
1532         }
1533         
1534         for(base= FIRSTBASE; base; base= base->next) {
1535                 if(base->lay & G.vd->lay) {
1536                         onedone= 1;
1537                         minmax_object(base->object, min, max);
1538                 }
1539         }
1540         if(!onedone) return;
1541         
1542         afm[0]= (max[0]-min[0]);
1543         afm[1]= (max[1]-min[1]);
1544         afm[2]= (max[2]-min[2]);
1545         size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1546         if(size==0.0) ok= 0;
1547                 
1548         if(ok) {
1549                 float new_dist;
1550                 float new_ofs[3];
1551                 
1552                 new_dist = size;
1553                 new_ofs[0]= -(min[0]+max[0])/2.0;
1554                 new_ofs[1]= -(min[1]+max[1])/2.0;
1555                 new_ofs[2]= -(min[2]+max[2])/2.0;
1556                 
1557                 // correction for window aspect ratio
1558                 if(curarea->winy>2 && curarea->winx>2) {
1559                         size= (float)curarea->winx/(float)curarea->winy;
1560                         if(size<1.0) size= 1.0/size;
1561                         new_dist*= size;
1562                 }
1563                 
1564                 if (G.vd->persp==2 && G.vd->camera) {
1565                         /* switch out of camera view */
1566                         float orig_lens= G.vd->lens;
1567                         
1568                         G.vd->persp=1;
1569                         G.vd->dist= 0.0;
1570                         view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
1571                         smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
1572                         
1573                 } else {
1574                         if(G.vd->persp>=2) G.vd->persp= 1;
1575                         smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
1576                 }
1577                 scrarea_queue_winredraw(curarea);
1578         }
1579         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1580
1581 }
1582
1583
1584 void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3])
1585 {
1586         float alignaxis[3] = {0.0, 0.0, 0.0};
1587         float norm[3], axis[3], angle, new_quat[4];
1588
1589         if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
1590         else alignaxis[-axisidx-1]= -1.0;
1591
1592         VECCOPY(norm, vec);
1593         Normalize(norm);
1594
1595         angle= acos(Inpf(alignaxis, norm));
1596         Crossf(axis, alignaxis, norm);
1597         VecRotToQuat(axis, -angle, new_quat);
1598
1599         v3d->view= 0;
1600         
1601         if (v3d->persp==2 && v3d->camera) {
1602                 /* switch out of camera view */
1603                 float orig_ofs[3];
1604                 float orig_dist= v3d->dist;
1605                 float orig_lens= v3d->lens;
1606
1607                 VECCOPY(orig_ofs, v3d->ofs);
1608                 G.vd->persp=1;
1609                 G.vd->dist= 0.0;
1610                 view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens);
1611                 smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
1612         } else {
1613                 if (v3d->persp>=2) v3d->persp= 1; /* switch out of camera mode */
1614                 smooth_view(v3d, NULL, new_quat, NULL, NULL);
1615         }
1616 }
1617
1618
1619
1620 /* SMOOTHVIEW */
1621 void smooth_view(View3D *v3d, float *ofs, float *quat, float *dist, float *lens)
1622 {
1623         /* View Animation enabled */
1624         if (U.smooth_viewtx) {
1625                 int i;
1626                 char changed = 0;
1627                 float step = 0.0, step_inv;
1628                 float orig_dist;
1629                 float orig_lens;
1630                 float orig_quat[4];
1631                 float orig_ofs[3];
1632                 
1633                 double time_allowed, time_current, time_start;
1634                 
1635                 /* if there is no difference, return */
1636                 changed = 0; /* zero means no difference */
1637                 if (dist) {
1638                         if ((*dist) != v3d->dist)
1639                                 changed = 1;
1640                 }
1641                 
1642                 if (lens) {
1643                         if ((*lens) != v3d->lens)
1644                                 changed = 1;
1645                 }
1646                 
1647                 if (!changed && ofs) {
1648                         if ((ofs[0]!=v3d->ofs[0]) ||
1649                                 (ofs[1]!=v3d->ofs[1]) ||
1650                                 (ofs[2]!=v3d->ofs[2]) )
1651                                 changed = 1;
1652                 }
1653                 
1654                 if (!changed && quat ) {
1655                         if ((quat[0]!=v3d->viewquat[0]) ||
1656                                 (quat[1]!=v3d->viewquat[1]) ||
1657                                 (quat[2]!=v3d->viewquat[2]) ||
1658                                 (quat[3]!=v3d->viewquat[3]) )
1659                                 changed = 1;
1660                 }
1661                 
1662                 /* The new view is different from teh old one
1663                  * so animate the view */
1664                 if (changed) {
1665                         
1666                         /* store original values */
1667                         VECCOPY(orig_ofs,       v3d->ofs);
1668                         QUATCOPY(orig_quat,     v3d->viewquat);
1669                         orig_dist =                     v3d->dist;
1670                         orig_lens =                     v3d->lens;
1671                         
1672                         time_allowed= (float)U.smooth_viewtx / 1000.0;
1673                         time_current = time_start = PIL_check_seconds_timer();
1674                         
1675                         /* if this is view rotation only
1676                          * we can decrease the time allowed by
1677                          * the angle between quats 
1678                          * this means small rotations wont lag */
1679                          if (quat && !ofs && !dist) {
1680                                 float vec1[3], vec2[3];
1681                                 VECCOPY(vec1, quat);
1682                                 VECCOPY(vec2, v3d->viewquat);
1683                                 Normalize(vec1);
1684                                 Normalize(vec2);
1685                                 /* scale the time allowed by the rotation */
1686                                 time_allowed *= NormalizedVecAngle2(vec1, vec2)/(M_PI/2); 
1687                          }
1688                         
1689                         while (time_start + time_allowed > time_current) {
1690                                 
1691                                 step =  (float)((time_current-time_start) / time_allowed);
1692                                 
1693                                 /* ease in/out */
1694                                 if (step < 0.5) step = pow(step*2, 2)/2;
1695                                 else                    step = 1-(pow(2*(1-step) ,2)/2);
1696                                 
1697                                 step_inv = 1-step;
1698                                 
1699                                 if (ofs)
1700                                         for (i=0; i<3; i++)
1701                                                 v3d->ofs[i] = ofs[i]*step + orig_ofs[i]*step_inv;
1702                                 
1703                                 
1704                                 if (quat)
1705                                         QuatInterpol(v3d->viewquat, orig_quat, quat, step);
1706                                         
1707                                 if (dist)
1708                                         v3d->dist = ((*dist)*step) + (orig_dist*step_inv);
1709                                 
1710                                 if (lens)
1711                                         v3d->lens = ((*lens)*step) + (orig_lens*step_inv);
1712                                 
1713                                 /*redraw the view*/
1714                                 scrarea_do_windraw(curarea);
1715                                 screen_swapbuffers();
1716                                 
1717                                 time_current= PIL_check_seconds_timer();
1718                         }
1719                 }
1720         }
1721         
1722         /* set these values even if animation is enabled because flaot
1723          * error will make then not quite accurate */
1724         if (ofs)
1725                 VECCOPY(v3d->ofs, ofs);
1726         if (quat)
1727                 QUATCOPY(v3d->viewquat, quat);
1728         if (dist)
1729                 v3d->dist = *dist;
1730         if (lens)
1731                 v3d->lens = *lens;
1732         
1733 }
1734
1735
1736
1737 /* Gets the view trasnformation from a camera
1738  * currently dosnt take camzoom into account
1739  * 
1740  * The dist is not modified for this function, if NULL its assimed zero
1741  * */
1742 void view_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens)
1743 {       
1744         float bmat[4][4];
1745         float imat[4][4];
1746         float tmat[3][3];
1747         
1748         if (!ob) return;
1749         
1750         /* Offset */
1751         if (ofs) {
1752                 where_is_object(ob);
1753                 VECCOPY(ofs, ob->obmat[3]);
1754                 VecMulf(ofs, -1.0f); /*flip the vector*/
1755         }
1756         
1757         /* Quat */
1758         if (quat) {
1759                 Mat4CpyMat4(bmat, ob->obmat);
1760                 Mat4Ortho(bmat);
1761                 Mat4Invert(imat, bmat);
1762                 Mat3CpyMat4(tmat, imat);
1763                 Mat3ToQuat(tmat, quat);
1764         }
1765         
1766         if (dist) {
1767                 float vec[3];
1768                 Mat3CpyMat4(tmat, ob->obmat);
1769                 
1770                 vec[0]= vec[1] = 0.0;
1771                 vec[2]= -(*dist);
1772                 Mat3MulVecfl(tmat, vec);
1773                 VecSubf(ofs, ofs, vec);
1774         }
1775         
1776         /* Lens */
1777         if (lens)
1778                 object_view_settings(ob, lens, NULL, NULL);
1779 }
1780
1781 /* For use with smooth view
1782  * 
1783  * the current view is unchanged, blend between the current view and the
1784  * camera view
1785  * */
1786 void smooth_view_to_camera(View3D *v3d)
1787 {
1788         if (!U.smooth_viewtx || !v3d->camera || G.vd->persp != 2) {
1789                 return;
1790         } else {
1791                 Object *ob = v3d->camera;
1792                 
1793                 float orig_ofs[3];
1794                 float orig_dist=v3d->dist;
1795                 float orig_lens=v3d->lens;
1796                 float new_dist=0.0;
1797                 float new_lens=35.0;
1798                 float new_quat[4];
1799                 float new_ofs[3];
1800                 
1801                 VECCOPY(orig_ofs, v3d->ofs);
1802                 
1803                 view_settings_from_ob(ob, new_ofs, new_quat, NULL, &new_lens);
1804                 
1805                 G.vd->persp=1;
1806                 smooth_view(v3d, new_ofs, new_quat, &new_dist, &new_lens);
1807                 VECCOPY(v3d->ofs, orig_ofs);
1808                 v3d->lens= orig_lens;
1809                 v3d->dist = orig_dist; /* restore the dist */
1810                 
1811                 v3d->camera = ob;
1812                 v3d->persp=2;
1813         }
1814 }