Seam Cutting in Faceselect Mode:
[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_anim.h"
65 #include "BKE_global.h"
66 #include "BKE_main.h"
67 #include "BKE_object.h"
68 #include "BKE_utildefines.h"
69
70 #include "BIF_gl.h"
71 #include "BIF_space.h"
72 #include "BIF_mywindow.h"
73 #include "BIF_previewrender.h"
74 #include "BIF_screen.h"
75 #include "BIF_toolbox.h"
76
77 #include "BSE_view.h"
78 #include "BSE_edit.h"           /* For countall */
79 #include "BSE_drawview.h"       /* For inner_play_anim_loop */
80
81 #include "BDR_drawobject.h"     /* For draw_object */
82 #include "BDR_editface.h"       /* For minmax_tface */
83
84 #include "mydevice.h"
85 #include "blendef.h"
86
87 #define TRACKBALLSIZE  (1.1)
88 #define BL_NEAR_CLIP 0.001
89
90
91 /* local prototypes ----------*/
92 void setcameratoview3d(void); /* windows.c & toets.c */
93
94 void persp_general(int a)
95 {
96         /* for all window types, not 3D */
97         
98         if(a== 0) {
99                 glPushMatrix();
100                 glMatrixMode(GL_PROJECTION);
101                 glPushMatrix();
102                 glMatrixMode(GL_MODELVIEW);
103
104                 myortho2(-0.375, ((float)(curarea->winx))-0.375, -0.375, ((float)(curarea->winy))-0.375);
105                 glLoadIdentity();
106         }
107         else if(a== 1) {
108                 glMatrixMode(GL_PROJECTION);
109                 glPopMatrix();
110                 glMatrixMode(GL_MODELVIEW);
111                 glPopMatrix();
112         }
113 }
114
115 void persp(int a)
116 {
117         /* only 3D windows */
118
119         if(curarea->spacetype!=SPACE_VIEW3D) persp_general(a);
120         else if(a == PERSP_STORE) {             // only store
121                 glMatrixMode(GL_PROJECTION);
122                 mygetmatrix(G.vd->winmat1);     
123                 glMatrixMode(GL_MODELVIEW);
124                 mygetmatrix(G.vd->viewmat1); 
125         }
126         else if(a== PERSP_WIN) {                // only set
127                 myortho2(-0.375, (float)(curarea->winx)-0.375, -0.375, (float)(curarea->winy)-0.375);
128                 glLoadIdentity();
129         }
130         else if(a== PERSP_VIEW) {
131                 glMatrixMode(GL_PROJECTION);
132                 myloadmatrix(G.vd->winmat1); // put back
133                 Mat4CpyMat4(curarea->winmat, G.vd->winmat1); // to be sure? 
134                 glMatrixMode(GL_MODELVIEW); 
135                 myloadmatrix(G.vd->viewmat); // put back
136                 
137         }
138 }
139
140
141 float zfac=1.0;
142
143 void initgrabz(float x, float y, float z)
144 {
145         if(G.vd==0) return;
146         zfac= G.vd->persmat[0][3]*x+ G.vd->persmat[1][3]*y+ G.vd->persmat[2][3]*z+ G.vd->persmat[3][3];
147         
148         /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that */
149         if (zfac==0.0f) zfac = 1.0f;
150 }
151
152 void window_to_3d(float *vec, short mx, short my)
153 {
154         /* always call initzgrab */
155         float dx, dy;
156         
157         dx= 2.0f*mx*zfac/curarea->winx;
158         dy= 2.0f*my*zfac/curarea->winy;
159         
160         vec[0]= (G.vd->persinv[0][0]*dx + G.vd->persinv[1][0]*dy);
161         vec[1]= (G.vd->persinv[0][1]*dx + G.vd->persinv[1][1]*dy);
162         vec[2]= (G.vd->persinv[0][2]*dx + G.vd->persinv[1][2]*dy);
163 }
164
165 void project_short(float *vec, short *adr)      /* clips */
166 {
167         float fx, fy, vec4[4];
168
169         adr[0]= IS_CLIPPED;
170         
171         if(G.vd->flag & V3D_CLIPPING) {
172                 if(view3d_test_clipping(G.vd, vec))
173                         return;
174         }
175
176         VECCOPY(vec4, vec);
177         vec4[3]= 1.0;
178         Mat4MulVec4fl(G.vd->persmat, vec4);
179         
180         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
181                 fx= (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
182                 
183                 if( fx>0 && fx<curarea->winx) {
184                 
185                         fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
186                         
187                         if(fy>0.0 && fy< (float)curarea->winy) {
188                                 adr[0]= floor(fx); 
189                                 adr[1]= floor(fy);
190                         }
191                 }
192         }
193 }
194
195 void project_int(float *vec, int *adr)
196 {
197         float fx, fy, vec4[4];
198
199         adr[0]= 2140000000.0f;
200         VECCOPY(vec4, vec);
201         vec4[3]= 1.0;
202         
203         Mat4MulVec4fl(G.vd->persmat, vec4);
204
205         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
206                 fx= (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
207                 
208                 if( fx>-2140000000.0f && fx<2140000000.0f) {
209                         fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
210                         
211                         if(fy>-2140000000.0f && fy<2140000000.0f) {
212                                 adr[0]= floor(fx); 
213                                 adr[1]= floor(fy);
214                         }
215                 }
216         }
217 }
218
219 void project_short_noclip(float *vec, short *adr)
220 {
221         float fx, fy, vec4[4];
222
223         adr[0]= IS_CLIPPED;
224         VECCOPY(vec4, vec);
225         vec4[3]= 1.0;
226         
227         Mat4MulVec4fl(G.vd->persmat, vec4);
228
229         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
230                 fx= (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
231                 
232                 if( fx>-32700 && fx<32700) {
233                 
234                         fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
235                         
236                         if(fy>-32700.0 && fy<32700.0) {
237                                 adr[0]= floor(fx); 
238                                 adr[1]= floor(fy);
239                         }
240                 }
241         }
242 }
243
244 void project_float(float *vec, float *adr)
245 {
246         float vec4[4];
247         
248         adr[0]= IS_CLIPPED;
249         VECCOPY(vec4, vec);
250         vec4[3]= 1.0;
251         
252         Mat4MulVec4fl(G.vd->persmat, vec4);
253
254         if( vec4[3]>BL_NEAR_CLIP ) {
255                 adr[0]= (curarea->winx/2.0)+(curarea->winx/2.0)*vec4[0]/vec4[3];        
256                 adr[1]= (curarea->winy/2.0)+(curarea->winy/2.0)*vec4[1]/vec4[3];
257         }
258 }
259
260 void view3d_get_object_project_mat(ScrArea *area, Object *ob, float pmat[4][4], float vmat[4][4])
261 {
262         if (area->spacetype!=SPACE_VIEW3D || !area->spacedata.first) {
263                 Mat4One(pmat);
264                 Mat4One(vmat);
265         } else {
266                 View3D *vd = area->spacedata.first;
267
268                 Mat4MulMat4(vmat, ob->obmat, vd->viewmat);
269                 Mat4MulMat4(pmat, vmat, vd->winmat1);
270                 Mat4CpyMat4(vmat, ob->obmat);
271         }
272 }
273
274 /* projectmat brings it to window coords, wmat to rotated world space */
275 void view3d_project_short_clip(ScrArea *area, float *vec, short *adr, float projmat[4][4], float wmat[4][4])
276 {
277         View3D *v3d= area->spacedata.first;
278         float fx, fy, vec4[4];
279
280         adr[0]= IS_CLIPPED;
281         
282         /* clipplanes in eye space */
283         if(v3d->flag & V3D_CLIPPING) {
284                 VECCOPY(vec4, vec);
285                 Mat4MulVecfl(wmat, vec4);
286                 if(view3d_test_clipping(v3d, vec4))
287                         return;
288         }
289         
290         VECCOPY(vec4, vec);
291         vec4[3]= 1.0;
292         
293         Mat4MulVec4fl(projmat, vec4);
294         
295         /* clipplanes in window space */
296         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
297                 fx= (area->winx/2)*(1 + vec4[0]/vec4[3]);
298                 
299                 if( fx>0 && fx<area->winx) {
300                 
301                         fy= (area->winy/2)*(1 + vec4[1]/vec4[3]);
302                         
303                         if(fy>0.0 && fy< (float)area->winy) {
304                                 adr[0]= floor(fx); 
305                                 adr[1]= floor(fy);
306                         }
307                 }
308         }
309 }
310
311 void view3d_project_short_noclip(ScrArea *area, float *vec, short *adr, float mat[4][4])
312 {
313         float fx, fy, vec4[4];
314
315         adr[0]= IS_CLIPPED;
316         
317         VECCOPY(vec4, vec);
318         vec4[3]= 1.0;
319         
320         Mat4MulVec4fl(mat, vec4);
321
322         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
323                 fx= (area->winx/2)*(1 + vec4[0]/vec4[3]);
324                 
325                 if( fx>-32700 && fx<32700) {
326                 
327                         fy= (area->winy/2)*(1 + vec4[1]/vec4[3]);
328                         
329                         if(fy>-32700.0 && fy<32700.0) {
330                                 adr[0]= floor(fx); 
331                                 adr[1]= floor(fy);
332                         }
333                 }
334         }
335 }
336
337 void view3d_project_float(ScrArea *area, float *vec, float *adr, float mat[4][4])
338 {
339         float vec4[4];
340         
341         adr[0]= IS_CLIPPED;
342         VECCOPY(vec4, vec);
343         vec4[3]= 1.0;
344         
345         Mat4MulVec4fl(mat, vec4);
346
347         if( vec4[3]>FLT_EPSILON ) {
348                 adr[0] = (area->winx/2.0)+(area->winx/2.0)*vec4[0]/vec4[3];     
349                 adr[1] = (area->winy/2.0)+(area->winy/2.0)*vec4[1]/vec4[3];
350         } else {
351                 adr[0] = adr[1] = 0.0;
352         }
353 }
354
355 int boundbox_clip(float obmat[][4], BoundBox *bb)
356 {
357         /* return 1: draw */
358         
359         float mat[4][4];
360         float vec[4], min, max;
361         int a, flag= -1, fl;
362         
363         if(bb==0) return 1;
364         
365         Mat4MulMat4(mat, obmat, G.vd->persmat);
366
367         for(a=0; a<8; a++) {
368                 VECCOPY(vec, bb->vec[a]);
369                 vec[3]= 1.0;
370                 Mat4MulVec4fl(mat, vec);
371                 max= vec[3];
372                 min= -vec[3];
373
374                 fl= 0;
375                 if(vec[0] < min) fl+= 1;
376                 if(vec[0] > max) fl+= 2;
377                 if(vec[1] < min) fl+= 4;
378                 if(vec[1] > max) fl+= 8;
379                 if(vec[2] < min) fl+= 16;
380                 if(vec[2] > max) fl+= 32;
381                 
382                 flag &= fl;
383                 if(flag==0) return 1;
384         }
385
386         return 0;
387
388 }
389
390 void fdrawline(float x1, float y1, float x2, float y2)
391 {
392         float v[2];
393
394         glBegin(GL_LINE_STRIP);
395         v[0] = x1; v[1] = y1;
396         glVertex2fv(v);
397         v[0] = x2; v[1] = y2;
398         glVertex2fv(v);
399         glEnd();
400 }
401
402 void fdrawbox(float x1, float y1, float x2, float y2)
403 {
404         float v[2];
405
406         glBegin(GL_LINE_STRIP);
407
408         v[0] = x1; v[1] = y1;
409         glVertex2fv(v);
410         v[0] = x1; v[1] = y2;
411         glVertex2fv(v);
412         v[0] = x2; v[1] = y2;
413         glVertex2fv(v);
414         v[0] = x2; v[1] = y1;
415         glVertex2fv(v);
416         v[0] = x1; v[1] = y1;
417         glVertex2fv(v);
418
419         glEnd();
420 }
421
422 void sdrawline(short x1, short y1, short x2, short y2)
423 {
424         short v[2];
425
426         glBegin(GL_LINE_STRIP);
427         v[0] = x1; v[1] = y1;
428         glVertex2sv(v);
429         v[0] = x2; v[1] = y2;
430         glVertex2sv(v);
431         glEnd();
432 }
433
434 void sdrawbox(short x1, short y1, short x2, short y2)
435 {
436         short v[2];
437
438         glBegin(GL_LINE_STRIP);
439
440         v[0] = x1; v[1] = y1;
441         glVertex2sv(v);
442         v[0] = x1; v[1] = y2;
443         glVertex2sv(v);
444         v[0] = x2; v[1] = y2;
445         glVertex2sv(v);
446         v[0] = x2; v[1] = y1;
447         glVertex2sv(v);
448         v[0] = x1; v[1] = y1;
449         glVertex2sv(v);
450
451         glEnd();
452 }
453
454 /* the central math in this function was copied from trackball.cpp, sample code from the 
455    Developers Toolbox series by SGI. */
456
457 /* trackball: better one than a full spherical solution */
458
459 void calctrackballvecfirst(rcti *area, short *mval, float *vec)
460 {
461         float x, y, radius, d, z, t;
462         
463         radius= TRACKBALLSIZE;
464         
465         /* normalise x and y */
466         x= (area->xmax + area->xmin)/2 -mval[0];
467         x/= (float)((area->xmax - area->xmin)/2);
468         y= (area->ymax + area->ymin)/2 -mval[1];
469         y/= (float)((area->ymax - area->ymin)/2);
470         
471         d = sqrt(x*x + y*y);
472         if (d < radius*M_SQRT1_2)       /* Inside sphere */
473                 z = sqrt(radius*radius - d*d);
474         else
475         {                       /* On hyperbola */
476                 t = radius / M_SQRT2;
477                 z = t*t / d;
478         }
479
480         vec[0]= x;
481         vec[1]= y;
482         vec[2]= -z;             /* yah yah! */
483
484         if( fabs(vec[2])>fabs(vec[1]) && fabs(vec[2])>fabs(vec[0]) ) {
485                 vec[0]= 0.0;
486                 vec[1]= 0.0;
487                 if(vec[2]>0.0) vec[2]= 1.0; else vec[2]= -1.0;
488         }
489         else if( fabs(vec[1])>fabs(vec[0]) && fabs(vec[1])>fabs(vec[2]) ) {
490                 vec[0]= 0.0;
491                 vec[2]= 0.0;
492                 if(vec[1]>0.0) vec[1]= 1.0; else vec[1]= -1.0;
493         }
494         else  {
495                 vec[1]= 0.0;
496                 vec[2]= 0.0;
497                 if(vec[0]>0.0) vec[0]= 1.0; else vec[0]= -1.0;
498         }
499 }
500
501 void calctrackballvec(rcti *area, short *mval, float *vec)
502 {
503         float x, y, radius, d, z, t;
504         
505         radius= TRACKBALLSIZE;
506         
507         /* x en y normaliseren */
508         x= (area->xmax + area->xmin)/2 -mval[0];
509         x/= (float)((area->xmax - area->xmin)/4);
510         y= (area->ymax + area->ymin)/2 -mval[1];
511         y/= (float)((area->ymax - area->ymin)/2);
512         
513         d = sqrt(x*x + y*y);
514         if (d < radius*M_SQRT1_2)       /* Inside sphere */
515                 z = sqrt(radius*radius - d*d);
516         else
517         {                       /* On hyperbola */
518                 t = radius / M_SQRT2;
519                 z = t*t / d;
520         }
521
522         vec[0]= x;
523         vec[1]= y;
524         vec[2]= -z;             /* yah yah! */
525
526 }
527
528 void viewmove(int mode)
529 {
530         Object *ob = OBACT;
531         float firstvec[3], newvec[3], dvec[3];
532         float reverse, oldquat[4], q1[4], si, phi, dist0;
533         float ofs[3], obofs[3];
534         int firsttime=1;
535         short mvalball[2], mval[2], mvalo[2];
536         short use_sel = 0;
537         short preview3d_event= 1;
538         
539         /* 3D window may not be defined */
540         if( !G.vd ) {
541                 fprintf( stderr, "G.vd == NULL in viewmove()\n" );
542                 return;
543         }
544
545         /* sometimes this routine is called from headerbuttons */
546
547         areawinset(curarea->win);
548         
549         initgrabz(-G.vd->ofs[0], -G.vd->ofs[1], -G.vd->ofs[2]);
550         
551         QUATCOPY(oldquat, G.vd->viewquat);
552         
553         getmouseco_sc(mvalo);           /* work with screen coordinates because of trackball function */
554         mvalball[0]= mvalo[0];                  /* needed for turntable to work */
555         mvalball[1]= mvalo[1];
556         dist0= G.vd->dist;
557         
558         calctrackballvec(&curarea->winrct, mvalo, firstvec);
559
560         /* cumultime(0); */
561
562         if (G.obedit==NULL && ob && !(ob->flag & OB_POSEMODE) && U.uiflag & USER_ORBIT_SELECTION) {
563                 use_sel = 1;
564                 VECCOPY(ofs, G.vd->ofs);
565                 if (ob) {
566                         obofs[0] = -ob->obmat[3][0];
567                         obofs[1] = -ob->obmat[3][1];
568                         obofs[2] = -ob->obmat[3][2];
569                 }
570                 else {
571                         VECCOPY(obofs, ofs);
572                 }
573         }
574         else
575                 ofs[0] = ofs[1] = ofs[2] = 0.0f;
576
577         reverse= 1.0f;
578         if (G.vd->persmat[2][1] < 0.0f)
579                 reverse= -1.0f;
580
581         while(TRUE) {
582                 getmouseco_sc(mval);
583                 
584                 // if playanim = alt+A, screenhandlers are for animated UI, python, etc
585                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || (G.f & G_PLAYANIM) || do_screenhandlers(G.curscreen)) {
586                         
587                         if(firsttime) {
588                                 
589                                 firsttime= 0;
590                                 /* are we translating, rotating or zooming? */
591                                 if(mode==0) {
592                                         if(G.vd->view!=0) scrarea_queue_headredraw(curarea);    /*for button */
593                                         G.vd->view= 0;
594                                 }
595                                                 
596                                 if(G.vd->persp==2 && mode!=1) {
597                                         G.vd->persp= 1;
598                                         scrarea_do_windraw(curarea);
599                                         scrarea_queue_headredraw(curarea);
600                                 }
601                         }
602
603
604                         if(mode==0) {   /* view rotate */
605                                 if (U.uiflag & USER_AUTOPERSP) G.vd->persp= 1;
606
607                                 if (U.flag & USER_TRACKBALL) mvalball[0]= mval[0];
608                                 mvalball[1]= mval[1];
609                                 
610                                 calctrackballvec(&curarea->winrct, mvalball, newvec);
611                                 
612                                 VecSubf(dvec, newvec, firstvec);
613                                 
614                                 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
615                                 si/= (2.0*TRACKBALLSIZE);
616                         
617                                 if (U.flag & USER_TRACKBALL) {
618                                         Crossf(q1+1, firstvec, newvec);
619         
620                                         Normalise(q1+1);
621         
622                                         /* Allow for rotation beyond the interval
623                                          * [-pi, pi] */
624                                         while (si > 1.0)
625                                                 si -= 2.0;
626                 
627                                         /* This relation is used instead of
628                                          * phi = asin(si) so that the angle
629                                          * of rotation is linearly proportional
630                                          * to the distance that the mouse is
631                                          * dragged. */
632                                         phi = si * M_PI / 2.0;
633                 
634                                         si= sin(phi);
635                                         q1[0]= cos(phi);
636                                         q1[1]*= si;
637                                         q1[2]*= si;
638                                         q1[3]*= si;     
639                                         QuatMul(G.vd->viewquat, q1, oldquat);
640
641                                         if (use_sel) {
642                                                 /* compute the post multiplication quat, to rotate the offset correctly */
643                                                 QUATCOPY(q1, oldquat);
644                                                 QuatConj(q1);
645                                                 QuatMul(q1, q1, G.vd->viewquat);
646
647                                                 QuatConj(q1); /* conj == inv for unit quat */
648                                                 VECCOPY(G.vd->ofs, ofs);
649                                                 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
650                                                 QuatMulVecf(q1, G.vd->ofs);
651                                                 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
652                                         }
653                                 } else {
654                                         /* New turntable view code by John Aughey */
655
656                                         float m[3][3];
657                                         float m_inv[3][3];
658                                         float xvec[3] = {1,0,0};
659                                         /* Sensitivity will control how fast the viewport rotates.  0.0035 was
660                                            obtained experimentally by looking at viewport rotation sensitivities
661                                            on other modeling programs. */
662                                         /* Perhaps this should be a configurable user parameter. */
663                                         const float sensitivity = 0.0035;
664
665                                         /* Get the 3x3 matrix and its inverse from the quaternion */
666                                         QuatToMat3(G.vd->viewquat, m);
667                                         Mat3Inv(m_inv,m);
668
669                                         /* Determine the direction of the x vector (for rotating up and down) */
670                                         /* This can likely be compuated directly from the quaternion. */
671                                         Mat3MulVecfl(m_inv,xvec);
672
673                                         /* Perform the up/down rotation */
674                                         phi = sensitivity * -(mval[1] - mvalo[1]);
675                                         si = sin(phi);
676                                         q1[0] = cos(phi);
677                                         q1[1] = si * xvec[0];
678                                         q1[2] = si * xvec[1];
679                                         q1[3] = si * xvec[2];
680                                         QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
681
682                                         if (use_sel) {
683                                                 QuatConj(q1); /* conj == inv for unit quat */
684                                                 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
685                                                 QuatMulVecf(q1, G.vd->ofs);
686                                                 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
687                                         }
688
689                                         /* Perform the orbital rotation */
690                                         phi = sensitivity * reverse * (mval[0] - mvalo[0]);
691                                         q1[0] = cos(phi);
692                                         q1[1] = q1[2] = 0.0;
693                                         q1[3] = sin(phi);
694                                         QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
695
696                                         if (use_sel) {
697                                                 QuatConj(q1);
698                                                 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
699                                                 QuatMulVecf(q1, G.vd->ofs);
700                                                 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
701                                         }
702                                 }
703                         }
704                         else if(mode==1) {      /* translate */
705                                 if(G.vd->persp==2) {
706                                         float max= (float)MAX2(curarea->winx, curarea->winy);
707
708                                         G.vd->camdx += (mvalo[0]-mval[0])/(max);
709                                         G.vd->camdy += (mvalo[1]-mval[1])/(max);
710                                         CLAMP(G.vd->camdx, -1.0f, 1.0f);
711                                         CLAMP(G.vd->camdy, -1.0f, 1.0f);
712                                         preview3d_event= 0;
713                                 }
714                                 else {
715                                         window_to_3d(dvec, mval[0]-mvalo[0], mval[1]-mvalo[1]);
716                                         VecAddf(G.vd->ofs, G.vd->ofs, dvec);
717                                 }
718                         }
719                         else if(mode==2) {
720                                 if(U.viewzoom==USER_ZOOM_CONT) {
721                                         // oldstyle zoom
722                                         G.vd->dist*= 1.0+(float)(mvalo[0]-mval[0]+mvalo[1]-mval[1])/1000.0;
723                                 }
724                                 else if(U.viewzoom==USER_ZOOM_SCALE) {
725                                         int ctr[2], len1, len2;
726                                         // method which zooms based on how far you move the mouse
727                                         
728                                         ctr[0] = (curarea->winrct.xmax + curarea->winrct.xmin)/2;
729                                         ctr[1] = (curarea->winrct.ymax + curarea->winrct.ymin)/2;
730                                         
731                                         len1 = (int)sqrt((ctr[0] - mval[0])*(ctr[0] - mval[0]) + (ctr[1] - mval[1])*(ctr[1] - mval[1])) + 5;
732                                         len2 = (int)sqrt((ctr[0] - mvalo[0])*(ctr[0] - mvalo[0]) + (ctr[1] - mvalo[1])*(ctr[1] - mvalo[1])) + 5;
733                                         
734                                         G.vd->dist= dist0 * ((float)len2/len1);
735                                 }
736                                 else {  /* USER_ZOOM_DOLLY */
737                                         float len1 = (curarea->winrct.ymax - mval[1]) + 5;
738                                         float len2 = (curarea->winrct.ymax - mvalo[1]) + 5;
739                                         
740                                         G.vd->dist= dist0 * (2.0*((len2/len1)-1.0) + 1.0);
741                                 }
742                                 
743                                 /* these limits are in toets.c too */
744                                 if(G.vd->dist<0.001*G.vd->grid) G.vd->dist= 0.001*G.vd->grid;
745                                 if(G.vd->dist>10.0*G.vd->far) G.vd->dist=10.0*G.vd->far;
746                                 
747                                 mval[1]= mvalo[1]; /* preserve first value */
748                                 mval[0]= mvalo[0];
749                                 
750                                 if(G.vd->persp==0 || G.vd->persp==2) preview3d_event= 0;
751                         }
752                         
753                         mvalo[0]= mval[0];
754                         mvalo[1]= mval[1];
755
756                         if(G.f & G_PLAYANIM) inner_play_anim_loop(0, 0);
757                         if(G.f & G_SIMULATION) break;
758
759                         scrarea_do_windraw(curarea);
760                         screen_swapbuffers();
761                 }
762                 else {
763                         short val;
764                         unsigned short event;
765                         /* we need to empty the queue... when you do this very long it overflows */
766                         while(qtest()) event= extern_qread(&val);
767                         
768                         BIF_wait_for_statechange();
769                 }
770                 
771                 /* this in the end, otherwise get_mbut does not work on a PC... */
772                 if( !(get_mbut() & (L_MOUSE|M_MOUSE))) break;
773         }
774
775         if(preview3d_event) 
776                 BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
777         else
778                 BIF_view3d_previewrender_signal(curarea, PR_PROJECTED);
779
780 }
781
782 int get_view3d_viewplane(int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend)
783 {
784         Camera *cam=NULL;
785         float lens, fac, x1, y1, x2, y2;
786         float winx= (float)winxi, winy= (float)winyi;
787         int orth= 0;
788         
789         lens= G.vd->lens;       
790         
791         *clipsta= G.vd->near;
792         *clipend= G.vd->far;
793
794         if(G.vd->persp==2) {
795                 *clipsta= G.vd->near;
796                 *clipend= G.vd->far;
797                 if(G.vd->camera) {
798                         if(G.vd->camera->type==OB_LAMP ) {
799                                 Lamp *la;
800                                 
801                                 la= G.vd->camera->data;
802                                 fac= cos( M_PI*la->spotsize/360.0);
803                                 
804                                 x1= saacos(fac);
805                                 lens= 16.0*fac/sin(x1);
806                 
807                                 *clipsta= la->clipsta;
808                                 *clipend= la->clipend;
809                         }
810                         else if(G.vd->camera->type==OB_CAMERA) {
811                                 cam= G.vd->camera->data;
812                                 lens= cam->lens;
813                                 *clipsta= cam->clipsta;
814                                 *clipend= cam->clipend;
815                         }
816                 }
817         }
818         
819         if(G.vd->persp==0) {
820                 if(winx>winy) x1= -G.vd->dist;
821                 else x1= -winx*G.vd->dist/winy;
822                 x2= -x1;
823
824                 if(winx>winy) y1= -winy*G.vd->dist/winx;
825                 else y1= -G.vd->dist;
826                 y2= -y1;
827                 
828                 *clipend *= 0.5;        // otherwise too extreme low zbuffer quality
829                 *clipsta= - *clipend;
830                 orth= 1;
831         }
832         else {
833                 if(G.vd->persp==2) {
834                         fac= (1.41421+( (float)G.vd->camzoom )/50.0);
835                         fac*= fac;
836                 }
837                 else fac= 2.0;
838                 
839                 /* viewplane size depends... */
840                 if(cam && cam->type==CAM_ORTHO) {
841                         /* ortho_scale == 1 means exact 1 to 1 mapping */
842                         float dfac= 2.0*cam->ortho_scale/fac;
843                         
844                         if(winx>winy) x1= -dfac;
845                         else x1= -winx*dfac/winy;
846                         x2= -x1;
847                         
848                         if(winx>winy) y1= -winy*dfac/winx;
849                         else y1= -dfac;
850                         y2= -y1;
851                         orth= 1;
852                 }
853                 else {
854                         float dfac;
855                         
856                         if(winx>winy) dfac= 64.0/(fac*winx*lens);
857                         else dfac= 64.0/(fac*winy*lens);
858                         
859                         x1= - *clipsta * winx*dfac;
860                         x2= -x1;
861                         y1= - *clipsta * winy*dfac;
862                         y2= -y1;
863                         orth= 0;
864                 }
865                 /* cam view offset */
866                 if(cam) {
867                         float dx= G.vd->camdx*(x2-x1);
868                         float dy= G.vd->camdy*(y2-y1);
869                         x1+= dx;
870                         x2+= dx;
871                         y1+= dy;
872                         y2+= dy;
873                 }
874         }
875         
876         viewplane->xmin= x1;
877         viewplane->ymin= y1;
878         viewplane->xmax= x2;
879         viewplane->ymax= y2;
880         
881         return orth;
882 }
883
884 /* important to not set windows active in here, can be renderwin for example */
885 void setwinmatrixview3d(int winx, int winy, rctf *rect)         /* rect: for picking */
886 {
887         rctf viewplane;
888         float clipsta, clipend, x1, y1, x2, y2;
889         int orth;
890         
891         orth= get_view3d_viewplane(winx, winy, &viewplane, &clipsta, &clipend);
892 //      printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
893         x1= viewplane.xmin;
894         y1= viewplane.ymin;
895         x2= viewplane.xmax;
896         y2= viewplane.ymax;
897         
898         if(rect) {              /* picking */
899                 rect->xmin/= (float)curarea->winx;
900                 rect->xmin= x1+rect->xmin*(x2-x1);
901                 rect->ymin/= (float)curarea->winy;
902                 rect->ymin= y1+rect->ymin*(y2-y1);
903                 rect->xmax/= (float)curarea->winx;
904                 rect->xmax= x1+rect->xmax*(x2-x1);
905                 rect->ymax/= (float)curarea->winy;
906                 rect->ymax= y1+rect->ymax*(y2-y1);
907                 
908                 if(orth) myortho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
909                 else mywindow(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
910                 
911         }
912         else {
913                 if(orth) myortho(x1, x2, y1, y2, clipsta, clipend);
914                 else mywindow(x1, x2, y1, y2, clipsta, clipend);
915         }
916
917         /* not sure what this was for? (ton) */
918         glMatrixMode(GL_PROJECTION);
919         mygetmatrix(curarea->winmat);
920         glMatrixMode(GL_MODELVIEW);
921 }
922
923 void obmat_to_viewmat(Object *ob)
924 {
925         float bmat[4][4];
926         float tmat[3][3];
927
928         Mat4CpyMat4(bmat, ob->obmat);
929         Mat4Ortho(bmat);
930         Mat4Invert(G.vd->viewmat, bmat);
931         
932         /* view quat calculation, needed for add object */
933         Mat3CpyMat4(tmat, G.vd->viewmat);
934         Mat3ToQuat(tmat, G.vd->viewquat);
935 }
936
937 /* dont set windows active in in here, is used by renderwin too */
938 void setviewmatrixview3d()
939 {
940         Camera *cam;
941
942         if(G.vd->persp>=2) {        /* obs/camera */
943                 if(G.vd->camera) {
944                         
945                         where_is_object(G.vd->camera);  
946                         obmat_to_viewmat(G.vd->camera);
947                         
948                         if(G.vd->camera->type==OB_CAMERA) {
949                                 cam= G.vd->camera->data;
950                                 //if(cam->type==CAM_ORTHO) G.vd->viewmat[3][2]*= 100.0;
951                         }
952                 }
953                 else {
954                         QuatToMat4(G.vd->viewquat, G.vd->viewmat);
955                         G.vd->viewmat[3][2]-= G.vd->dist;
956                 }
957         }
958         else {
959                 
960                 QuatToMat4(G.vd->viewquat, G.vd->viewmat);
961                 if(G.vd->persp==1) G.vd->viewmat[3][2]-= G.vd->dist;
962                 i_translate(G.vd->ofs[0], G.vd->ofs[1], G.vd->ofs[2], G.vd->viewmat);
963         }
964 }
965
966 void setcameratoview3d(void)
967 {
968         Object *ob;
969         float dvec[3];
970
971         ob= G.vd->camera;
972         dvec[0]= G.vd->dist*G.vd->viewinv[2][0];
973         dvec[1]= G.vd->dist*G.vd->viewinv[2][1];
974         dvec[2]= G.vd->dist*G.vd->viewinv[2][2];                                        
975         VECCOPY(ob->loc, dvec);
976         VecSubf(ob->loc, ob->loc, G.vd->ofs);
977         G.vd->viewquat[0]= -G.vd->viewquat[0];
978         if (ob->transflag & OB_QUAT) {
979                 QUATCOPY(ob->quat, G.vd->viewquat);
980         } else {
981                 QuatToEul(G.vd->viewquat, ob->rot);
982         }
983         G.vd->viewquat[0]= -G.vd->viewquat[0];
984 }
985
986 /* IGLuint-> GLuint*/
987 short  view3d_opengl_select(unsigned int *buffer, unsigned int bufsize, short x1, short y1, short x2, short y2)
988 {
989         rctf rect;
990         short mval[2], code, hits;
991
992         G.f |= G_PICKSEL;
993         
994         if(x1==0 && x2==0 && y1==0 && y2==0) {
995                 getmouseco_areawin(mval);
996                 rect.xmin= mval[0]-12;  // seems to be default value for bones only now
997                 rect.xmax= mval[0]+12;
998                 rect.ymin= mval[1]-12;
999                 rect.ymax= mval[1]+12;
1000         }
1001         else {
1002                 rect.xmin= x1;
1003                 rect.xmax= x2;
1004                 rect.ymin= y1;
1005                 rect.ymax= y2;
1006         }
1007         /* get rid of overlay button matrix */
1008         persp(PERSP_VIEW);
1009         setwinmatrixview3d(curarea->winx, curarea->winy, &rect);
1010         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
1011         
1012         if(G.vd->drawtype > OB_WIRE) {
1013                 G.vd->zbuf= TRUE;
1014                 glEnable(GL_DEPTH_TEST);
1015         }
1016
1017         if(G.vd->flag & V3D_CLIPPING)
1018                 view3d_set_clipping(G.vd);
1019         
1020         glSelectBuffer( bufsize, (GLuint *)buffer);
1021         glRenderMode(GL_SELECT);
1022         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1023         glPushName(-1);
1024         code= 1;
1025         
1026         if(G.obedit && G.obedit->type==OB_MBALL) {
1027                 draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1028         }
1029         else if ((G.obedit && G.obedit->type==OB_ARMATURE)) {
1030                 draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1031         }
1032         else {
1033                 Base *base;
1034                 
1035                 G.vd->xray= TRUE;       // otherwise it postpones drawing
1036                 for(base= G.scene->base.first; base; base= base->next) {
1037                         if(base->lay & G.vd->lay) {
1038                                 base->selcol= code;
1039                                 glLoadName(code);
1040                                 draw_object(base, DRAW_PICKING|DRAW_CONSTCOLOR);
1041                                 
1042                                 /* we draw group-duplicators for selection too */
1043                                 if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1044                                         ListBase *lb;
1045                                         DupliObject *dob;
1046                                         Base tbase;
1047                                         
1048                                         tbase.flag= OB_FROMDUPLI;
1049                                         lb= object_duplilist(G.scene, base->object);
1050                                         
1051                                         for(dob= lb->first; dob; dob= dob->next) {
1052                                                 tbase.object= dob->ob;
1053                                                 Mat4CpyMat4(dob->ob->obmat, dob->mat);
1054                                                 
1055                                                 draw_object(&tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1056                                                 
1057                                                 Mat4CpyMat4(dob->ob->obmat, dob->omat);
1058                                         }
1059                                         BLI_freelistN(lb);
1060                                 }
1061                                 
1062                                 code++;
1063                         }
1064                 }
1065                 G.vd->xray= FALSE;      // restore
1066         }
1067         
1068         glPopName();    /* see above (pushname) */
1069         hits= glRenderMode(GL_RENDER);
1070         if(hits<0) error("Too many objects in select buffer");
1071
1072         G.f &= ~G_PICKSEL;
1073         setwinmatrixview3d(curarea->winx, curarea->winy, NULL);
1074         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
1075         
1076         if(G.vd->drawtype > OB_WIRE) {
1077                 G.vd->zbuf= 0;
1078                 glDisable(GL_DEPTH_TEST);
1079         }
1080         persp(PERSP_WIN);
1081         
1082         if(G.vd->flag & V3D_CLIPPING)
1083                 view3d_clr_clipping();
1084
1085         return hits;
1086 }
1087
1088 float *give_cursor()
1089 {
1090         if(G.vd && G.vd->localview) return G.vd->cursor;
1091         else return G.scene->cursor;
1092 }
1093
1094 unsigned int free_localbit()
1095 {
1096         unsigned int lay;
1097         ScrArea *sa;
1098         bScreen *sc;
1099         
1100         lay= 0;
1101         
1102         /* sometimes we loose a localview: when an area is closed */
1103         /* check all areas: which localviews are in use? */
1104         sc= G.main->screen.first;
1105         while(sc) {
1106                 sa= sc->areabase.first;
1107                 while(sa) {
1108                         SpaceLink *sl= sa->spacedata.first;
1109                         while(sl) {
1110                                 if(sl->spacetype==SPACE_VIEW3D) {
1111                                         View3D *v3d= (View3D*) sl;
1112                                         lay |= v3d->lay;
1113                                 }
1114                                 sl= sl->next;
1115                         }
1116                         sa= sa->next;
1117                 }
1118                 sc= sc->id.next;
1119         }
1120         
1121         if( (lay & 0x01000000)==0) return 0x01000000;
1122         if( (lay & 0x02000000)==0) return 0x02000000;
1123         if( (lay & 0x04000000)==0) return 0x04000000;
1124         if( (lay & 0x08000000)==0) return 0x08000000;
1125         if( (lay & 0x10000000)==0) return 0x10000000;
1126         if( (lay & 0x20000000)==0) return 0x20000000;
1127         if( (lay & 0x40000000)==0) return 0x40000000;
1128         if( (lay & 0x80000000)==0) return 0x80000000;
1129         
1130         return 0;
1131 }
1132
1133
1134 void initlocalview()
1135 {
1136         Base *base;
1137         float size = 0.0, min[3], max[3], afm[3];
1138         unsigned int locallay;
1139         int ok=0;
1140
1141         if(G.vd->localvd) return;
1142
1143         min[0]= min[1]= min[2]= 1.0e10;
1144         max[0]= max[1]= max[2]= -1.0e10;
1145
1146         locallay= free_localbit();
1147
1148         if(locallay==0) {
1149                 error("Sorry,  no more than 8 localviews");
1150                 ok= 0;
1151         }
1152         else {
1153                 if(G.obedit) {
1154                         minmax_object(G.obedit, min, max);
1155                         
1156                         ok= 1;
1157                 
1158                         BASACT->lay |= locallay;
1159                         G.obedit->lay= BASACT->lay;
1160                 }
1161                 else {
1162                         base= FIRSTBASE;
1163                         while(base) {
1164                                 if TESTBASE(base)  {
1165                                         minmax_object(base->object, min, max);
1166                                         base->lay |= locallay;
1167                                         base->object->lay= base->lay;
1168                                         ok= 1;
1169                                 }
1170                                 base= base->next;
1171                         }
1172                 }
1173                 
1174                 afm[0]= (max[0]-min[0]);
1175                 afm[1]= (max[1]-min[1]);
1176                 afm[2]= (max[2]-min[2]);
1177                 size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1178                 if(size<=0.01) size= 0.01;
1179         }
1180         
1181         if(ok) {
1182                 G.vd->localvd= MEM_mallocN(sizeof(View3D), "localview");
1183                 memcpy(G.vd->localvd, G.vd, sizeof(View3D));
1184
1185                 G.vd->ofs[0]= -(min[0]+max[0])/2.0;
1186                 G.vd->ofs[1]= -(min[1]+max[1])/2.0;
1187                 G.vd->ofs[2]= -(min[2]+max[2])/2.0;
1188
1189                 G.vd->dist= size;
1190
1191                 // correction for window aspect ratio
1192                 if(curarea->winy>2 && curarea->winx>2) {
1193                         size= (float)curarea->winx/(float)curarea->winy;
1194                         if(size<1.0) size= 1.0/size;
1195                         G.vd->dist*= size;
1196                 }
1197                 
1198                 if(G.vd->persp>1) {
1199                         G.vd->persp= 1;
1200                         
1201                 }
1202                 G.vd->near= 0.1;
1203                 G.vd->cursor[0]= -G.vd->ofs[0];
1204                 G.vd->cursor[1]= -G.vd->ofs[1];
1205                 G.vd->cursor[2]= -G.vd->ofs[2];
1206
1207                 G.vd->lay= locallay;
1208                 
1209                 countall();
1210                 scrarea_queue_winredraw(curarea);
1211         }
1212         else {
1213                 /* clear flags */
1214                 base= FIRSTBASE;
1215                 while(base) {
1216                         if( base->lay & locallay ) {
1217                                 base->lay-= locallay;
1218                                 if(base->lay==0) base->lay= G.vd->layact;
1219                                 if(base->object != G.obedit) base->flag |= SELECT;
1220                                 base->object->lay= base->lay;
1221                         }
1222                         base= base->next;
1223                 }
1224                 scrarea_queue_headredraw(curarea);
1225                 
1226                 G.vd->localview= 0;
1227         }
1228         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1229 }
1230
1231 void centreview()       /* like a localview without local! */
1232 {
1233         Object *ob= OBACT;
1234         float size, min[3], max[3], afm[3];
1235         int ok=0;
1236
1237         min[0]= min[1]= min[2]= 1.0e10;
1238         max[0]= max[1]= max[2]= -1.0e10;
1239
1240         if(G.obedit) {
1241                 minmax_verts(min, max); // ony selected
1242                 ok= 1;
1243         }
1244         else if(ob && (ob->flag & OB_POSEMODE)) {
1245                 if(ob->pose) {
1246                         bArmature *arm= ob->data;
1247                         bPoseChannel *pchan;
1248                         float vec[3];
1249                         
1250                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
1251                                 if(pchan->bone->flag & BONE_SELECTED) {
1252                                         if(pchan->bone->layer & arm->layer) {
1253                                                 ok= 1;
1254                                                 VECCOPY(vec, pchan->pose_head);
1255                                                 Mat4MulVecfl(ob->obmat, vec);
1256                                                 DO_MINMAX(vec, min, max);
1257                                                 VECCOPY(vec, pchan->pose_tail);
1258                                                 Mat4MulVecfl(ob->obmat, vec);
1259                                                 DO_MINMAX(vec, min, max);
1260                                         }
1261                                 }
1262                         }
1263                 }
1264         }
1265         else if (G.f & G_FACESELECT) {
1266                 minmax_tface(min, max);
1267                 ok= 1;
1268         }
1269         else {
1270                 Base *base= FIRSTBASE;
1271                 while(base) {
1272                         if TESTBASE(base)  {
1273                                 minmax_object(base->object, min, max);
1274                                 ok= 1;
1275                         }
1276                         base= base->next;
1277                 }
1278         }
1279         
1280         if(ok==0) return;
1281         
1282         afm[0]= (max[0]-min[0]);
1283         afm[1]= (max[1]-min[1]);
1284         afm[2]= (max[2]-min[2]);
1285         size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1286         
1287         if(size<=0.01) size= 0.01;
1288         
1289         G.vd->ofs[0]= -(min[0]+max[0])/2.0;
1290         G.vd->ofs[1]= -(min[1]+max[1])/2.0;
1291         G.vd->ofs[2]= -(min[2]+max[2])/2.0;
1292
1293         G.vd->dist= size;
1294
1295         // correction for window aspect ratio
1296         if(curarea->winy>2 && curarea->winx>2) {
1297                 size= (float)curarea->winx/(float)curarea->winy;
1298                 if(size<1.0) size= 1.0/size;
1299                 G.vd->dist*= size;
1300         }
1301         
1302         if(G.vd->persp>1) {
1303                 G.vd->persp= 1;
1304         }
1305
1306         G.vd->cursor[0]= -G.vd->ofs[0];
1307         G.vd->cursor[1]= -G.vd->ofs[1];
1308         G.vd->cursor[2]= -G.vd->ofs[2];
1309
1310         scrarea_queue_winredraw(curarea);
1311         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1312
1313 }
1314
1315
1316 void restore_localviewdata(View3D *vd)
1317 {
1318         if(vd->localvd==0) return;
1319         
1320         VECCOPY(vd->ofs, vd->localvd->ofs);
1321         vd->dist= vd->localvd->dist;
1322         vd->persp= vd->localvd->persp;
1323         vd->view= vd->localvd->view;
1324         vd->near= vd->localvd->near;
1325         vd->far= vd->localvd->far;
1326         vd->lay= vd->localvd->lay;
1327         vd->layact= vd->localvd->layact;
1328         vd->drawtype= vd->localvd->drawtype;
1329         vd->camera= vd->localvd->camera;
1330         QUATCOPY(vd->viewquat, vd->localvd->viewquat);
1331         
1332 }
1333
1334 void endlocalview(ScrArea *sa)
1335 {
1336         View3D *v3d;
1337         struct Base *base;
1338         unsigned int locallay;
1339         
1340         if(sa->spacetype!=SPACE_VIEW3D) return;
1341         v3d= sa->spacedata.first;
1342         
1343         if(v3d->localvd) {
1344                 
1345                 locallay= v3d->lay & 0xFF000000;
1346                 
1347                 restore_localviewdata(v3d);
1348                 
1349                 MEM_freeN(v3d->localvd);
1350                 v3d->localvd= 0;
1351                 v3d->localview= 0;
1352
1353                 /* for when in other window the layers have changed */
1354                 if(v3d->scenelock) v3d->lay= G.scene->lay;
1355                 
1356                 base= FIRSTBASE;
1357                 while(base) {
1358                         if( base->lay & locallay ) {
1359                                 base->lay-= locallay;
1360                                 if(base->lay==0) base->lay= v3d->layact;
1361                                 if(base->object != G.obedit) {
1362                                         base->flag |= SELECT;
1363                                         base->object->flag |= SELECT;
1364                                 }
1365                                 base->object->lay= base->lay;
1366                         }
1367                         base= base->next;
1368                 }
1369
1370                 countall();
1371                 allqueue(REDRAWVIEW3D, 0);      /* because of select */
1372                 allqueue(REDRAWOOPS, 0);        /* because of select */
1373                 BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1374         }
1375 }
1376
1377 void view3d_home(int centre)
1378 {
1379         Base *base;
1380         float size, min[3], max[3], afm[3];
1381         int ok= 1, onedone=0;
1382
1383         if(centre) {
1384                 min[0]= min[1]= min[2]= 0.0;
1385                 max[0]= max[1]= max[2]= 0.0;
1386         }
1387         else {
1388                 min[0]= min[1]= min[2]= 1.0e10;
1389                 max[0]= max[1]= max[2]= -1.0e10;
1390         }
1391         
1392         base= FIRSTBASE;
1393         if(base==0) return;
1394         while(base) {
1395                 if(base->lay & G.vd->lay) {
1396                         onedone= 1;
1397                         minmax_object(base->object, min, max);
1398                 }
1399                 base= base->next;
1400         }
1401         if(!onedone) return;
1402         
1403         afm[0]= (max[0]-min[0]);
1404         afm[1]= (max[1]-min[1]);
1405         afm[2]= (max[2]-min[2]);
1406         size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1407         if(size==0.0) ok= 0;
1408                 
1409         if(ok) {
1410
1411                 G.vd->ofs[0]= -(min[0]+max[0])/2.0;
1412                 G.vd->ofs[1]= -(min[1]+max[1])/2.0;
1413                 G.vd->ofs[2]= -(min[2]+max[2])/2.0;
1414
1415                 G.vd->dist= size;
1416                 
1417                 // correction for window aspect ratio
1418                 if(curarea->winy>2 && curarea->winx>2) {
1419                         size= (float)curarea->winx/(float)curarea->winy;
1420                         if(size<1.0) size= 1.0/size;
1421                         G.vd->dist*= size;
1422                 }
1423                 
1424                 if(G.vd->persp==2) G.vd->persp= 1;
1425                 
1426                 scrarea_queue_winredraw(curarea);
1427         }
1428         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1429
1430 }
1431
1432
1433 void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3])
1434 {
1435         float alignaxis[3];
1436         float norm[3], axis[3], angle;
1437
1438         alignaxis[0]= alignaxis[1]= alignaxis[2]= 0.0;
1439         alignaxis[axisidx]= 1.0;
1440
1441         norm[0]= vec[0], norm[1]= vec[1], norm[2]= vec[2];
1442         Normalise(norm);
1443
1444         angle= acos(Inpf(alignaxis, norm));
1445         Crossf(axis, alignaxis, norm);
1446         VecRotToQuat(axis, -angle, v3d->viewquat);
1447
1448         v3d->view= 0;
1449         if (v3d->persp>=2) v3d->persp= 0; /* switch out of camera mode */
1450 }
1451