Initial revision
[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  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <math.h>
34
35 #ifdef WIN32
36 #include <io.h>
37 #include "BLI_winstuff.h"
38 #else
39 #include <unistd.h>
40 #endif   
41
42 #include "MEM_guardedalloc.h"
43
44 #include "BLI_blenlib.h"
45 #include "BLI_arithb.h"
46 #include "BLI_editVert.h"
47
48 #include "DNA_object_types.h"
49 #include "DNA_screen_types.h"
50 #include "DNA_scene_types.h"
51 #include "DNA_space_types.h"
52 #include "DNA_view3d_types.h"
53 #include "DNA_camera_types.h"
54 #include "DNA_lamp_types.h"
55 #include "DNA_userdef_types.h"
56
57 #include "BKE_utildefines.h"
58 #include "BKE_object.h"
59 #include "BKE_global.h"
60 #include "BKE_main.h"
61
62 #include "BIF_gl.h"
63 #include "BIF_space.h"
64 #include "BIF_mywindow.h"
65 #include "BIF_screen.h"
66 #include "BIF_toolbox.h"
67
68 #include "BSE_view.h"
69 #include "BSE_edit.h"           /* For countall */
70 #include "BSE_drawview.h"       /* For inner_play_anim_loop */
71
72 #include "BDR_drawobject.h"     /* For draw_object */
73
74 #include "mydevice.h"
75 #include "blendef.h"
76
77 /* Modules used */
78 #include "render.h"
79
80 #define TRACKBALLSIZE  (1.1)
81
82 void persp3d(View3D *v3d, int a)
83 {
84         ScrArea *area= v3d->area;
85         
86                 /* oppasen met optimaliseren: dan laatste mode in area bewaren */
87                 /* only 3D windows */
88         if(a== 0) {
89                 bwin_get_winmatrix(area->win, area->winmat);
90                 glMatrixMode(GL_MODELVIEW);
91                 bwin_ortho2(area->win, -0.5, (float)(area->winx)-.05, -0.5, (float)(area->winy)-0.5);
92                 glLoadIdentity();
93         }
94         else if(a== 1) {
95                 glMatrixMode(GL_PROJECTION);
96                 bwin_load_winmatrix(area->win, area->winmat);
97                 glMatrixMode(GL_MODELVIEW);
98                 bwin_load_viewmatrix(area->win, v3d->viewmat);
99         }
100 }
101
102 void persp_general(int a)
103 {
104         /* for all window types, not 3D */
105         
106         if(a== 0) {
107                 glPushMatrix();
108                 glMatrixMode(GL_PROJECTION);
109                 glPushMatrix();
110                 glMatrixMode(GL_MODELVIEW);
111
112                 myortho2(-0.5, ((float)(curarea->winx))-0.5, -0.5, ((float)(curarea->winy))-0.5);
113                 glLoadIdentity();
114         }
115         else if(a== 1) {
116                 glMatrixMode(GL_PROJECTION);
117                 glPopMatrix();
118                 glMatrixMode(GL_MODELVIEW);
119                 glPopMatrix();
120         }
121 }
122
123 void persp(int a)
124 {
125         /* oppasen met optimaliseren: dan laatste mode in area bewaren */
126         /* only 3D windows */
127
128         if(curarea->spacetype!=SPACE_VIEW3D) persp_general(a);
129         else if(a== 0) {
130                 glMatrixMode(GL_PROJECTION);
131                 mygetmatrix(curarea->winmat);
132                 glMatrixMode(GL_MODELVIEW);
133                 myortho2(-0.5, (float)(curarea->winx)-.05, -0.5, (float)(curarea->winy)-0.5);
134                 glLoadIdentity();
135         }
136         else if(a== 1) {
137                 glMatrixMode(GL_PROJECTION);
138                 myloadmatrix(curarea->winmat);
139                 glMatrixMode(GL_MODELVIEW);
140                 myloadmatrix(G.vd->viewmat);
141         }
142 }
143
144
145 float zfac=1.0;
146
147 void initgrabz(float x, float y, float z)
148 {
149         if(G.vd==0) return;
150         zfac= G.vd->persmat[0][3]*x+ G.vd->persmat[1][3]*y+ G.vd->persmat[2][3]*z+ G.vd->persmat[3][3];
151 }
152
153 void window_to_3d(float *vec, short mx, short my)
154 {
155         /* altijd initzgrab aanroepen */
156         float dx, dy;
157         float fmx, fmy, winx, winy;
158         
159         /* stupid! */
160         winx= curarea->winx;
161         winy= curarea->winy;
162         fmx= mx;
163         fmy= my;
164         
165         dx= (2.0*fmx)/winx;
166         dx*= zfac;
167         dy= (2.0*fmy)/winy;
168         dy*= zfac;
169
170         vec[0]= (G.vd->persinv[0][0]*dx + G.vd->persinv[1][0]*dy);
171         vec[1]= (G.vd->persinv[0][1]*dx + G.vd->persinv[1][1]*dy);
172         vec[2]= (G.vd->persinv[0][2]*dx + G.vd->persinv[1][2]*dy);
173 }
174
175 void project_short(float *vec, short *adr)      /* clipt */
176 {
177         float fx, fy, vec4[4];
178
179         adr[0]= 3200;
180         VECCOPY(vec4, vec);
181         vec4[3]= 1.0;
182         
183         Mat4MulVec4fl(G.vd->persmat, vec4);
184
185         if( vec4[3]>0.1 ) {
186                 fx= (curarea->winx/2)+(curarea->winx/2)*vec4[0]/vec4[3];
187                 
188                 if( fx>0 && fx<curarea->winx) {
189                 
190                         fy= (curarea->winy/2)+(curarea->winy/2)*vec4[1]/vec4[3];
191                         
192                         if(fy>0.0 && fy< (float)curarea->winy) {
193                                 adr[0]= floor(fx+0.5); 
194                                 adr[1]= floor(fy+0.5);
195                         }
196                 }
197         }
198 }
199
200 void project_short_noclip(float *vec, short *adr)
201 {
202         float fx, fy, vec4[4];
203
204         adr[0]= 3200;
205         VECCOPY(vec4, vec);
206         vec4[3]= 1.0;
207         
208         Mat4MulVec4fl(G.vd->persmat, vec4);
209
210         if( vec4[3]>0.1 ) {
211                 fx= (curarea->winx/2)+(curarea->winx/2)*vec4[0]/vec4[3];
212                 
213                 if( fx>-32700 && fx<32700) {
214                 
215                         fy= (curarea->winy/2)+(curarea->winy/2)*vec4[1]/vec4[3];
216                         
217                         if(fy>-32700.0 && fy<32700.0) {
218                                 adr[0]= floor(fx+0.5); 
219                                 adr[1]= floor(fy+0.5);
220                         }
221                 }
222         }
223 }
224
225 int boundbox_clip(float obmat[][4], BoundBox *bb)
226 {
227         /* return 1: afbeelden */
228         
229         float mat[4][4];
230         float vec[4], min, max;
231         int a, flag= -1, fl;
232         
233         if(bb==0) return 1;
234         
235         Mat4MulMat4(mat, obmat, G.vd->persmat);
236
237         for(a=0; a<8; a++) {
238                 VECCOPY(vec, bb->vec[a]);
239                 vec[3]= 1.0;
240                 Mat4MulVec4fl(mat, vec);
241                 max= vec[3];
242                 min= -vec[3];
243
244                 fl= 0;
245                 if(vec[0] < min) fl+= 1;
246                 if(vec[0] > max) fl+= 2;
247                 if(vec[1] < min) fl+= 4;
248                 if(vec[1] > max) fl+= 8;
249                 if(vec[2] < min) fl+= 16;
250                 if(vec[2] > max) fl+= 32;
251                 
252                 flag &= fl;
253                 if(flag==0) return 1;
254         }
255
256         return 0;
257
258 }
259
260 void fdrawline(float x1, float y1, float x2, float y2)
261 {
262         float v[2];
263
264         glBegin(GL_LINE_STRIP);
265         v[0] = x1; v[1] = y1;
266         glVertex2fv(v);
267         v[0] = x2; v[1] = y2;
268         glVertex2fv(v);
269         glEnd();
270 }
271
272 void fdrawbox(float x1, float y1, float x2, float y2)
273 {
274         float v[2];
275
276         glBegin(GL_LINE_STRIP);
277
278         v[0] = x1; v[1] = y1;
279         glVertex2fv(v);
280         v[0] = x1; v[1] = y2;
281         glVertex2fv(v);
282         v[0] = x2; v[1] = y2;
283         glVertex2fv(v);
284         v[0] = x2; v[1] = y1;
285         glVertex2fv(v);
286         v[0] = x1; v[1] = y1;
287         glVertex2fv(v);
288
289         glEnd();
290 }
291
292 void sdrawline(short x1, short y1, short x2, short y2)
293 {
294         short v[2];
295
296         glBegin(GL_LINE_STRIP);
297         v[0] = x1; v[1] = y1;
298         glVertex2sv(v);
299         v[0] = x2; v[1] = y2;
300         glVertex2sv(v);
301         glEnd();
302 }
303
304 void sdrawbox(short x1, short y1, short x2, short y2)
305 {
306         short v[2];
307
308         glBegin(GL_LINE_STRIP);
309
310         v[0] = x1; v[1] = y1;
311         glVertex2sv(v);
312         v[0] = x1; v[1] = y2;
313         glVertex2sv(v);
314         v[0] = x2; v[1] = y2;
315         glVertex2sv(v);
316         v[0] = x2; v[1] = y1;
317         glVertex2sv(v);
318         v[0] = x1; v[1] = y1;
319         glVertex2sv(v);
320
321         glEnd();
322 }
323
324 /* trackball: deze is t.o.v. een 100% bol formule wel zo mooi */
325
326 void calctrackballvecfirst(rcti *area, short *mval, float *vec)
327 {
328         float x, y, radius, d, z, t;
329         
330         radius= TRACKBALLSIZE;
331         
332         /* x en y normaliseren */
333         x= (area->xmax + area->xmin)/2 -mval[0];
334         x/= (float)((area->xmax - area->xmin)/2);
335         y= (area->ymax + area->ymin)/2 -mval[1];
336         y/= (float)((area->ymax - area->ymin)/2);
337         
338         d = sqrt(x*x + y*y);
339         if (d < radius*M_SQRT1_2)       /* Inside sphere */
340                 z = sqrt(radius*radius - d*d);
341         else
342         {                       /* On hyperbola */
343                 t = radius / M_SQRT2;
344                 z = t*t / d;
345         }
346
347         vec[0]= x;
348         vec[1]= y;
349         vec[2]= -z;             /* jawel! */
350
351         if( fabs(vec[2])>fabs(vec[1]) && fabs(vec[2])>fabs(vec[0]) ) {
352                 vec[0]= 0.0;
353                 vec[1]= 0.0;
354                 if(vec[2]>0.0) vec[2]= 1.0; else vec[2]= -1.0;
355         }
356         else if( fabs(vec[1])>fabs(vec[0]) && fabs(vec[1])>fabs(vec[2]) ) {
357                 vec[0]= 0.0;
358                 vec[2]= 0.0;
359                 if(vec[1]>0.0) vec[1]= 1.0; else vec[1]= -1.0;
360         }
361         else  {
362                 vec[1]= 0.0;
363                 vec[2]= 0.0;
364                 if(vec[0]>0.0) vec[0]= 1.0; else vec[0]= -1.0;
365         }
366 }
367
368 void calctrackballvec(rcti *area, short *mval, float *vec)
369 {
370         float x, y, radius, d, z, t;
371         
372         radius= TRACKBALLSIZE;
373         
374         /* x en y normaliseren */
375         x= (area->xmax + area->xmin)/2 -mval[0];
376         x/= (float)((area->xmax - area->xmin)/4);
377         y= (area->ymax + area->ymin)/2 -mval[1];
378         y/= (float)((area->ymax - area->ymin)/2);
379         
380         d = sqrt(x*x + y*y);
381         if (d < radius*M_SQRT1_2)       /* Inside sphere */
382                 z = sqrt(radius*radius - d*d);
383         else
384         {                       /* On hyperbola */
385                 t = radius / M_SQRT2;
386                 z = t*t / d;
387         }
388
389         vec[0]= x;
390         vec[1]= y;
391         vec[2]= -z;             /* jawel! */
392
393 }
394
395 void viewmove(int mode)
396 {
397         float firstvec[3], newvec[3], dvec[3];
398         float oldquat[4], q1[4], q2[4], si, phi;
399         int firsttime=1;
400         short mval[2], mvalo[2];
401         
402         /* sometimes this routine is called from headerbuttons */
403         areawinset(curarea->win);
404         curarea->head_swap= 0;
405         
406         initgrabz(-G.vd->ofs[0], -G.vd->ofs[1], -G.vd->ofs[2]);
407         
408         QUATCOPY(oldquat, G.vd->viewquat);
409         getmouseco_sc(mvalo);           /* werk met screencoordinaten ivm trackball functie */
410         calctrackballvec(&curarea->winrct, mvalo, firstvec);
411
412         /* cumultime(0); */
413
414         while(TRUE) {
415                 getmouseco_sc(mval);
416                 
417                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || (G.f & G_PLAYANIM)) {
418                         
419                         if(firsttime) {
420                                 firsttime= 0;
421                                 /* wordt hier geroteerd, gezoomd of transleerd */
422                                 if(mode==0) {
423                                         if(G.vd->view!=0) scrarea_queue_headredraw(curarea);    /* voor button */
424                                         G.vd->view= 0;
425                                 }
426                                                 
427                                 if(G.vd->persp==2 || (G.vd->persp==3 && mode!=1)) {
428                                         G.vd->persp= 1;
429                                         scrarea_do_windraw(curarea);
430                                         scrarea_queue_headredraw(curarea);
431                                 }
432                         }
433
434
435                         if(mode==0) {   /* viewroteer */
436                                 
437                                 if(U.flag & TRACKBALL) {
438                                         calctrackballvec(&curarea->winrct, mval, newvec);
439                                         
440                                         VecSubf(dvec, newvec, firstvec);
441                                         
442                                         si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
443                                         si/= (2.0*TRACKBALLSIZE);
444                                         
445                                         if(si<1.0) {
446                                                 Crossf(q1+1, firstvec, newvec);
447         
448                                                 Normalise(q1+1);
449                         
450                                                 phi= asin(si);
451                 
452                                                 si= sin(phi);
453                                                 q1[0]= cos(phi);
454                                                 q1[1]*= si;
455                                                 q1[2]*= si;
456                                                 q1[3]*= si;
457                                                 
458                                                 QuatMul(G.vd->viewquat, q1, oldquat);
459                                         }
460                                 }
461                                 else {
462                                         /* roteren om z-as (x beweging) en liggende as (y) */
463                                         
464                                         phi= 2*(mval[0]-mvalo[0]);
465                                         phi/= (float)curarea->winx;
466                                         si= sin(phi);
467                                         q1[0]= cos(phi);
468                                         q1[1]= q1[2]= 0.0;
469                                         q1[3]= si;
470                                         
471                                         /* liggende as */
472                                         VECCOPY(q2+1, G.vd->viewinv[0]);
473                                         Normalise(q2+1);
474                                         phi= (mvalo[1]-mval[1]);
475                                         phi/= (float)curarea->winy;
476                                         si= sin(phi);
477                                         q2[0]= cos(phi);
478                                         q2[1]*= si;
479                                         q2[2]*= si;
480                                         q2[3]*= si;
481                                         
482                                         QuatMul(q1, q1, q2);
483                                         QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
484                                 }
485                         }
486                         else if(mode==1) {      /* translate */
487                                 if(G.vd->persp==3) {
488                                         /* zoom= 0.5+0.5*(float)(2<<G.vd->rt1); */
489                                         /* dx-= (mval[0]-mvalo[0])/zoom; */
490                                         /* dy-= (mval[1]-mvalo[1])/zoom; */
491                                         /* G.vd->rt2= dx; */
492                                         /* G.vd->rt3= dy; */
493                                         /* if(G.vd->rt2<-320) G.vd->rt2= -320; */
494                                         /* if(G.vd->rt2> 320) G.vd->rt2=  320; */
495                                         /* if(G.vd->rt3<-250) G.vd->rt3= -250; */
496                                         /* if(G.vd->rt3> 250) G.vd->rt3=  250; */
497                                 }
498                                 else {
499                                         window_to_3d(dvec, mval[0]-mvalo[0], mval[1]-mvalo[1]);
500                                         VecAddf(G.vd->ofs, G.vd->ofs, dvec);
501                                 }
502                         }
503                         else if(mode==2) {
504                                 G.vd->dist*= 1.0+(float)(mvalo[0]-mval[0]+mvalo[1]-mval[1])/1000.0;
505                                 
506                                 /* deze limits ook in toets.c */
507                                 if(G.vd->dist<0.001*G.vd->grid) G.vd->dist= 0.001*G.vd->grid;
508                                 if(G.vd->dist>10.0*G.vd->far) G.vd->dist=10.0*G.vd->far;
509                                 
510                                 mval[1]= mvalo[1]; /* blijft ie zoomen */
511                                 mval[0]= mvalo[0];
512                         }
513                         
514                         mvalo[0]= mval[0];
515                         mvalo[1]= mval[1];
516
517                         if(G.f & G_PLAYANIM) inner_play_anim_loop(0, 0);
518                         if(G.f & G_SIMULATION) break;
519
520                         scrarea_do_windraw(curarea);
521                         screen_swapbuffers();
522                 }
523                 else BIF_wait_for_statechange();
524
525                 /* dit moet onderaan, anders pakt de get_mbut het niet op de PC... */
526                 if( !(get_mbut() & (L_MOUSE|M_MOUSE))) break;
527         }
528
529         curarea->head_swap= WIN_FRONT_OK;
530 }
531
532 short v3d_windowmode=0;
533
534 void setwinmatrixview3d(rctf *rect)             /* rect: voor picking */
535 {
536         Camera *cam=0;
537         float d, near, far, winx = 0.0, winy = 0.0;
538         float lens, dfac, tfac, fac, x1, y1, x2, y2;
539         short orth;
540         
541         lens= G.vd->lens;
542         near= G.vd->near;
543         far= G.vd->far;
544         
545         if(G.vd->persp==2) {
546                 if(G.vd->camera) {
547                         if(G.vd->camera->type==OB_LAMP ) {
548                                 Lamp *la;
549                                 
550                                 la= G.vd->camera->data;
551                                 fac= cos( M_PI*la->spotsize/360.0);
552                                 
553                                 x1= saacos(fac);
554                                 lens= 16.0*fac/sin(x1);
555                 
556                                 near= la->clipsta;
557                                 far= la->clipend;
558                         }
559                         else if(G.vd->camera->type==OB_CAMERA) {
560                                 cam= G.vd->camera->data;
561                                 lens= cam->lens;
562                                 near= cam->clipsta;
563                                 far= cam->clipend;
564                                 
565                                 if(cam->type==CAM_ORTHO) {
566                                         lens*= 100.0;
567                                         near= (near+1.0)*100.0; /* otherwise zbuffer troubles. a Patch! */
568                                         far*= 100.0;
569                                 }
570                         }
571                 }
572         }
573         
574         if(v3d_windowmode) {
575                 winx= R.rectx;
576                 winy= R.recty;
577         }
578         else {
579                 winx= curarea->winx;
580                 winy= curarea->winy;
581         }
582         
583         if(winx>winy) d= 0.015625*winx*lens;
584         else d= 0.015625*winy*lens;
585         
586         dfac= near/d;
587
588         /* if(G.vd->persp==1 && G.vd->dproj>1.0) far= G.vd->dproj*far; */
589
590         if(G.vd->persp==0) {
591                 /* x1= -winx*G.vd->dist/1000.0; */
592                 x1= -G.vd->dist;
593                 x2= -x1;
594                 y1= -winy*G.vd->dist/winx;
595                 y2= -y1;
596                 orth= 1;
597         }
598         else {
599                 if(G.vd->persp==2) {
600                         fac= (1.41421+( (float)G.vd->camzoom )/50.0);
601                         fac*= fac;
602                 }
603                 else fac= 2.0;
604                 
605                 x1= -dfac*(winx/fac);
606                 x2= -x1;
607                 y1= -dfac*(winy/fac);
608                 y2= -y1;
609                 
610                 if(G.vd->persp==2 && (G.special1 & G_HOLO)) {
611                         if(cam && (cam->flag & CAM_HOLO2)) {
612                                 tfac= fac/4.0;  /* de fac is 1280/640 gecorr voor obszoom */
613
614                                 if(cam->netend==0.0) cam->netend= EFRA;
615                                 fac= (G.scene->r.cfra-1.0)/(cam->netend)-0.5;
616                                 
617                                 fac*= tfac*(x2-x1);
618                                 fac*= ( cam->hololen1 );
619                                 x1-= fac;
620                                 x2-= fac;
621                         }
622                 }
623                 
624                 orth= 0;
625         }
626
627         if(rect) {              /* picking */
628                 rect->xmin/= winx;
629                 rect->xmin= x1+rect->xmin*(x2-x1);
630                 rect->ymin/= winy;
631                 rect->ymin= y1+rect->ymin*(y2-y1);
632                 rect->xmax/= winx;
633                 rect->xmax= x1+rect->xmax*(x2-x1);
634                 rect->ymax/= winy;
635                 rect->ymax= y1+rect->ymax*(y2-y1);
636
637                 if(orth) myortho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -far, far);
638                 else mywindow(rect->xmin, rect->xmax, rect->ymin, rect->ymax, near, far);
639
640         }
641         else {
642                 if(v3d_windowmode) {
643                         if(orth) i_ortho(x1, x2, y1, y2, -far, far, R.winmat);
644                         else {
645                                 if(cam && cam->type==CAM_ORTHO) i_window(x1, x2, y1, y2, near, far, R.winmat);
646                                 else i_window(x1, x2, y1, y2, near, far, R.winmat);
647                         }
648                 }
649                 else {
650                         if(orth) myortho(x1, x2, y1, y2, -far, far);
651                         else {
652                                 if(cam && cam->type==CAM_ORTHO) mywindow(x1, x2, y1, y2, near, far);
653                                 else mywindow(x1, x2, y1, y2, near, far);
654                         }
655                 }
656         }
657
658         if(v3d_windowmode==0) {
659                 glMatrixMode(GL_PROJECTION);
660                 mygetmatrix(curarea->winmat);
661                 glMatrixMode(GL_MODELVIEW);
662         }
663 }
664
665
666 void obmat_to_viewmat(Object *ob)
667 {
668         float bmat[4][4];
669         float tmat[3][3];
670
671         Mat4CpyMat4(bmat, ob->obmat);
672         Mat4Ortho(bmat);
673         Mat4Invert(G.vd->viewmat, bmat);
674         
675         /* viewquat berekenen, o.a. voor add object */
676         Mat3CpyMat4(tmat, G.vd->viewmat);
677         Mat3ToQuat(tmat, G.vd->viewquat);
678 }
679
680
681 void setviewmatrixview3d()
682 {
683         Camera *cam;
684 /*      float bepaalphitheta(); */
685
686         if(G.special1 & G_HOLO) RE_holoview();
687
688         if(G.vd->persp>=2) {        /* obs/camera */
689                 if(G.vd->camera) {
690                         
691                         where_is_object(G.vd->camera);  
692                         obmat_to_viewmat(G.vd->camera);
693                         
694                         if(G.vd->camera->type==OB_CAMERA) {
695                                 cam= G.vd->camera->data;
696                                 if(cam->type==CAM_ORTHO) G.vd->viewmat[3][2]*= 100.0;
697                         }
698                 }
699                 else {
700                         QuatToMat4(G.vd->viewquat, G.vd->viewmat);
701                         G.vd->viewmat[3][2]-= G.vd->dist;
702                 }
703         }
704         else {
705                 
706                 QuatToMat4(G.vd->viewquat, G.vd->viewmat);
707                 if(G.vd->persp==1) G.vd->viewmat[3][2]-= G.vd->dist;
708                 i_translate(G.vd->ofs[0], G.vd->ofs[1], G.vd->ofs[2], G.vd->viewmat);
709         }
710 }
711
712 /* IGLuint-> GLuint*/
713 short selectprojektie(unsigned int *buffer, short x1, short y1, short x2, short y2)
714 {
715         rctf rect;
716         Base *base;
717         short mval[2], code, hits;
718
719         G.f |= G_PICKSEL;
720         
721         if(x1==0 && x2==0 && y1==0 && y2==0) {
722                 getmouseco_areawin(mval);
723                 rect.xmin= mval[0]-7;
724                 rect.xmax= mval[0]+7;
725                 rect.ymin= mval[1]-7;
726                 rect.ymax= mval[1]+7;
727         }
728         else {
729                 rect.xmin= x1;
730                 rect.xmax= x2;
731                 rect.ymin= y1;
732                 rect.ymax= y2;
733         }
734         setwinmatrixview3d(&rect);
735         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
736         
737         if(G.vd->drawtype > OB_WIRE) {
738                 G.zbuf= TRUE;
739                 glEnable(GL_DEPTH_TEST);
740         }
741
742         glSelectBuffer( MAXPICKBUF, buffer);
743         glRenderMode(GL_SELECT);
744         glInitNames();  /* deze twee fies zijn waarvoor? Anders werkt het niet */
745         glPushName(-1);
746         code= 1;
747         
748         if(G.obedit && G.obedit->type==OB_MBALL) {
749                 draw_object(BASACT);
750         }
751         else if ((G.obedit && G.obedit->type==OB_ARMATURE)||(G.obpose && G.obpose->type==OB_ARMATURE)) {
752                 draw_object(BASACT);
753         }
754         else {
755                 base= G.scene->base.first;
756                 while(base) {
757                         if(base->lay & G.vd->lay) {
758                                 base->selcol= code;
759                                 glLoadName(code);
760                                 draw_object(base);
761                                 code++;
762                         }
763                         base= base->next;
764                 }
765         }
766         glPopName();    /* zie boven (pushname) */
767         hits= glRenderMode(GL_RENDER);
768         if(hits<0) error("Too many objects in selectbuf");
769
770         G.f &= ~G_PICKSEL;
771         setwinmatrixview3d(0);
772         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
773         
774         if(G.vd->drawtype > OB_WIRE) {
775                 G.zbuf= 0;
776                 glDisable(GL_DEPTH_TEST);
777         }
778
779         return hits;
780 }
781
782 float *give_cursor()
783 {
784         if(G.vd && G.vd->localview) return G.vd->cursor;
785         else return G.scene->cursor;
786 }
787
788 unsigned int free_localbit()
789 {
790         unsigned int lay;
791         ScrArea *sa;
792         bScreen *sc;
793         
794         lay= 0;
795         
796         /* soms kunnen we een localview kwijtrijaken: als een area gesloten wordt */
797         /* alle area's aflopen: welke localviews zijn in gebruik */
798         sc= G.main->screen.first;
799         while(sc) {
800                 sa= sc->areabase.first;
801                 while(sa) {
802                         SpaceLink *sl= sa->spacedata.first;
803                         while(sl) {
804                                 if(sl->spacetype==SPACE_VIEW3D) {
805                                         View3D *v3d= (View3D*) sl;
806                                         lay |= v3d->lay;
807                                 }
808                                 sl= sl->next;
809                         }
810                         sa= sa->next;
811                 }
812                 sc= sc->id.next;
813         }
814         
815         if( (lay & 0x01000000)==0) return 0x01000000;
816         if( (lay & 0x02000000)==0) return 0x02000000;
817         if( (lay & 0x04000000)==0) return 0x04000000;
818         if( (lay & 0x08000000)==0) return 0x08000000;
819         if( (lay & 0x10000000)==0) return 0x10000000;
820         if( (lay & 0x20000000)==0) return 0x20000000;
821         if( (lay & 0x40000000)==0) return 0x40000000;
822         if( (lay & 0x80000000)==0) return 0x80000000;
823         
824         return 0;
825 }
826
827
828 void initlocalview()
829 {
830         Base *base;
831         float size = 0.0, min[3], max[3], afm[3];
832         unsigned int locallay;
833         int ok=0;
834
835         if(G.vd->localvd) return;
836
837         min[0]= min[1]= min[2]= 1.0e10;
838         max[0]= max[1]= max[2]= -1.0e10;
839
840         locallay= free_localbit();
841
842         if(locallay==0) {
843                 error("Sorry,  no more than 8 localviews");
844                 ok= 0;
845         }
846         else {
847                 if(G.obedit) {
848                         minmax_object(G.obedit, min, max);
849                         
850                         ok= 1;
851                 
852                         BASACT->lay |= locallay;
853                         G.obedit->lay= BASACT->lay;
854                 }
855                 else {
856                         base= FIRSTBASE;
857                         while(base) {
858                                 if TESTBASE(base)  {
859                                         minmax_object(base->object, min, max);
860                                         base->lay |= locallay;
861                                         base->object->lay= base->lay;
862                                         ok= 1;
863                                 }
864                                 base= base->next;
865                         }
866                 }
867                 
868                 afm[0]= (max[0]-min[0]);
869                 afm[1]= (max[1]-min[1]);
870                 afm[2]= (max[2]-min[2]);
871                 size= MAX3(afm[0], afm[1], afm[2]);
872                 if(size<=0.01) size= 0.01;
873         }
874         
875         if(ok) {
876                 G.vd->localvd= MEM_mallocN(sizeof(View3D), "localview");
877                 memcpy(G.vd->localvd, G.vd, sizeof(View3D));
878
879                 G.vd->ofs[0]= -(min[0]+max[0])/2.0;
880                 G.vd->ofs[1]= -(min[1]+max[1])/2.0;
881                 G.vd->ofs[2]= -(min[2]+max[2])/2.0;
882
883                 G.vd->dist= size;
884
885                 if(G.vd->persp>1) {
886                         G.vd->persp= 1;
887                         
888                 }
889                 G.vd->near= 0.1;
890                 G.vd->cursor[0]= -G.vd->ofs[0];
891                 G.vd->cursor[1]= -G.vd->ofs[1];
892                 G.vd->cursor[2]= -G.vd->ofs[2];
893
894                 G.vd->lay= locallay;
895                 
896                 countall();
897                 scrarea_queue_winredraw(curarea);
898         }
899         else {
900                 /* flags wissen */
901                 base= FIRSTBASE;
902                 while(base) {
903                         if( base->lay & locallay ) {
904                                 base->lay-= locallay;
905                                 if(base->lay==0) base->lay= G.vd->layact;
906                                 if(base->object != G.obedit) base->flag |= SELECT;
907                                 base->object->lay= base->lay;
908                         }
909                         base= base->next;
910                 }
911                 scrarea_queue_headredraw(curarea);
912                 
913                 G.vd->localview= 0;
914         }
915 }
916
917 void centreview()       /* localview zonder local! */
918 {
919         Base *base;
920         float size, min[3], max[3], afm[3];
921         int ok=0;
922
923         min[0]= min[1]= min[2]= 1.0e10;
924         max[0]= max[1]= max[2]= -1.0e10;
925
926         if(G.obedit) {
927                 minmax_object(G.obedit, min, max);
928                 
929                 ok= 1;
930         }
931         else {
932                 base= FIRSTBASE;
933                 while(base) {
934                         if TESTBASE(base)  {
935                                 minmax_object(base->object, min, max);
936                                 ok= 1;
937                         }
938                         base= base->next;
939                 }
940         }
941         
942         if(ok==0) return;
943         
944         afm[0]= (max[0]-min[0]);
945         afm[1]= (max[1]-min[1]);
946         afm[2]= (max[2]-min[2]);
947         size= MAX3(afm[0], afm[1], afm[2]);
948         
949         if(size<=0.01) size= 0.01;
950         
951         
952
953         G.vd->ofs[0]= -(min[0]+max[0])/2.0;
954         G.vd->ofs[1]= -(min[1]+max[1])/2.0;
955         G.vd->ofs[2]= -(min[2]+max[2])/2.0;
956
957         G.vd->dist= size;
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         scrarea_queue_winredraw(curarea);
969
970 }
971
972
973 void restore_localviewdata(View3D *vd)
974 {
975         if(vd->localvd==0) return;
976         
977         VECCOPY(vd->ofs, vd->localvd->ofs);
978         vd->dist= vd->localvd->dist;
979         vd->persp= vd->localvd->persp;
980         vd->view= vd->localvd->view;
981         vd->near= vd->localvd->near;
982         vd->far= vd->localvd->far;
983         vd->lay= vd->localvd->lay;
984         vd->layact= vd->localvd->layact;
985         vd->drawtype= vd->localvd->drawtype;
986         vd->camera= vd->localvd->camera;
987         QUATCOPY(vd->viewquat, vd->localvd->viewquat);
988         
989 }
990
991 void endlocalview(ScrArea *sa)
992 {
993         View3D *v3d;
994         struct Base *base;
995         unsigned int locallay;
996         
997         if(sa->spacetype!=SPACE_VIEW3D) return;
998         v3d= sa->spacedata.first;
999         
1000         if(v3d->localvd) {
1001                 
1002                 locallay= v3d->lay & 0xFF000000;
1003                 
1004                 restore_localviewdata(v3d);
1005                 
1006                 MEM_freeN(v3d->localvd);
1007                 v3d->localvd= 0;
1008                 v3d->localview= 0;
1009
1010                 /* als in ander window de layers zijn veranderd */
1011                 if(v3d->scenelock) v3d->lay= G.scene->lay;
1012                 
1013                 base= FIRSTBASE;
1014                 while(base) {
1015                         if( base->lay & locallay ) {
1016                                 base->lay-= locallay;
1017                                 if(base->lay==0) base->lay= v3d->layact;
1018                                 if(base->object != G.obedit) base->flag |= SELECT;
1019                                 base->object->lay= base->lay;
1020                         }
1021                         base= base->next;
1022                 }
1023
1024                 countall();
1025                 allqueue(REDRAWVIEW3D, 0);      /* ivm select */
1026                 
1027         }
1028 }
1029
1030 void view3d_home(int centre)
1031 {
1032         Base *base;
1033         float size, min[3], max[3], afm[3];
1034         int ok= 1, onedone=0;
1035
1036         if(centre) {
1037                 min[0]= min[1]= min[2]= 0.0;
1038                 max[0]= max[1]= max[2]= 0.0;
1039         }
1040         else {
1041                 min[0]= min[1]= min[2]= 1.0e10;
1042                 max[0]= max[1]= max[2]= -1.0e10;
1043         }
1044         
1045         base= FIRSTBASE;
1046         if(base==0) return;
1047         while(base) {
1048                 if(base->lay & G.vd->lay) {
1049                         onedone= 1;
1050                         minmax_object(base->object, min, max);
1051                 }
1052                 base= base->next;
1053         }
1054         if(!onedone) return;
1055         
1056         afm[0]= (max[0]-min[0]);
1057         afm[1]= (max[1]-min[1]);
1058         afm[2]= (max[2]-min[2]);
1059         size= MAX3(afm[0], afm[1], afm[2]);
1060         if(size==0.0) ok= 0;
1061                 
1062         if(ok) {
1063
1064                 G.vd->ofs[0]= -(min[0]+max[0])/2.0;
1065                 G.vd->ofs[1]= -(min[1]+max[1])/2.0;
1066                 G.vd->ofs[2]= -(min[2]+max[2])/2.0;
1067
1068                 G.vd->dist= size;
1069                 
1070                 if(G.vd->persp==2) G.vd->persp= 1;
1071                 
1072                 scrarea_queue_winredraw(curarea);
1073         }
1074 }
1075
1076
1077 void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3])
1078 {
1079         float alignaxis[3];
1080         float norm[3], axis[3], angle;
1081
1082         alignaxis[0]= alignaxis[1]= alignaxis[2]= 0.0;
1083         alignaxis[axisidx]= 1.0;
1084
1085         norm[0]= vec[0], norm[1]= vec[1], norm[2]= vec[2];
1086         Normalise(norm);
1087
1088         angle= acos(Inpf(alignaxis, norm));
1089         Crossf(axis, alignaxis, norm);
1090         VecRotToQuat(axis, -angle, v3d->viewquat);
1091
1092         v3d->view= 0;
1093         if (v3d->persp>=2) v3d->persp= 0; /* switch out of camera mode */
1094 }
1095