Commit for the 4 aforementioned "features":
[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"
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+0.5); 
185                                 adr[1]= floor(fy+0.5);
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+0.5); 
210                                 adr[1]= floor(fy+0.5);
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         curarea->head_swap= 0;
415         
416         initgrabz(-G.vd->ofs[0], -G.vd->ofs[1], -G.vd->ofs[2]);
417         
418         QUATCOPY(oldquat, G.vd->viewquat);
419         
420         getmouseco_sc(mvalo);           /* work with screen coordinates because of trackball function */
421         mvalball[0]= mvalo[0];                  /* needed for turntable to work */
422         mvalball[1]= mvalo[1];
423         dist0= G.vd->dist;
424         
425         calctrackballvec(&curarea->winrct, mvalo, firstvec);
426
427         /* cumultime(0); */
428
429         while(TRUE) {
430                 getmouseco_sc(mval);
431                 
432                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || (G.f & G_PLAYANIM)) {
433                         
434                         if(firsttime) {
435                                 
436                                 firsttime= 0;
437                                 /* are we translating, rotating or zooming? */
438                                 if(mode==0) {
439                                         if(G.vd->view!=0) scrarea_queue_headredraw(curarea);    /*for button */
440                                         G.vd->view= 0;
441                                 }
442                                                 
443                                 if(G.vd->persp==2 || (G.vd->persp==3 && mode!=1)) {
444                                         G.vd->persp= 1;
445                                         scrarea_do_windraw(curarea);
446                                         scrarea_queue_headredraw(curarea);
447                                 }
448                         }
449
450
451                         if(mode==0) {   /* view rotate */
452
453                                 if (U.uiflag & USER_AUTOPERSP) G.vd->persp= 1;
454                         
455                                 /* if turntable method, we don't change mvalball[0] */
456                         
457                                 if(U.flag & USER_TRACKBALL) mvalball[0]= mval[0];
458                                 mvalball[1]= mval[1];
459                                 
460                                 calctrackballvec(&curarea->winrct, mvalball, newvec);
461                                 
462                                 VecSubf(dvec, newvec, firstvec);
463                                 
464                                 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
465                                 si/= (2.0*TRACKBALLSIZE);
466                                 
467                                 /* is there an acceptable solution? (180 degrees limitor) */
468                                 if(si<1.0) {
469                                         Crossf(q1+1, firstvec, newvec);
470
471                                         Normalise(q1+1);
472                 
473                                         phi= asin(si);
474         
475                                         si= sin(phi);
476                                         q1[0]= cos(phi);
477                                         q1[1]*= si;
478                                         q1[2]*= si;
479                                         q1[3]*= si;
480                                         
481                                         QuatMul(G.vd->viewquat, q1, oldquat);
482
483                                         if( (U.flag & USER_TRACKBALL)==0 ) {
484                                         
485                                                 /* rotate around z-axis (mouse x moves)  */
486                                                 
487                                                 phi= 2*(mval[0]-mvalball[0]);
488                                                 phi/= (float)curarea->winx;
489                                                 si= sin(phi);
490                                                 q1[0]= cos(phi);
491                                                 q1[1]= q1[2]= 0.0;
492                                                 q1[3]= si;
493                                                 
494                                                 QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
495                                         }
496                                 }
497                         }
498                         else if(mode==1) {      /* translate */
499                                 if(G.vd->persp==3) {
500                                         /* zoom= 0.5+0.5*(float)(2<<G.vd->rt1); */
501                                         /* dx-= (mval[0]-mvalo[0])/zoom; */
502                                         /* dy-= (mval[1]-mvalo[1])/zoom; */
503                                         /* G.vd->rt2= dx; */
504                                         /* G.vd->rt3= dy; */
505                                         /* if(G.vd->rt2<-320) G.vd->rt2= -320; */
506                                         /* if(G.vd->rt2> 320) G.vd->rt2=  320; */
507                                         /* if(G.vd->rt3<-250) G.vd->rt3= -250; */
508                                         /* if(G.vd->rt3> 250) G.vd->rt3=  250; */
509                                 }
510                                 else {
511                                         window_to_3d(dvec, mval[0]-mvalo[0], mval[1]-mvalo[1]);
512                                         VecAddf(G.vd->ofs, G.vd->ofs, dvec);
513                                 }
514                         }
515                         else if(mode==2) {
516                                 if(U.viewzoom==USER_ZOOM_CONT) {
517                                         // oldstyle zoom
518                                         G.vd->dist*= 1.0+(float)(mvalo[0]-mval[0]+mvalo[1]-mval[1])/1000.0;
519                                 }
520                                 else if(U.viewzoom==USER_ZOOM_SCALE) {
521                                         int ctr[2], len1, len2;
522                                         // method which zooms based on how far you move the mouse
523                                         
524                                         ctr[0] = (curarea->winrct.xmax + curarea->winrct.xmin)/2;
525                                         ctr[1] = (curarea->winrct.ymax + curarea->winrct.ymin)/2;
526                                         
527                                         len1 = (int)sqrt((ctr[0] - mval[0])*(ctr[0] - mval[0]) + (ctr[1] - mval[1])*(ctr[1] - mval[1])) + 5;
528                                         len2 = (int)sqrt((ctr[0] - mvalo[0])*(ctr[0] - mvalo[0]) + (ctr[1] - mvalo[1])*(ctr[1] - mvalo[1])) + 5;
529                                         
530                                         G.vd->dist= dist0 * ((float)len2/len1);
531                                 }
532                                 else {  /* USER_ZOOM_DOLLY */
533                                         float len1 = (curarea->winrct.ymax - mval[1]) + 5;
534                                         float len2 = (curarea->winrct.ymax - mvalo[1]) + 5;
535                                         
536                                         G.vd->dist= dist0 * (2.0*((len2/len1)-1.0) + 1.0);
537                                 }
538                                 
539                                 /* these limits are in toets.c too */
540                                 if(G.vd->dist<0.001*G.vd->grid) G.vd->dist= 0.001*G.vd->grid;
541                                 if(G.vd->dist>10.0*G.vd->far) G.vd->dist=10.0*G.vd->far;
542                                 
543                                 mval[1]= mvalo[1]; /* preserve first value */
544                                 mval[0]= mvalo[0];
545                         }
546                         
547                         mvalo[0]= mval[0];
548                         mvalo[1]= mval[1];
549
550                         if(G.f & G_PLAYANIM) inner_play_anim_loop(0, 0);
551                         if(G.f & G_SIMULATION) break;
552
553                         scrarea_do_windraw(curarea);
554                         screen_swapbuffers();
555                 }
556                 else {
557                         BIF_wait_for_statechange();
558                 }
559                 
560                 /* this in the end, otherwise get_mbut does not work on a PC... */
561                 if( !(get_mbut() & (L_MOUSE|M_MOUSE))) break;
562         }
563
564         curarea->head_swap= WIN_FRONT_OK;
565 }
566
567 short v3d_windowmode=0;
568
569 void setwinmatrixview3d(rctf *rect)             /* rect: for picking */
570 {
571         Camera *cam=0;
572         float d, near, far, winx = 0.0, winy = 0.0;
573         float lens, dfac, fac, x1, y1, x2, y2;
574         short orth;
575         
576         lens= G.vd->lens;       
577         
578         near= G.vd->near;
579         far= G.vd->far;
580
581         if(G.vd->persp==2) {
582                 near= G.vd->near;
583                 far= G.vd->far;
584                 if(G.vd->camera) {
585                         if(G.vd->camera->type==OB_LAMP ) {
586                                 Lamp *la;
587                                 
588                                 la= G.vd->camera->data;
589                                 fac= cos( M_PI*la->spotsize/360.0);
590                                 
591                                 x1= saacos(fac);
592                                 lens= 16.0*fac/sin(x1);
593                 
594                                 near= la->clipsta;
595                                 far= la->clipend;
596                         }
597                         else if(G.vd->camera->type==OB_CAMERA) {
598                                 cam= G.vd->camera->data;
599                                 lens= cam->lens;
600                                 near= cam->clipsta;
601                                 far= cam->clipend;
602                                 
603                                 if(cam->type==CAM_ORTHO) {
604                                         lens*= 100.0;
605                                         near= (near+1.0)*100.0; /* otherwise zbuffer troubles. a Patch! */
606                                         far*= 100.0;
607                                 }
608                         }
609                 }
610         }
611         
612         if(v3d_windowmode) {
613                 winx= R.rectx;
614                 winy= R.recty;
615         }
616         else {
617                 winx= curarea->winx;
618                 winy= curarea->winy;
619         }
620         
621         if(winx>winy) d= 0.015625*winx*lens;
622         else d= 0.015625*winy*lens;
623         
624         dfac= near/d;
625
626         if(G.vd->persp==0) {
627                 if(winx>winy) x1= -G.vd->dist;
628                 else x1= -winx*G.vd->dist/winy;
629                 
630                 x2= -x1;
631
632                 if(winx>winy) y1= -winy*G.vd->dist/winx;
633                 else y1= -G.vd->dist;
634                 
635                 y2= -y1;
636                 orth= 1;
637         }
638         else {
639                 if(G.vd->persp==2) {
640                         fac= (1.41421+( (float)G.vd->camzoom )/50.0);
641                         fac*= fac;
642                 }
643                 else fac= 2.0;
644                 
645                 x1= -dfac*(winx/fac);
646                 x2= -x1;
647                 y1= -dfac*(winy/fac);
648                 y2= -y1;
649
650                 orth= 0;
651         }
652
653         if(rect) {              /* picking */
654                 rect->xmin/= winx;
655                 rect->xmin= x1+rect->xmin*(x2-x1);
656                 rect->ymin/= winy;
657                 rect->ymin= y1+rect->ymin*(y2-y1);
658                 rect->xmax/= winx;
659                 rect->xmax= x1+rect->xmax*(x2-x1);
660                 rect->ymax/= winy;
661                 rect->ymax= y1+rect->ymax*(y2-y1);
662
663                 if(orth) myortho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -far, far);
664                 else mywindow(rect->xmin, rect->xmax, rect->ymin, rect->ymax, near, far);
665
666         }
667         else {
668                 if(v3d_windowmode) {
669                         if(orth) i_ortho(x1, x2, y1, y2, -far, far, R.winmat);
670                         else {
671                                 if(cam && cam->type==CAM_ORTHO) i_window(x1, x2, y1, y2, near, far, R.winmat);
672                                 else i_window(x1, x2, y1, y2, near, far, R.winmat);
673                         }
674                 }
675                 else {
676                         if(orth) myortho(x1, x2, y1, y2, -far, far);
677                         else {
678                                 if(cam && cam->type==CAM_ORTHO) mywindow(x1, x2, y1, y2, near, far);
679                                 else mywindow(x1, x2, y1, y2, near, far);
680                         }
681                 }
682         }
683
684         if(v3d_windowmode==0) {
685                 glMatrixMode(GL_PROJECTION);
686                 mygetmatrix(curarea->winmat);
687                 glMatrixMode(GL_MODELVIEW);
688         }
689 }
690
691
692 void obmat_to_viewmat(Object *ob)
693 {
694         float bmat[4][4];
695         float tmat[3][3];
696
697         Mat4CpyMat4(bmat, ob->obmat);
698         Mat4Ortho(bmat);
699         Mat4Invert(G.vd->viewmat, bmat);
700         
701         /* view quat calculation, needed for add object */
702         Mat3CpyMat4(tmat, G.vd->viewmat);
703         Mat3ToQuat(tmat, G.vd->viewquat);
704 }
705
706
707 void setviewmatrixview3d()
708 {
709         Camera *cam;
710
711         if(G.vd->persp>=2) {        /* obs/camera */
712                 if(G.vd->camera) {
713                         
714                         where_is_object(G.vd->camera);  
715                         obmat_to_viewmat(G.vd->camera);
716                         
717                         if(G.vd->camera->type==OB_CAMERA) {
718                                 cam= G.vd->camera->data;
719                                 if(cam->type==CAM_ORTHO) G.vd->viewmat[3][2]*= 100.0;
720                         }
721                 }
722                 else {
723                         QuatToMat4(G.vd->viewquat, G.vd->viewmat);
724                         G.vd->viewmat[3][2]-= G.vd->dist;
725                 }
726         }
727         else {
728                 
729                 QuatToMat4(G.vd->viewquat, G.vd->viewmat);
730                 if(G.vd->persp==1) G.vd->viewmat[3][2]-= G.vd->dist;
731                 i_translate(G.vd->ofs[0], G.vd->ofs[1], G.vd->ofs[2], G.vd->viewmat);
732         }
733 }
734
735 void setcameratoview3d()
736 {
737         Object *ob;
738         float dvec[3];
739
740         ob= G.vd->camera;
741         dvec[0]= G.vd->dist*G.vd->viewinv[2][0];
742         dvec[1]= G.vd->dist*G.vd->viewinv[2][1];
743         dvec[2]= G.vd->dist*G.vd->viewinv[2][2];                                        
744         VECCOPY(ob->loc, dvec);
745         VecSubf(ob->loc, ob->loc, G.vd->ofs);
746         G.vd->viewquat[0]= -G.vd->viewquat[0];
747         if (ob->transflag & OB_QUAT) {
748                 QUATCOPY(ob->quat, G.vd->viewquat);
749         } else {
750                 QuatToEul(G.vd->viewquat, ob->rot);
751         }
752         G.vd->viewquat[0]= -G.vd->viewquat[0];
753 }
754
755 /* IGLuint-> GLuint*/
756 short selectprojektie(unsigned int *buffer, short x1, short y1, short x2, short y2)
757 {
758         rctf rect;
759         Base *base;
760         short mval[2], code, hits;
761
762         G.f |= G_PICKSEL;
763         
764         if(x1==0 && x2==0 && y1==0 && y2==0) {
765                 getmouseco_areawin(mval);
766                 rect.xmin= mval[0]-7;
767                 rect.xmax= mval[0]+7;
768                 rect.ymin= mval[1]-7;
769                 rect.ymax= mval[1]+7;
770         }
771         else {
772                 rect.xmin= x1;
773                 rect.xmax= x2;
774                 rect.ymin= y1;
775                 rect.ymax= y2;
776         }
777         /* get rid of overlay button matrix */
778         persp(PERSP_VIEW);
779         setwinmatrixview3d(&rect);
780         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
781         
782         if(G.vd->drawtype > OB_WIRE) {
783                 G.zbuf= TRUE;
784                 glEnable(GL_DEPTH_TEST);
785         }
786
787         glSelectBuffer( MAXPICKBUF, (GLuint *)buffer);
788         glRenderMode(GL_SELECT);
789         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
790         glPushName(-1);
791         code= 1;
792         
793         if(G.obedit && G.obedit->type==OB_MBALL) {
794                 draw_object(BASACT);
795         }
796         else if ((G.obedit && G.obedit->type==OB_ARMATURE)||(G.obpose && G.obpose->type==OB_ARMATURE)) {
797                 draw_object(BASACT);
798         }
799         else {
800                 base= G.scene->base.first;
801                 while(base) {
802                         if(base->lay & G.vd->lay) {
803                                 base->selcol= code;
804                                 glLoadName(code);
805                                 draw_object(base);
806                                 code++;
807                         }
808                         base= base->next;
809                 }
810         }
811         glPopName();    /* see above (pushname) */
812         hits= glRenderMode(GL_RENDER);
813         if(hits<0) error("Too many objects in selectbuf");
814
815         G.f &= ~G_PICKSEL;
816         setwinmatrixview3d(0);
817         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
818         
819         if(G.vd->drawtype > OB_WIRE) {
820                 G.zbuf= 0;
821                 glDisable(GL_DEPTH_TEST);
822         }
823         persp(PERSP_WIN);
824
825         return hits;
826 }
827
828 float *give_cursor()
829 {
830         if(G.vd && G.vd->localview) return G.vd->cursor;
831         else return G.scene->cursor;
832 }
833
834 unsigned int free_localbit()
835 {
836         unsigned int lay;
837         ScrArea *sa;
838         bScreen *sc;
839         
840         lay= 0;
841         
842         /* sometimes we loose a localview: when an area is closed */
843         /* check all areas: which localviews are in use? */
844         sc= G.main->screen.first;
845         while(sc) {
846                 sa= sc->areabase.first;
847                 while(sa) {
848                         SpaceLink *sl= sa->spacedata.first;
849                         while(sl) {
850                                 if(sl->spacetype==SPACE_VIEW3D) {
851                                         View3D *v3d= (View3D*) sl;
852                                         lay |= v3d->lay;
853                                 }
854                                 sl= sl->next;
855                         }
856                         sa= sa->next;
857                 }
858                 sc= sc->id.next;
859         }
860         
861         if( (lay & 0x01000000)==0) return 0x01000000;
862         if( (lay & 0x02000000)==0) return 0x02000000;
863         if( (lay & 0x04000000)==0) return 0x04000000;
864         if( (lay & 0x08000000)==0) return 0x08000000;
865         if( (lay & 0x10000000)==0) return 0x10000000;
866         if( (lay & 0x20000000)==0) return 0x20000000;
867         if( (lay & 0x40000000)==0) return 0x40000000;
868         if( (lay & 0x80000000)==0) return 0x80000000;
869         
870         return 0;
871 }
872
873
874 void initlocalview()
875 {
876         Base *base;
877         float size = 0.0, min[3], max[3], afm[3];
878         unsigned int locallay;
879         int ok=0;
880
881         if(G.vd->localvd) return;
882
883         min[0]= min[1]= min[2]= 1.0e10;
884         max[0]= max[1]= max[2]= -1.0e10;
885
886         locallay= free_localbit();
887
888         if(locallay==0) {
889                 error("Sorry,  no more than 8 localviews");
890                 ok= 0;
891         }
892         else {
893                 if(G.obedit) {
894                         minmax_object(G.obedit, min, max);
895                         
896                         ok= 1;
897                 
898                         BASACT->lay |= locallay;
899                         G.obedit->lay= BASACT->lay;
900                 }
901                 else {
902                         base= FIRSTBASE;
903                         while(base) {
904                                 if TESTBASE(base)  {
905                                         minmax_object(base->object, min, max);
906                                         base->lay |= locallay;
907                                         base->object->lay= base->lay;
908                                         ok= 1;
909                                 }
910                                 base= base->next;
911                         }
912                 }
913                 
914                 afm[0]= (max[0]-min[0]);
915                 afm[1]= (max[1]-min[1]);
916                 afm[2]= (max[2]-min[2]);
917                 size= MAX3(afm[0], afm[1], afm[2]);
918                 if(size<=0.01) size= 0.01;
919         }
920         
921         if(ok) {
922                 G.vd->localvd= MEM_mallocN(sizeof(View3D), "localview");
923                 memcpy(G.vd->localvd, G.vd, sizeof(View3D));
924
925                 G.vd->ofs[0]= -(min[0]+max[0])/2.0;
926                 G.vd->ofs[1]= -(min[1]+max[1])/2.0;
927                 G.vd->ofs[2]= -(min[2]+max[2])/2.0;
928
929                 G.vd->dist= size;
930
931                 if(G.vd->persp>1) {
932                         G.vd->persp= 1;
933                         
934                 }
935                 G.vd->near= 0.1;
936                 G.vd->cursor[0]= -G.vd->ofs[0];
937                 G.vd->cursor[1]= -G.vd->ofs[1];
938                 G.vd->cursor[2]= -G.vd->ofs[2];
939
940                 G.vd->lay= locallay;
941                 
942                 countall();
943                 scrarea_queue_winredraw(curarea);
944         }
945         else {
946                 /* clear flags */
947                 base= FIRSTBASE;
948                 while(base) {
949                         if( base->lay & locallay ) {
950                                 base->lay-= locallay;
951                                 if(base->lay==0) base->lay= G.vd->layact;
952                                 if(base->object != G.obedit) base->flag |= SELECT;
953                                 base->object->lay= base->lay;
954                         }
955                         base= base->next;
956                 }
957                 scrarea_queue_headredraw(curarea);
958                 
959                 G.vd->localview= 0;
960         }
961 }
962
963 void centreview()       /* like a localview without local! */
964 {
965         Base *base;
966         float size, min[3], max[3], afm[3];
967         int ok=0;
968
969         min[0]= min[1]= min[2]= 1.0e10;
970         max[0]= max[1]= max[2]= -1.0e10;
971
972         if(G.obedit) {
973                 minmax_verts(min, max);
974                 //minmax_object(G.obedit, min, max);
975                 
976                 ok= 1;
977         }
978         else {
979                 base= FIRSTBASE;
980                 while(base) {
981                         if TESTBASE(base)  {
982                                 minmax_object(base->object, min, max);
983                                 ok= 1;
984                         }
985                         base= base->next;
986                 }
987         }
988         
989         if(ok==0) return;
990         
991         afm[0]= (max[0]-min[0]);
992         afm[1]= (max[1]-min[1]);
993         afm[2]= (max[2]-min[2]);
994         size= MAX3(afm[0], afm[1], afm[2]);
995         
996         if(size<=0.01) size= 0.01;
997         
998         
999
1000         G.vd->ofs[0]= -(min[0]+max[0])/2.0;
1001         G.vd->ofs[1]= -(min[1]+max[1])/2.0;
1002         G.vd->ofs[2]= -(min[2]+max[2])/2.0;
1003
1004         G.vd->dist= size;
1005
1006         if(G.vd->persp>1) {
1007                 G.vd->persp= 1;
1008                 
1009         }
1010
1011         G.vd->cursor[0]= -G.vd->ofs[0];
1012         G.vd->cursor[1]= -G.vd->ofs[1];
1013         G.vd->cursor[2]= -G.vd->ofs[2];
1014
1015         scrarea_queue_winredraw(curarea);
1016
1017 }
1018
1019
1020 void restore_localviewdata(View3D *vd)
1021 {
1022         if(vd->localvd==0) return;
1023         
1024         VECCOPY(vd->ofs, vd->localvd->ofs);
1025         vd->dist= vd->localvd->dist;
1026         vd->persp= vd->localvd->persp;
1027         vd->view= vd->localvd->view;
1028         vd->near= vd->localvd->near;
1029         vd->far= vd->localvd->far;
1030         vd->lay= vd->localvd->lay;
1031         vd->layact= vd->localvd->layact;
1032         vd->drawtype= vd->localvd->drawtype;
1033         vd->camera= vd->localvd->camera;
1034         QUATCOPY(vd->viewquat, vd->localvd->viewquat);
1035         
1036 }
1037
1038 void endlocalview(ScrArea *sa)
1039 {
1040         View3D *v3d;
1041         struct Base *base;
1042         unsigned int locallay;
1043         
1044         if(sa->spacetype!=SPACE_VIEW3D) return;
1045         v3d= sa->spacedata.first;
1046         
1047         if(v3d->localvd) {
1048                 
1049                 locallay= v3d->lay & 0xFF000000;
1050                 
1051                 restore_localviewdata(v3d);
1052                 
1053                 MEM_freeN(v3d->localvd);
1054                 v3d->localvd= 0;
1055                 v3d->localview= 0;
1056
1057                 /* for when in other window the layers have changed */
1058                 if(v3d->scenelock) v3d->lay= G.scene->lay;
1059                 
1060                 base= FIRSTBASE;
1061                 while(base) {
1062                         if( base->lay & locallay ) {
1063                                 base->lay-= locallay;
1064                                 if(base->lay==0) base->lay= v3d->layact;
1065                                 if(base->object != G.obedit) base->flag |= SELECT;
1066                                 base->object->lay= base->lay;
1067                         }
1068                         base= base->next;
1069                 }
1070
1071                 countall();
1072                 allqueue(REDRAWVIEW3D, 0);      /* because of select */
1073                 
1074         }
1075 }
1076
1077 void view3d_home(int centre)
1078 {
1079         Base *base;
1080         float size, min[3], max[3], afm[3];
1081         int ok= 1, onedone=0;
1082
1083         if(centre) {
1084                 min[0]= min[1]= min[2]= 0.0;
1085                 max[0]= max[1]= max[2]= 0.0;
1086         }
1087         else {
1088                 min[0]= min[1]= min[2]= 1.0e10;
1089                 max[0]= max[1]= max[2]= -1.0e10;
1090         }
1091         
1092         base= FIRSTBASE;
1093         if(base==0) return;
1094         while(base) {
1095                 if(base->lay & G.vd->lay) {
1096                         onedone= 1;
1097                         minmax_object(base->object, min, max);
1098                 }
1099                 base= base->next;
1100         }
1101         if(!onedone) return;
1102         
1103         afm[0]= (max[0]-min[0]);
1104         afm[1]= (max[1]-min[1]);
1105         afm[2]= (max[2]-min[2]);
1106         size= MAX3(afm[0], afm[1], afm[2]);
1107         if(size==0.0) ok= 0;
1108                 
1109         if(ok) {
1110
1111                 G.vd->ofs[0]= -(min[0]+max[0])/2.0;
1112                 G.vd->ofs[1]= -(min[1]+max[1])/2.0;
1113                 G.vd->ofs[2]= -(min[2]+max[2])/2.0;
1114
1115                 G.vd->dist= size;
1116                 
1117                 // correction for window aspect ratio
1118                 if(curarea->winy>2 && curarea->winx>2) {
1119                         size= (float)curarea->winx/(float)curarea->winy;
1120                         if(size<1.0) size= 1.0/size;
1121                         G.vd->dist*= size;
1122                 }
1123                 
1124                 if(G.vd->persp==2) G.vd->persp= 1;
1125                 
1126                 scrarea_queue_winredraw(curarea);
1127         }
1128 }
1129
1130
1131 void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3])
1132 {
1133         float alignaxis[3];
1134         float norm[3], axis[3], angle;
1135
1136         alignaxis[0]= alignaxis[1]= alignaxis[2]= 0.0;
1137         alignaxis[axisidx]= 1.0;
1138
1139         norm[0]= vec[0], norm[1]= vec[1], norm[2]= vec[2];
1140         Normalise(norm);
1141
1142         angle= acos(Inpf(alignaxis, norm));
1143         Crossf(axis, alignaxis, norm);
1144         VecRotToQuat(axis, -angle, v3d->viewquat);
1145
1146         v3d->view= 0;
1147         if (v3d->persp>=2) v3d->persp= 0; /* switch out of camera mode */
1148 }