41d29c78a08f82d3785b8d8b99524484e42afff4
[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 #include "BLI_winstuff.h"
45 #else
46 #include <unistd.h>
47 #endif   
48
49 #include "MEM_guardedalloc.h"
50
51 #include "BLI_blenlib.h"
52 #include "BLI_arithb.h"
53
54 #include "DNA_object_types.h"
55 #include "DNA_screen_types.h"
56 #include "DNA_scene_types.h"
57 #include "DNA_space_types.h"
58 #include "DNA_view3d_types.h"
59 #include "DNA_camera_types.h"
60 #include "DNA_lamp_types.h"
61 #include "DNA_userdef_types.h"
62
63 #include "BKE_utildefines.h"
64 #include "BKE_object.h"
65 #include "BKE_global.h"
66 #include "BKE_main.h"
67
68 #include "BIF_gl.h"
69 #include "BIF_space.h"
70 #include "BIF_mywindow.h"
71 #include "BIF_screen.h"
72 #include "BIF_toolbox.h"
73
74 #include "BSE_view.h"
75 #include "BSE_edit.h"           /* For countall */
76 #include "BSE_drawview.h"       /* For inner_play_anim_loop */
77
78 #include "BDR_drawobject.h"     /* For draw_object */
79
80 #include "mydevice.h"
81 #include "blendef.h"
82
83 /* Modules used */
84 #include "render.h"             /* R. stuff for ogl view render */
85
86 #define TRACKBALLSIZE  (1.1)
87 #define BL_NEAR_CLIP 0.001
88
89 void persp_general(int a)
90 {
91         /* for all window types, not 3D */
92         
93         if(a== 0) {
94                 glPushMatrix();
95                 glMatrixMode(GL_PROJECTION);
96                 glPushMatrix();
97                 glMatrixMode(GL_MODELVIEW);
98
99                 myortho2(-0.375, ((float)(curarea->winx))-0.375, -0.375, ((float)(curarea->winy))-0.375);
100                 glLoadIdentity();
101         }
102         else if(a== 1) {
103                 glMatrixMode(GL_PROJECTION);
104                 glPopMatrix();
105                 glMatrixMode(GL_MODELVIEW);
106                 glPopMatrix();
107         }
108 }
109
110 void persp(int a)
111 {
112         /* only 3D windows */
113
114         if(curarea->spacetype!=SPACE_VIEW3D) persp_general(a);
115         else if(a == PERSP_STORE) {             // only store
116                 glMatrixMode(GL_PROJECTION);
117                 mygetmatrix(G.vd->winmat1);     
118                 glMatrixMode(GL_MODELVIEW);
119                 mygetmatrix(G.vd->viewmat1); 
120         }
121         else if(a== PERSP_WIN) {                // only set
122                 myortho2(-0.375, (float)(curarea->winx)-0.375, -0.375, (float)(curarea->winy)-0.375);
123                 glLoadIdentity();
124         }
125         else if(a== PERSP_VIEW) {
126                 glMatrixMode(GL_PROJECTION);
127                 myloadmatrix(G.vd->winmat1); // put back
128                 Mat4CpyMat4(curarea->winmat, G.vd->winmat1); // to be sure? 
129                 glMatrixMode(GL_MODELVIEW); 
130                 myloadmatrix(G.vd->viewmat); // put back
131                 
132         }
133 }
134
135
136 float zfac=1.0;
137
138 void initgrabz(float x, float y, float z)
139 {
140         if(G.vd==0) return;
141         zfac= G.vd->persmat[0][3]*x+ G.vd->persmat[1][3]*y+ G.vd->persmat[2][3]*z+ G.vd->persmat[3][3];
142 }
143
144 void window_to_3d(float *vec, short mx, short my)
145 {
146         /* always call initzgrab */
147         float dx, dy;
148         float fmx, fmy, winx, winy;
149         
150         /* stupid! */
151         winx= curarea->winx;
152         winy= curarea->winy;
153         fmx= mx;
154         fmy= my;
155         
156         dx= (2.0*fmx)/winx;
157         dx*= zfac;
158         dy= (2.0*fmy)/winy;
159         dy*= zfac;
160
161         vec[0]= (G.vd->persinv[0][0]*dx + G.vd->persinv[1][0]*dy);
162         vec[1]= (G.vd->persinv[0][1]*dx + G.vd->persinv[1][1]*dy);
163         vec[2]= (G.vd->persinv[0][2]*dx + G.vd->persinv[1][2]*dy);
164 }
165
166 void project_short(float *vec, short *adr)      /* clips */
167 {
168         float fx, fy, vec4[4];
169
170         adr[0]= 3200;
171         VECCOPY(vec4, vec);
172         vec4[3]= 1.0;
173         
174         Mat4MulVec4fl(G.vd->persmat, vec4);
175
176         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
177                 fx= (curarea->winx/2)+(curarea->winx/2)*vec4[0]/vec4[3];
178                 
179                 if( fx>0 && fx<curarea->winx) {
180                 
181                         fy= (curarea->winy/2)+(curarea->winy/2)*vec4[1]/vec4[3];
182                         
183                         if(fy>0.0 && fy< (float)curarea->winy) {
184                                 adr[0]= floor(fx); 
185                                 adr[1]= floor(fy);
186                         }
187                 }
188         }
189 }
190
191 void project_short_noclip(float *vec, short *adr)
192 {
193         float fx, fy, vec4[4];
194
195         adr[0]= 3200;
196         VECCOPY(vec4, vec);
197         vec4[3]= 1.0;
198         
199         Mat4MulVec4fl(G.vd->persmat, vec4);
200
201         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
202                 fx= (curarea->winx/2)+(curarea->winx/2)*vec4[0]/vec4[3];
203                 
204                 if( fx>-32700 && fx<32700) {
205                 
206                         fy= (curarea->winy/2)+(curarea->winy/2)*vec4[1]/vec4[3];
207                         
208                         if(fy>-32700.0 && fy<32700.0) {
209                                 adr[0]= floor(fx); 
210                                 adr[1]= floor(fy);
211                         }
212                 }
213         }
214 }
215
216 void project_float(float *vec, float *adr)
217 {
218         float vec4[4];
219         
220         adr[0]= 3200.0;
221         VECCOPY(vec4, vec);
222         vec4[3]= 1.0;
223         
224         Mat4MulVec4fl(G.vd->persmat, vec4);
225
226         if( vec4[3]>BL_NEAR_CLIP ) {
227                 adr[0]= (curarea->winx/2.0)+(curarea->winx/2.0)*vec4[0]/vec4[3];        
228                 adr[1]= (curarea->winy/2.0)+(curarea->winy/2.0)*vec4[1]/vec4[3];
229         }
230 }
231
232 int boundbox_clip(float obmat[][4], BoundBox *bb)
233 {
234         /* return 1: draw */
235         
236         float mat[4][4];
237         float vec[4], min, max;
238         int a, flag= -1, fl;
239         
240         if(bb==0) return 1;
241         
242         Mat4MulMat4(mat, obmat, G.vd->persmat);
243
244         for(a=0; a<8; a++) {
245                 VECCOPY(vec, bb->vec[a]);
246                 vec[3]= 1.0;
247                 Mat4MulVec4fl(mat, vec);
248                 max= vec[3];
249                 min= -vec[3];
250
251                 fl= 0;
252                 if(vec[0] < min) fl+= 1;
253                 if(vec[0] > max) fl+= 2;
254                 if(vec[1] < min) fl+= 4;
255                 if(vec[1] > max) fl+= 8;
256                 if(vec[2] < min) fl+= 16;
257                 if(vec[2] > max) fl+= 32;
258                 
259                 flag &= fl;
260                 if(flag==0) return 1;
261         }
262
263         return 0;
264
265 }
266
267 void fdrawline(float x1, float y1, float x2, float y2)
268 {
269         float v[2];
270
271         glBegin(GL_LINE_STRIP);
272         v[0] = x1; v[1] = y1;
273         glVertex2fv(v);
274         v[0] = x2; v[1] = y2;
275         glVertex2fv(v);
276         glEnd();
277 }
278
279 void fdrawbox(float x1, float y1, float x2, float y2)
280 {
281         float v[2];
282
283         glBegin(GL_LINE_STRIP);
284
285         v[0] = x1; v[1] = y1;
286         glVertex2fv(v);
287         v[0] = x1; v[1] = y2;
288         glVertex2fv(v);
289         v[0] = x2; v[1] = y2;
290         glVertex2fv(v);
291         v[0] = x2; v[1] = y1;
292         glVertex2fv(v);
293         v[0] = x1; v[1] = y1;
294         glVertex2fv(v);
295
296         glEnd();
297 }
298
299 void sdrawline(short x1, short y1, short x2, short y2)
300 {
301         short v[2];
302
303         glBegin(GL_LINE_STRIP);
304         v[0] = x1; v[1] = y1;
305         glVertex2sv(v);
306         v[0] = x2; v[1] = y2;
307         glVertex2sv(v);
308         glEnd();
309 }
310
311 void sdrawbox(short x1, short y1, short x2, short y2)
312 {
313         short v[2];
314
315         glBegin(GL_LINE_STRIP);
316
317         v[0] = x1; v[1] = y1;
318         glVertex2sv(v);
319         v[0] = x1; v[1] = y2;
320         glVertex2sv(v);
321         v[0] = x2; v[1] = y2;
322         glVertex2sv(v);
323         v[0] = x2; v[1] = y1;
324         glVertex2sv(v);
325         v[0] = x1; v[1] = y1;
326         glVertex2sv(v);
327
328         glEnd();
329 }
330
331 /* the central math in this function was copied from trackball.cpp, sample code from the 
332    Developers Toolbox series by SGI. */
333
334 /* trackball: better one than a full spherical solution */
335
336 void calctrackballvecfirst(rcti *area, short *mval, float *vec)
337 {
338         float x, y, radius, d, z, t;
339         
340         radius= TRACKBALLSIZE;
341         
342         /* normalise x and y */
343         x= (area->xmax + area->xmin)/2 -mval[0];
344         x/= (float)((area->xmax - area->xmin)/2);
345         y= (area->ymax + area->ymin)/2 -mval[1];
346         y/= (float)((area->ymax - area->ymin)/2);
347         
348         d = sqrt(x*x + y*y);
349         if (d < radius*M_SQRT1_2)       /* Inside sphere */
350                 z = sqrt(radius*radius - d*d);
351         else
352         {                       /* On hyperbola */
353                 t = radius / M_SQRT2;
354                 z = t*t / d;
355         }
356
357         vec[0]= x;
358         vec[1]= y;
359         vec[2]= -z;             /* yah yah! */
360
361         if( fabs(vec[2])>fabs(vec[1]) && fabs(vec[2])>fabs(vec[0]) ) {
362                 vec[0]= 0.0;
363                 vec[1]= 0.0;
364                 if(vec[2]>0.0) vec[2]= 1.0; else vec[2]= -1.0;
365         }
366         else if( fabs(vec[1])>fabs(vec[0]) && fabs(vec[1])>fabs(vec[2]) ) {
367                 vec[0]= 0.0;
368                 vec[2]= 0.0;
369                 if(vec[1]>0.0) vec[1]= 1.0; else vec[1]= -1.0;
370         }
371         else  {
372                 vec[1]= 0.0;
373                 vec[2]= 0.0;
374                 if(vec[0]>0.0) vec[0]= 1.0; else vec[0]= -1.0;
375         }
376 }
377
378 void calctrackballvec(rcti *area, short *mval, float *vec)
379 {
380         float x, y, radius, d, z, t;
381         
382         radius= TRACKBALLSIZE;
383         
384         /* x en y normaliseren */
385         x= (area->xmax + area->xmin)/2 -mval[0];
386         x/= (float)((area->xmax - area->xmin)/4);
387         y= (area->ymax + area->ymin)/2 -mval[1];
388         y/= (float)((area->ymax - area->ymin)/2);
389         
390         d = sqrt(x*x + y*y);
391         if (d < radius*M_SQRT1_2)       /* Inside sphere */
392                 z = sqrt(radius*radius - d*d);
393         else
394         {                       /* On hyperbola */
395                 t = radius / M_SQRT2;
396                 z = t*t / d;
397         }
398
399         vec[0]= x;
400         vec[1]= y;
401         vec[2]= -z;             /* yah yah! */
402
403 }
404
405 void viewmove(int mode)
406 {
407         float firstvec[3], newvec[3], dvec[3];
408         float oldquat[4], q1[4], si, phi, dist0;
409         int firsttime=1;
410         short mvalball[2], mval[2], mvalo[2];
411         
412         /* sometimes this routine is called from headerbuttons */
413         areawinset(curarea->win);
414         
415         initgrabz(-G.vd->ofs[0], -G.vd->ofs[1], -G.vd->ofs[2]);
416         
417         QUATCOPY(oldquat, G.vd->viewquat);
418         
419         getmouseco_sc(mvalo);           /* work with screen coordinates because of trackball function */
420         mvalball[0]= mvalo[0];                  /* needed for turntable to work */
421         mvalball[1]= mvalo[1];
422         dist0= G.vd->dist;
423         
424         calctrackballvec(&curarea->winrct, mvalo, firstvec);
425
426         /* cumultime(0); */
427
428         while(TRUE) {
429                 getmouseco_sc(mval);
430                 
431                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || (G.f & G_PLAYANIM)) {
432                         
433                         if(firsttime) {
434                                 
435                                 firsttime= 0;
436                                 /* are we translating, rotating or zooming? */
437                                 if(mode==0) {
438                                         if(G.vd->view!=0) scrarea_queue_headredraw(curarea);    /*for button */
439                                         G.vd->view= 0;
440                                 }
441                                                 
442                                 if(G.vd->persp==2 || (G.vd->persp==3 && mode!=1)) {
443                                         G.vd->persp= 1;
444                                         scrarea_do_windraw(curarea);
445                                         scrarea_queue_headredraw(curarea);
446                                 }
447                         }
448
449
450                         if(mode==0) {   /* view rotate */
451
452                                 if (U.uiflag & USER_AUTOPERSP) G.vd->persp= 1;
453
454                                 if (U.flag & USER_TRACKBALL) mvalball[0]= mval[0];
455                                 mvalball[1]= mval[1];
456                                 
457                                 calctrackballvec(&curarea->winrct, mvalball, newvec);
458                                 
459                                 VecSubf(dvec, newvec, firstvec);
460                                 
461                                 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
462                                 si/= (2.0*TRACKBALLSIZE);
463                         
464                                 if (U.flag & USER_TRACKBALL) {
465                                         Crossf(q1+1, firstvec, newvec);
466         
467                                         Normalise(q1+1);
468         
469                                         /* Allow for rotation beyond the interval
470                                          * [-pi, pi] */
471                                         while (si > 1.0)
472                                                 si -= 2.0;
473                 
474                                         /* This relation is used instead of
475                                          * phi = asin(si) so that the angle
476                                          * of rotation is linearly proportional
477                                          * to the distance that the mouse is
478                                          * dragged. */
479                                         phi = si * M_PI / 2.0;
480                 
481                                         si= sin(phi);
482                                         q1[0]= cos(phi);
483                                         q1[1]*= si;
484                                         q1[2]*= si;
485                                         q1[3]*= si;                                             
486                                         QuatMul(G.vd->viewquat, q1, oldquat);
487                                 } else {
488                                         /* is there an acceptable solution? (180 degrees limitor) */
489                                         if(si<1.0) {
490                                                 Crossf(q1+1, firstvec, newvec);
491         
492                                                 Normalise(q1+1);
493                         
494                                                 phi= asin(si);
495                 
496                                                 si= sin(phi);
497                                                 q1[0]= cos(phi);
498                                                 q1[1]*= si;
499                                                 q1[2]*= si;
500                                                 q1[3]*= si;
501                                                 
502                                                 QuatMul(G.vd->viewquat, q1, oldquat);
503         
504                                                 /* rotate around z-axis (mouse x moves)  */
505                                                 
506                                                 phi= 2*(mval[0]-mvalball[0]);
507                                                 phi/= (float)curarea->winx;
508                                                 si= sin(phi);
509                                                 q1[0]= cos(phi);
510                                                 q1[1]= q1[2]= 0.0;
511                                                 q1[3]= si;
512                                         
513                                                 QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
514                                         }
515                                 }
516                         }
517                         else if(mode==1) {      /* translate */
518                                 if(G.vd->persp==3) {
519                                         /* zoom= 0.5+0.5*(float)(2<<G.vd->rt1); */
520                                         /* dx-= (mval[0]-mvalo[0])/zoom; */
521                                         /* dy-= (mval[1]-mvalo[1])/zoom; */
522                                         /* G.vd->rt2= dx; */
523                                         /* G.vd->rt3= dy; */
524                                         /* if(G.vd->rt2<-320) G.vd->rt2= -320; */
525                                         /* if(G.vd->rt2> 320) G.vd->rt2=  320; */
526                                         /* if(G.vd->rt3<-250) G.vd->rt3= -250; */
527                                         /* if(G.vd->rt3> 250) G.vd->rt3=  250; */
528                                 }
529                                 else {
530                                         window_to_3d(dvec, mval[0]-mvalo[0], mval[1]-mvalo[1]);
531                                         VecAddf(G.vd->ofs, G.vd->ofs, dvec);
532                                 }
533                         }
534                         else if(mode==2) {
535                                 if(U.viewzoom==USER_ZOOM_CONT) {
536                                         // oldstyle zoom
537                                         G.vd->dist*= 1.0+(float)(mvalo[0]-mval[0]+mvalo[1]-mval[1])/1000.0;
538                                 }
539                                 else if(U.viewzoom==USER_ZOOM_SCALE) {
540                                         int ctr[2], len1, len2;
541                                         // method which zooms based on how far you move the mouse
542                                         
543                                         ctr[0] = (curarea->winrct.xmax + curarea->winrct.xmin)/2;
544                                         ctr[1] = (curarea->winrct.ymax + curarea->winrct.ymin)/2;
545                                         
546                                         len1 = (int)sqrt((ctr[0] - mval[0])*(ctr[0] - mval[0]) + (ctr[1] - mval[1])*(ctr[1] - mval[1])) + 5;
547                                         len2 = (int)sqrt((ctr[0] - mvalo[0])*(ctr[0] - mvalo[0]) + (ctr[1] - mvalo[1])*(ctr[1] - mvalo[1])) + 5;
548                                         
549                                         G.vd->dist= dist0 * ((float)len2/len1);
550                                 }
551                                 else {  /* USER_ZOOM_DOLLY */
552                                         float len1 = (curarea->winrct.ymax - mval[1]) + 5;
553                                         float len2 = (curarea->winrct.ymax - mvalo[1]) + 5;
554                                         
555                                         G.vd->dist= dist0 * (2.0*((len2/len1)-1.0) + 1.0);
556                                 }
557                                 
558                                 /* these limits are in toets.c too */
559                                 if(G.vd->dist<0.001*G.vd->grid) G.vd->dist= 0.001*G.vd->grid;
560                                 if(G.vd->dist>10.0*G.vd->far) G.vd->dist=10.0*G.vd->far;
561                                 
562                                 mval[1]= mvalo[1]; /* preserve first value */
563                                 mval[0]= mvalo[0];
564                         }
565                         
566                         mvalo[0]= mval[0];
567                         mvalo[1]= mval[1];
568
569                         if(G.f & G_PLAYANIM) inner_play_anim_loop(0, 0);
570                         if(G.f & G_SIMULATION) break;
571
572                         scrarea_do_windraw(curarea);
573                         screen_swapbuffers();
574                 }
575                 else {
576                         BIF_wait_for_statechange();
577                 }
578                 
579                 /* this in the end, otherwise get_mbut does not work on a PC... */
580                 if( !(get_mbut() & (L_MOUSE|M_MOUSE))) break;
581         }
582 }
583
584 short v3d_windowmode=0;
585
586 /* important to not set windows active in here, can be renderwin for example */
587 void setwinmatrixview3d(rctf *rect)             /* rect: for picking */
588 {
589         Camera *cam=0;
590         float near, far, winx = 0.0, winy = 0.0;
591         float lens, fac, x1, y1, x2, y2;
592         short orth;
593         
594         lens= G.vd->lens;       
595         
596         near= G.vd->near;
597         far= G.vd->far;
598
599         if(G.vd->persp==2) {
600                 near= G.vd->near;
601                 far= G.vd->far;
602                 if(G.vd->camera) {
603                         if(G.vd->camera->type==OB_LAMP ) {
604                                 Lamp *la;
605                                 
606                                 la= G.vd->camera->data;
607                                 fac= cos( M_PI*la->spotsize/360.0);
608                                 
609                                 x1= saacos(fac);
610                                 lens= 16.0*fac/sin(x1);
611                 
612                                 near= la->clipsta;
613                                 far= la->clipend;
614                         }
615                         else if(G.vd->camera->type==OB_CAMERA) {
616                                 cam= G.vd->camera->data;
617                                 lens= cam->lens;
618                                 near= cam->clipsta;
619                                 far= cam->clipend;
620                         }
621                 }
622         }
623         
624         if(v3d_windowmode) { // hackish
625                 winx= R.rectx;
626                 winy= R.recty;
627         }
628         else {
629                 winx= curarea->winx;
630                 winy= curarea->winy;
631         }
632         
633         if(G.vd->persp==0) {
634                 if(winx>winy) x1= -G.vd->dist;
635                 else x1= -winx*G.vd->dist/winy;
636                 x2= -x1;
637
638                 if(winx>winy) y1= -winy*G.vd->dist/winx;
639                 else y1= -G.vd->dist;
640                 y2= -y1;
641                 
642                 near= -far;
643                 orth= 1;
644         }
645         else {
646                 if(G.vd->persp==2) {
647                         fac= (1.41421+( (float)G.vd->camzoom )/50.0);
648                         fac*= fac;
649                 }
650                 else fac= 2.0;
651                 
652                 /* viewplane size depends... */
653                 if(cam && cam->type==CAM_ORTHO) {
654                         /* ortho_scale == 1 means exact 1 to 1 mapping */
655                         float dfac= 2.0*cam->ortho_scale/fac;
656                         
657                         if(winx>winy) x1= -dfac;
658                         else x1= -winx*dfac/winy;
659                         x2= -x1;
660                         
661                         if(winx>winy) y1= -winy*dfac/winx;
662                         else y1= -dfac;
663                         y2= -y1;
664                         orth= 1;
665                 }
666                 else {
667                         float dfac;
668                         
669                         if(winx>winy) dfac= 64.0/(fac*winx*lens);
670                         else dfac= 64.0/(fac*winy*lens);
671                         
672                         x1= - near*winx*dfac;
673                         x2= -x1;
674                         y1= - near*winy*dfac;
675                         y2= -y1;
676                         orth= 0;
677                 }
678         }
679
680         if(rect) {              /* picking */
681                 rect->xmin/= winx;
682                 rect->xmin= x1+rect->xmin*(x2-x1);
683                 rect->ymin/= winy;
684                 rect->ymin= y1+rect->ymin*(y2-y1);
685                 rect->xmax/= winx;
686                 rect->xmax= x1+rect->xmax*(x2-x1);
687                 rect->ymax/= winy;
688                 rect->ymax= y1+rect->ymax*(y2-y1);
689
690                 if(orth) myortho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -far, far);
691                 else mywindow(rect->xmin, rect->xmax, rect->ymin, rect->ymax, near, far);
692
693         }
694         else {
695                 if(v3d_windowmode) {
696                         if(orth) i_ortho(x1, x2, y1, y2, near, far, R.winmat);
697                         else i_window(x1, x2, y1, y2, near, far, R.winmat);
698                 }
699                 else {
700                         if(orth) myortho(x1, x2, y1, y2, near, far);
701                         else mywindow(x1, x2, y1, y2, near, far);
702                 }
703         }
704
705         if(v3d_windowmode==0) {
706                 glMatrixMode(GL_PROJECTION);
707                 mygetmatrix(curarea->winmat);
708                 glMatrixMode(GL_MODELVIEW);
709         }
710 }
711
712
713 void obmat_to_viewmat(Object *ob)
714 {
715         float bmat[4][4];
716         float tmat[3][3];
717
718         Mat4CpyMat4(bmat, ob->obmat);
719         Mat4Ortho(bmat);
720         Mat4Invert(G.vd->viewmat, bmat);
721         
722         /* view quat calculation, needed for add object */
723         Mat3CpyMat4(tmat, G.vd->viewmat);
724         Mat3ToQuat(tmat, G.vd->viewquat);
725 }
726
727 /* dont set windows active in in here, is used by renderwin too */
728 void setviewmatrixview3d()
729 {
730         Camera *cam;
731
732         if(G.vd->persp>=2) {        /* obs/camera */
733                 if(G.vd->camera) {
734                         
735                         where_is_object(G.vd->camera);  
736                         obmat_to_viewmat(G.vd->camera);
737                         
738                         if(G.vd->camera->type==OB_CAMERA) {
739                                 cam= G.vd->camera->data;
740                                 //if(cam->type==CAM_ORTHO) G.vd->viewmat[3][2]*= 100.0;
741                         }
742                 }
743                 else {
744                         QuatToMat4(G.vd->viewquat, G.vd->viewmat);
745                         G.vd->viewmat[3][2]-= G.vd->dist;
746                 }
747         }
748         else {
749                 
750                 QuatToMat4(G.vd->viewquat, G.vd->viewmat);
751                 if(G.vd->persp==1) G.vd->viewmat[3][2]-= G.vd->dist;
752                 i_translate(G.vd->ofs[0], G.vd->ofs[1], G.vd->ofs[2], G.vd->viewmat);
753         }
754 }
755
756 void setcameratoview3d()
757 {
758         Object *ob;
759         float dvec[3];
760
761         ob= G.vd->camera;
762         dvec[0]= G.vd->dist*G.vd->viewinv[2][0];
763         dvec[1]= G.vd->dist*G.vd->viewinv[2][1];
764         dvec[2]= G.vd->dist*G.vd->viewinv[2][2];                                        
765         VECCOPY(ob->loc, dvec);
766         VecSubf(ob->loc, ob->loc, G.vd->ofs);
767         G.vd->viewquat[0]= -G.vd->viewquat[0];
768         if (ob->transflag & OB_QUAT) {
769                 QUATCOPY(ob->quat, G.vd->viewquat);
770         } else {
771                 QuatToEul(G.vd->viewquat, ob->rot);
772         }
773         G.vd->viewquat[0]= -G.vd->viewquat[0];
774 }
775
776 /* IGLuint-> GLuint*/
777 short selectprojektie(unsigned int *buffer, short x1, short y1, short x2, short y2)
778 {
779         rctf rect;
780         Base *base;
781         short mval[2], code, hits;
782
783         G.f |= G_PICKSEL;
784         
785         if(x1==0 && x2==0 && y1==0 && y2==0) {
786                 getmouseco_areawin(mval);
787                 rect.xmin= mval[0]-12;  // seems to be default value for bones only now
788                 rect.xmax= mval[0]+12;
789                 rect.ymin= mval[1]-12;
790                 rect.ymax= mval[1]+12;
791         }
792         else {
793                 rect.xmin= x1;
794                 rect.xmax= x2;
795                 rect.ymin= y1;
796                 rect.ymax= y2;
797         }
798         /* get rid of overlay button matrix */
799         persp(PERSP_VIEW);
800         setwinmatrixview3d(&rect);
801         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
802         
803         if(G.vd->drawtype > OB_WIRE) {
804                 G.zbuf= TRUE;
805                 glEnable(GL_DEPTH_TEST);
806         }
807
808         glSelectBuffer( MAXPICKBUF, (GLuint *)buffer);
809         glRenderMode(GL_SELECT);
810         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
811         glPushName(-1);
812         code= 1;
813         
814         if(G.obedit && G.obedit->type==OB_MBALL) {
815                 draw_object(BASACT);
816         }
817         else if ((G.obedit && G.obedit->type==OB_ARMATURE)||(G.obpose && G.obpose->type==OB_ARMATURE)) {
818                 draw_object(BASACT);
819         }
820         else {
821                 base= G.scene->base.first;
822                 while(base) {
823                         if(base->lay & G.vd->lay) {
824                                 base->selcol= code;
825                                 glLoadName(code);
826                                 draw_object(base);
827                                 code++;
828                         }
829                         base= base->next;
830                 }
831         }
832         glPopName();    /* see above (pushname) */
833         hits= glRenderMode(GL_RENDER);
834         if(hits<0) error("Too many objects in select buffer");
835
836         G.f &= ~G_PICKSEL;
837         setwinmatrixview3d(0);
838         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
839         
840         if(G.vd->drawtype > OB_WIRE) {
841                 G.zbuf= 0;
842                 glDisable(GL_DEPTH_TEST);
843         }
844         persp(PERSP_WIN);
845
846         return hits;
847 }
848
849 float *give_cursor()
850 {
851         if(G.vd && G.vd->localview) return G.vd->cursor;
852         else return G.scene->cursor;
853 }
854
855 unsigned int free_localbit()
856 {
857         unsigned int lay;
858         ScrArea *sa;
859         bScreen *sc;
860         
861         lay= 0;
862         
863         /* sometimes we loose a localview: when an area is closed */
864         /* check all areas: which localviews are in use? */
865         sc= G.main->screen.first;
866         while(sc) {
867                 sa= sc->areabase.first;
868                 while(sa) {
869                         SpaceLink *sl= sa->spacedata.first;
870                         while(sl) {
871                                 if(sl->spacetype==SPACE_VIEW3D) {
872                                         View3D *v3d= (View3D*) sl;
873                                         lay |= v3d->lay;
874                                 }
875                                 sl= sl->next;
876                         }
877                         sa= sa->next;
878                 }
879                 sc= sc->id.next;
880         }
881         
882         if( (lay & 0x01000000)==0) return 0x01000000;
883         if( (lay & 0x02000000)==0) return 0x02000000;
884         if( (lay & 0x04000000)==0) return 0x04000000;
885         if( (lay & 0x08000000)==0) return 0x08000000;
886         if( (lay & 0x10000000)==0) return 0x10000000;
887         if( (lay & 0x20000000)==0) return 0x20000000;
888         if( (lay & 0x40000000)==0) return 0x40000000;
889         if( (lay & 0x80000000)==0) return 0x80000000;
890         
891         return 0;
892 }
893
894
895 void initlocalview()
896 {
897         Base *base;
898         float size = 0.0, min[3], max[3], afm[3];
899         unsigned int locallay;
900         int ok=0;
901
902         if(G.vd->localvd) return;
903
904         min[0]= min[1]= min[2]= 1.0e10;
905         max[0]= max[1]= max[2]= -1.0e10;
906
907         locallay= free_localbit();
908
909         if(locallay==0) {
910                 error("Sorry,  no more than 8 localviews");
911                 ok= 0;
912         }
913         else {
914                 if(G.obedit) {
915                         minmax_object(G.obedit, min, max);
916                         
917                         ok= 1;
918                 
919                         BASACT->lay |= locallay;
920                         G.obedit->lay= BASACT->lay;
921                 }
922                 else {
923                         base= FIRSTBASE;
924                         while(base) {
925                                 if TESTBASE(base)  {
926                                         minmax_object(base->object, min, max);
927                                         base->lay |= locallay;
928                                         base->object->lay= base->lay;
929                                         ok= 1;
930                                 }
931                                 base= base->next;
932                         }
933                 }
934                 
935                 afm[0]= (max[0]-min[0]);
936                 afm[1]= (max[1]-min[1]);
937                 afm[2]= (max[2]-min[2]);
938                 size= 0.7*MAX3(afm[0], afm[1], afm[2]);
939                 if(size<=0.01) size= 0.01;
940         }
941         
942         if(ok) {
943                 G.vd->localvd= MEM_mallocN(sizeof(View3D), "localview");
944                 memcpy(G.vd->localvd, G.vd, sizeof(View3D));
945
946                 G.vd->ofs[0]= -(min[0]+max[0])/2.0;
947                 G.vd->ofs[1]= -(min[1]+max[1])/2.0;
948                 G.vd->ofs[2]= -(min[2]+max[2])/2.0;
949
950                 G.vd->dist= size;
951
952                 // correction for window aspect ratio
953                 if(curarea->winy>2 && curarea->winx>2) {
954                         size= (float)curarea->winx/(float)curarea->winy;
955                         if(size<1.0) size= 1.0/size;
956                         G.vd->dist*= size;
957                 }
958                 
959                 if(G.vd->persp>1) {
960                         G.vd->persp= 1;
961                         
962                 }
963                 G.vd->near= 0.1;
964                 G.vd->cursor[0]= -G.vd->ofs[0];
965                 G.vd->cursor[1]= -G.vd->ofs[1];
966                 G.vd->cursor[2]= -G.vd->ofs[2];
967
968                 G.vd->lay= locallay;
969                 
970                 countall();
971                 scrarea_queue_winredraw(curarea);
972         }
973         else {
974                 /* clear flags */
975                 base= FIRSTBASE;
976                 while(base) {
977                         if( base->lay & locallay ) {
978                                 base->lay-= locallay;
979                                 if(base->lay==0) base->lay= G.vd->layact;
980                                 if(base->object != G.obedit) base->flag |= SELECT;
981                                 base->object->lay= base->lay;
982                         }
983                         base= base->next;
984                 }
985                 scrarea_queue_headredraw(curarea);
986                 
987                 G.vd->localview= 0;
988         }
989 }
990
991 void centreview()       /* like a localview without local! */
992 {
993         Base *base;
994         float size, min[3], max[3], afm[3];
995         int ok=0;
996
997         min[0]= min[1]= min[2]= 1.0e10;
998         max[0]= max[1]= max[2]= -1.0e10;
999
1000         if(G.obedit) {
1001                 minmax_verts(min, max);
1002                 //minmax_object(G.obedit, min, max);
1003                 
1004                 ok= 1;
1005         }
1006         else {
1007                 base= FIRSTBASE;
1008                 while(base) {
1009                         if TESTBASE(base)  {
1010                                 minmax_object(base->object, min, max);
1011                                 ok= 1;
1012                         }
1013                         base= base->next;
1014                 }
1015         }
1016         
1017         if(ok==0) return;
1018         
1019         afm[0]= (max[0]-min[0]);
1020         afm[1]= (max[1]-min[1]);
1021         afm[2]= (max[2]-min[2]);
1022         size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1023         
1024         if(size<=0.01) size= 0.01;
1025         
1026         G.vd->ofs[0]= -(min[0]+max[0])/2.0;
1027         G.vd->ofs[1]= -(min[1]+max[1])/2.0;
1028         G.vd->ofs[2]= -(min[2]+max[2])/2.0;
1029
1030         G.vd->dist= size;
1031
1032         // correction for window aspect ratio
1033         if(curarea->winy>2 && curarea->winx>2) {
1034                 size= (float)curarea->winx/(float)curarea->winy;
1035                 if(size<1.0) size= 1.0/size;
1036                 G.vd->dist*= size;
1037         }
1038         
1039         if(G.vd->persp>1) {
1040                 G.vd->persp= 1;
1041         }
1042
1043         G.vd->cursor[0]= -G.vd->ofs[0];
1044         G.vd->cursor[1]= -G.vd->ofs[1];
1045         G.vd->cursor[2]= -G.vd->ofs[2];
1046
1047         scrarea_queue_winredraw(curarea);
1048
1049 }
1050
1051
1052 void restore_localviewdata(View3D *vd)
1053 {
1054         if(vd->localvd==0) return;
1055         
1056         VECCOPY(vd->ofs, vd->localvd->ofs);
1057         vd->dist= vd->localvd->dist;
1058         vd->persp= vd->localvd->persp;
1059         vd->view= vd->localvd->view;
1060         vd->near= vd->localvd->near;
1061         vd->far= vd->localvd->far;
1062         vd->lay= vd->localvd->lay;
1063         vd->layact= vd->localvd->layact;
1064         vd->drawtype= vd->localvd->drawtype;
1065         vd->camera= vd->localvd->camera;
1066         QUATCOPY(vd->viewquat, vd->localvd->viewquat);
1067         
1068 }
1069
1070 void endlocalview(ScrArea *sa)
1071 {
1072         View3D *v3d;
1073         struct Base *base;
1074         unsigned int locallay;
1075         
1076         if(sa->spacetype!=SPACE_VIEW3D) return;
1077         v3d= sa->spacedata.first;
1078         
1079         if(v3d->localvd) {
1080                 
1081                 locallay= v3d->lay & 0xFF000000;
1082                 
1083                 restore_localviewdata(v3d);
1084                 
1085                 MEM_freeN(v3d->localvd);
1086                 v3d->localvd= 0;
1087                 v3d->localview= 0;
1088
1089                 /* for when in other window the layers have changed */
1090                 if(v3d->scenelock) v3d->lay= G.scene->lay;
1091                 
1092                 base= FIRSTBASE;
1093                 while(base) {
1094                         if( base->lay & locallay ) {
1095                                 base->lay-= locallay;
1096                                 if(base->lay==0) base->lay= v3d->layact;
1097                                 if(base->object != G.obedit) base->flag |= SELECT;
1098                                 base->object->lay= base->lay;
1099                         }
1100                         base= base->next;
1101                 }
1102
1103                 countall();
1104                 allqueue(REDRAWVIEW3D, 0);      /* because of select */
1105                 
1106         }
1107 }
1108
1109 void view3d_home(int centre)
1110 {
1111         Base *base;
1112         float size, min[3], max[3], afm[3];
1113         int ok= 1, onedone=0;
1114
1115         if(centre) {
1116                 min[0]= min[1]= min[2]= 0.0;
1117                 max[0]= max[1]= max[2]= 0.0;
1118         }
1119         else {
1120                 min[0]= min[1]= min[2]= 1.0e10;
1121                 max[0]= max[1]= max[2]= -1.0e10;
1122         }
1123         
1124         base= FIRSTBASE;
1125         if(base==0) return;
1126         while(base) {
1127                 if(base->lay & G.vd->lay) {
1128                         onedone= 1;
1129                         minmax_object(base->object, min, max);
1130                 }
1131                 base= base->next;
1132         }
1133         if(!onedone) return;
1134         
1135         afm[0]= (max[0]-min[0]);
1136         afm[1]= (max[1]-min[1]);
1137         afm[2]= (max[2]-min[2]);
1138         size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1139         if(size==0.0) ok= 0;
1140                 
1141         if(ok) {
1142
1143                 G.vd->ofs[0]= -(min[0]+max[0])/2.0;
1144                 G.vd->ofs[1]= -(min[1]+max[1])/2.0;
1145                 G.vd->ofs[2]= -(min[2]+max[2])/2.0;
1146
1147                 G.vd->dist= size;
1148                 
1149                 // correction for window aspect ratio
1150                 if(curarea->winy>2 && curarea->winx>2) {
1151                         size= (float)curarea->winx/(float)curarea->winy;
1152                         if(size<1.0) size= 1.0/size;
1153                         G.vd->dist*= size;
1154                 }
1155                 
1156                 if(G.vd->persp==2) G.vd->persp= 1;
1157                 
1158                 scrarea_queue_winredraw(curarea);
1159         }
1160 }
1161
1162
1163 void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3])
1164 {
1165         float alignaxis[3];
1166         float norm[3], axis[3], angle;
1167
1168         alignaxis[0]= alignaxis[1]= alignaxis[2]= 0.0;
1169         alignaxis[axisidx]= 1.0;
1170
1171         norm[0]= vec[0], norm[1]= vec[1], norm[2]= vec[2];
1172         Normalise(norm);
1173
1174         angle= acos(Inpf(alignaxis, norm));
1175         Crossf(axis, alignaxis, norm);
1176         VecRotToQuat(axis, -angle, v3d->viewquat);
1177
1178         v3d->view= 0;
1179         if (v3d->persp>=2) v3d->persp= 0; /* switch out of camera mode */
1180 }
1181