5f1957b84b6ed926f0081f24bc04c714c72d0f76
[blender.git] / source / blender / editors / space_view3d / view3d_view.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL 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. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31 #include <math.h>
32 #include <float.h>
33
34 #include "DNA_action_types.h"
35 #include "DNA_armature_types.h"
36 #include "DNA_camera_types.h"
37 #include "DNA_lamp_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_space_types.h"
40 #include "DNA_scene_types.h"
41 #include "DNA_screen_types.h"
42 #include "DNA_userdef_types.h"
43 #include "DNA_view3d_types.h"
44 #include "DNA_world_types.h"
45
46 #include "MEM_guardedalloc.h"
47
48 #include "BLI_blenlib.h"
49 #include "BLI_arithb.h"
50 #include "BLI_rand.h"
51
52 #include "BKE_anim.h"
53 #include "BKE_action.h"
54 #include "BKE_object.h"
55 #include "BKE_global.h"
56 #include "BKE_main.h"
57 #include "BKE_scene.h"
58 #include "BKE_screen.h"
59 #include "BKE_utildefines.h"
60
61 #include "RE_pipeline.h"        // make_stars
62
63 #include "BIF_gl.h"
64
65 #include "WM_api.h"
66
67 #include "ED_screen.h"
68
69 #include "UI_interface.h"
70 #include "UI_resources.h"
71 #include "UI_view2d.h"
72
73 #include "PIL_time.h" /* smoothview */
74
75 #include "view3d_intern.h"      // own include
76
77 #define BL_NEAR_CLIP 0.001
78
79 float *give_cursor(Scene *scene, View3D *v3d)
80 {
81         if(v3d && v3d->localview) return v3d->cursor;
82         else return scene->cursor;
83 }
84
85 /* create intersection coordinates in view Z direction at mouse coordinates */
86 void viewline(ARegion *ar, View3D *v3d, short mval[2], float ray_start[3], float ray_end[3])
87 {
88         float vec[4];
89         
90         if(v3d->persp != V3D_ORTHO){
91                 vec[0]= 2.0f * mval[0] / ar->winx - 1;
92                 vec[1]= 2.0f * mval[1] / ar->winy - 1;
93                 vec[2]= -1.0f;
94                 vec[3]= 1.0f;
95                 
96                 Mat4MulVec4fl(v3d->persinv, vec);
97                 VecMulf(vec, 1.0f / vec[3]);
98                 
99                 VECCOPY(ray_start, v3d->viewinv[3]);
100                 VECSUB(vec, vec, ray_start);
101                 Normalize(vec);
102                 
103                 VECADDFAC(ray_start, v3d->viewinv[3], vec, v3d->near);
104                 VECADDFAC(ray_end, v3d->viewinv[3], vec, v3d->far);
105         }
106         else {
107                 vec[0] = 2.0f * mval[0] / ar->winx - 1;
108                 vec[1] = 2.0f * mval[1] / ar->winy - 1;
109                 vec[2] = 0.0f;
110                 vec[3] = 1.0f;
111                 
112                 Mat4MulVec4fl(v3d->persinv, vec);
113                 
114                 VECADDFAC(ray_start, vec, v3d->viewinv[2],  1000.0f);
115                 VECADDFAC(ray_end, vec, v3d->viewinv[2], -1000.0f);
116         }
117 }
118
119 /* create intersection ray in view Z direction at mouse coordinates */
120 void viewray(ARegion *ar, View3D *v3d, short mval[2], float ray_start[3], float ray_normal[3])
121 {
122         float ray_end[3];
123         
124         viewline(ar, v3d, mval, ray_start, ray_end);
125         VecSubf(ray_normal, ray_end, ray_start);
126         Normalize(ray_normal);
127 }
128
129
130 void initgrabz(View3D *v3d, float x, float y, float z)
131 {
132         if(v3d==NULL) return;
133         v3d->zfac= v3d->persmat[0][3]*x+ v3d->persmat[1][3]*y+ v3d->persmat[2][3]*z+ v3d->persmat[3][3];
134         
135         /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that 
136                 * (accounting for near zero values)
137                 * */
138         if (v3d->zfac < 1.e-6f && v3d->zfac > -1.e-6f) v3d->zfac = 1.0f;
139         
140         /* Negative zfac means x, y, z was behind the camera (in perspective).
141                 * This gives flipped directions, so revert back to ok default case.
142         */
143         if (v3d->zfac < 0.0f) v3d->zfac = 1.0f;
144 }
145
146 void window_to_3d(ARegion *ar, View3D *v3d, float *vec, short mx, short my)
147 {
148         /* always call initgrabz */
149         float dx, dy;
150         
151         dx= 2.0f*mx*v3d->zfac/ar->winx;
152         dy= 2.0f*my*v3d->zfac/ar->winy;
153         
154         vec[0]= (v3d->persinv[0][0]*dx + v3d->persinv[1][0]*dy);
155         vec[1]= (v3d->persinv[0][1]*dx + v3d->persinv[1][1]*dy);
156         vec[2]= (v3d->persinv[0][2]*dx + v3d->persinv[1][2]*dy);
157 }
158
159 void view3d_get_object_project_mat(View3D *v3d, Object *ob, float pmat[4][4], float vmat[4][4])
160 {
161         Mat4MulMat4(vmat, ob->obmat, v3d->viewmat);
162         Mat4MulMat4(pmat, vmat, v3d->winmat);
163         Mat4CpyMat4(vmat, ob->obmat);
164 }
165
166 /* projectmat brings it to window coords, wmat to rotated world space */
167 void view3d_project_short_clip(ARegion *ar, View3D *v3d, float *vec, short *adr, float projmat[4][4], float wmat[4][4])
168 {
169         float fx, fy, vec4[4];
170         
171         adr[0]= IS_CLIPPED;
172         
173         /* clipplanes in eye space */
174         if(v3d->flag & V3D_CLIPPING) {
175                 VECCOPY(vec4, vec);
176                 Mat4MulVecfl(wmat, vec4);
177                 if(view3d_test_clipping(v3d, vec4))
178                         return;
179         }
180         
181         VECCOPY(vec4, vec);
182         vec4[3]= 1.0;
183         
184         Mat4MulVec4fl(projmat, vec4);
185         
186         /* clipplanes in window space */
187         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
188                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
189                 
190                 if( fx>0 && fx<ar->winx) {
191                         
192                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
193                         
194                         if(fy>0.0 && fy< (float)ar->winy) {
195                                 adr[0]= (short)floor(fx); 
196                                 adr[1]= (short)floor(fy);
197                         }
198                 }
199         }
200 }
201
202 void view3d_project_short_noclip(ARegion *ar, float *vec, short *adr, float mat[4][4])
203 {
204         float fx, fy, vec4[4];
205         
206         adr[0]= IS_CLIPPED;
207         
208         VECCOPY(vec4, vec);
209         vec4[3]= 1.0;
210         
211         Mat4MulVec4fl(mat, vec4);
212         
213         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
214                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
215                 
216                 if( fx>-32700 && fx<32700) {
217                         
218                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
219                         
220                         if(fy>-32700.0 && fy<32700.0) {
221                                 adr[0]= (short)floor(fx); 
222                                 adr[1]= (short)floor(fy);
223                         }
224                 }
225         }
226 }
227
228 void view3d_project_float(ARegion *ar, float *vec, float *adr, float mat[4][4])
229 {
230         float vec4[4];
231         
232         adr[0]= IS_CLIPPED;
233         VECCOPY(vec4, vec);
234         vec4[3]= 1.0;
235         
236         Mat4MulVec4fl(mat, vec4);
237         
238         if( vec4[3]>FLT_EPSILON ) {
239                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];        
240                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
241         } else {
242                 adr[0] = adr[1] = 0.0f;
243         }
244 }
245
246 int boundbox_clip(View3D *v3d, float obmat[][4], BoundBox *bb)
247 {
248         /* return 1: draw */
249         
250         float mat[4][4];
251         float vec[4], min, max;
252         int a, flag= -1, fl;
253         
254         if(bb==NULL) return 1;
255         if(bb->flag & OB_BB_DISABLED) return 1;
256         
257         Mat4MulMat4(mat, obmat, v3d->persmat);
258         
259         for(a=0; a<8; a++) {
260                 VECCOPY(vec, bb->vec[a]);
261                 vec[3]= 1.0;
262                 Mat4MulVec4fl(mat, vec);
263                 max= vec[3];
264                 min= -vec[3];
265                 
266                 fl= 0;
267                 if(vec[0] < min) fl+= 1;
268                 if(vec[0] > max) fl+= 2;
269                 if(vec[1] < min) fl+= 4;
270                 if(vec[1] > max) fl+= 8;
271                 if(vec[2] < min) fl+= 16;
272                 if(vec[2] > max) fl+= 32;
273                 
274                 flag &= fl;
275                 if(flag==0) return 1;
276         }
277         
278         return 0;
279 }
280
281 void project_short(ARegion *ar, View3D *v3d, float *vec, short *adr)    /* clips */
282 {
283         float fx, fy, vec4[4];
284         
285         adr[0]= IS_CLIPPED;
286         
287         if(v3d->flag & V3D_CLIPPING) {
288                 if(view3d_test_clipping(v3d, vec))
289                         return;
290         }
291         
292         VECCOPY(vec4, vec);
293         vec4[3]= 1.0;
294         Mat4MulVec4fl(v3d->persmat, vec4);
295         
296         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
297                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
298                 
299                 if( fx>0 && fx<ar->winx) {
300                         
301                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
302                         
303                         if(fy>0.0 && fy< (float)ar->winy) {
304                                 adr[0]= (short)floor(fx); 
305                                 adr[1]= (short)floor(fy);
306                         }
307                 }
308         }
309 }
310
311 void project_int(ARegion *ar, View3D *v3d, float *vec, int *adr)
312 {
313         float fx, fy, vec4[4];
314         
315         adr[0]= (int)2140000000.0f;
316         VECCOPY(vec4, vec);
317         vec4[3]= 1.0;
318         
319         Mat4MulVec4fl(v3d->persmat, vec4);
320         
321         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
322                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
323                 
324                 if( fx>-2140000000.0f && fx<2140000000.0f) {
325                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
326                         
327                         if(fy>-2140000000.0f && fy<2140000000.0f) {
328                                 adr[0]= (int)floor(fx); 
329                                 adr[1]= (int)floor(fy);
330                         }
331                 }
332         }
333 }
334
335 void project_int_noclip(ARegion *ar, View3D *v3d, float *vec, int *adr)
336 {
337         float fx, fy, vec4[4];
338         
339         VECCOPY(vec4, vec);
340         vec4[3]= 1.0;
341         
342         Mat4MulVec4fl(v3d->persmat, vec4);
343         
344         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
345                 fx = (ar->winx/2)*(1 + vec4[0]/vec4[3]);
346                 fy = (ar->winy/2)*(1 + vec4[1]/vec4[3]);
347                 
348                 adr[0] = (int)floor(fx); 
349                 adr[1] = (int)floor(fy);
350         }
351         else
352         {
353                 adr[0] = ar->winx / 2;
354                 adr[1] = ar->winy / 2;
355         }
356 }
357
358 void project_short_noclip(ARegion *ar, View3D *v3d, float *vec, short *adr)
359 {
360         float fx, fy, vec4[4];
361         
362         adr[0]= IS_CLIPPED;
363         VECCOPY(vec4, vec);
364         vec4[3]= 1.0;
365         
366         Mat4MulVec4fl(v3d->persmat, vec4);
367         
368         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
369                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
370                 
371                 if( fx>-32700 && fx<32700) {
372                         
373                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
374                         
375                         if(fy>-32700.0 && fy<32700.0) {
376                                 adr[0]= (short)floor(fx); 
377                                 adr[1]= (short)floor(fy);
378                         }
379                 }
380         }
381 }
382
383 void project_float(ARegion *ar, View3D *v3d, float *vec, float *adr)
384 {
385         float vec4[4];
386         
387         adr[0]= IS_CLIPPED;
388         VECCOPY(vec4, vec);
389         vec4[3]= 1.0;
390         
391         Mat4MulVec4fl(v3d->persmat, vec4);
392         
393         if( vec4[3]>BL_NEAR_CLIP ) {
394                 adr[0] = (float)(ar->winx/2.0)+(ar->winx/2.0)*vec4[0]/vec4[3];  
395                 adr[1] = (float)(ar->winy/2.0)+(ar->winy/2.0)*vec4[1]/vec4[3];
396         }
397 }
398
399 void project_float_noclip(ARegion *ar, View3D *v3d, float *vec, float *adr)
400 {
401         float vec4[4];
402         
403         VECCOPY(vec4, vec);
404         vec4[3]= 1.0;
405         
406         Mat4MulVec4fl(v3d->persmat, vec4);
407         
408         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
409                 adr[0] = (float)(ar->winx/2.0)+(ar->winx/2.0)*vec4[0]/vec4[3];  
410                 adr[1] = (float)(ar->winy/2.0)+(ar->winy/2.0)*vec4[1]/vec4[3];
411         }
412         else
413         {
414                 adr[0] = ar->winx / 2.0f;
415                 adr[1] = ar->winy / 2.0f;
416         }
417 }
418
419
420
421 /* also exposed in previewrender.c */
422 int get_view3d_viewplane(View3D *v3d, int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
423 {
424         Camera *cam=NULL;
425         float lens, fac, x1, y1, x2, y2;
426         float winx= (float)winxi, winy= (float)winyi;
427         int orth= 0;
428         
429         lens= v3d->lens;        
430         
431         *clipsta= v3d->near;
432         *clipend= v3d->far;
433         
434         if(v3d->persp==V3D_CAMOB) {
435                 if(v3d->camera) {
436                         if(v3d->camera->type==OB_LAMP ) {
437                                 Lamp *la;
438                                 
439                                 la= v3d->camera->data;
440                                 fac= cos( M_PI*la->spotsize/360.0);
441                                 
442                                 x1= saacos(fac);
443                                 lens= 16.0*fac/sin(x1);
444                                 
445                                 *clipsta= la->clipsta;
446                                 *clipend= la->clipend;
447                         }
448                         else if(v3d->camera->type==OB_CAMERA) {
449                                 cam= v3d->camera->data;
450                                 lens= cam->lens;
451                                 *clipsta= cam->clipsta;
452                                 *clipend= cam->clipend;
453                         }
454                 }
455         }
456         
457         if(v3d->persp==V3D_ORTHO) {
458                 if(winx>winy) x1= -v3d->dist;
459                 else x1= -winx*v3d->dist/winy;
460                 x2= -x1;
461                 
462                 if(winx>winy) y1= -winy*v3d->dist/winx;
463                 else y1= -v3d->dist;
464                 y2= -y1;
465                 
466                 *clipend *= 0.5;        // otherwise too extreme low zbuffer quality
467                 *clipsta= - *clipend;
468                 orth= 1;
469         }
470         else {
471                 /* fac for zoom, also used for camdx */
472                 if(v3d->persp==V3D_CAMOB) {
473                         fac= (1.41421+( (float)v3d->camzoom )/50.0);
474                         fac*= fac;
475                 }
476                 else fac= 2.0;
477                 
478                 /* viewplane size depends... */
479                 if(cam && cam->type==CAM_ORTHO) {
480                         /* ortho_scale == 1 means exact 1 to 1 mapping */
481                         float dfac= 2.0*cam->ortho_scale/fac;
482                         
483                         if(winx>winy) x1= -dfac;
484                         else x1= -winx*dfac/winy;
485                         x2= -x1;
486                         
487                         if(winx>winy) y1= -winy*dfac/winx;
488                         else y1= -dfac;
489                         y2= -y1;
490                         orth= 1;
491                 }
492                 else {
493                         float dfac;
494                         
495                         if(winx>winy) dfac= 64.0/(fac*winx*lens);
496                         else dfac= 64.0/(fac*winy*lens);
497                         
498                         x1= - *clipsta * winx*dfac;
499                         x2= -x1;
500                         y1= - *clipsta * winy*dfac;
501                         y2= -y1;
502                         orth= 0;
503                 }
504                 /* cam view offset */
505                 if(cam) {
506                         float dx= 0.5*fac*v3d->camdx*(x2-x1);
507                         float dy= 0.5*fac*v3d->camdy*(y2-y1);
508                         x1+= dx;
509                         x2+= dx;
510                         y1+= dy;
511                         y2+= dy;
512                 }
513         }
514         
515         if(pixsize) {
516                 float viewfac;
517                 
518                 if(orth) {
519                         viewfac= (winx >= winy)? winx: winy;
520                         *pixsize= 1.0f/viewfac;
521                 }
522                 else {
523                         viewfac= (((winx >= winy)? winx: winy)*lens)/32.0;
524                         *pixsize= *clipsta/viewfac;
525                 }
526         }
527         
528         viewplane->xmin= x1;
529         viewplane->ymin= y1;
530         viewplane->xmax= x2;
531         viewplane->ymax= y2;
532         
533         return orth;
534 }
535
536
537 /* important to not set windows active in here, can be renderwin for example */
538 void setwinmatrixview3d(View3D *v3d, int winx, int winy, rctf *rect)            /* rect: for picking */
539 {
540         rctf viewplane;
541         float clipsta, clipend, x1, y1, x2, y2;
542         int orth;
543         
544         orth= get_view3d_viewplane(v3d, winx, winy, &viewplane, &clipsta, &clipend, NULL);
545         //      printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
546         x1= viewplane.xmin;
547         y1= viewplane.ymin;
548         x2= viewplane.xmax;
549         y2= viewplane.ymax;
550         
551         if(rect) {              /* picking */
552                 rect->xmin/= (float)winx;
553                 rect->xmin= x1+rect->xmin*(x2-x1);
554                 rect->ymin/= (float)winy;
555                 rect->ymin= y1+rect->ymin*(y2-y1);
556                 rect->xmax/= (float)winx;
557                 rect->xmax= x1+rect->xmax*(x2-x1);
558                 rect->ymax/= (float)winy;
559                 rect->ymax= y1+rect->ymax*(y2-y1);
560                 
561                 if(orth) wmOrtho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
562                 else wmFrustum(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
563                 
564         }
565         else {
566                 if(orth) wmOrtho(x1, x2, y1, y2, clipsta, clipend);
567                 else wmFrustum(x1, x2, y1, y2, clipsta, clipend);
568         }
569
570         /* not sure what this was for? (ton) */
571         glMatrixMode(GL_PROJECTION);
572         wmGetMatrix(v3d->winmat);
573         glMatrixMode(GL_MODELVIEW);
574 }
575
576
577
578 /* Gets the lens and clipping values from a camera of lamp type object */
579 static void object_view_settings(Object *ob, float *lens, float *clipsta, float *clipend)
580 {       
581         if (!ob) return;
582         
583         if(ob->type==OB_LAMP ) {
584                 Lamp *la = ob->data;
585                 if (lens) {
586                         float x1, fac;
587                         fac= cos( M_PI*la->spotsize/360.0);
588                         x1= saacos(fac);
589                         *lens= 16.0*fac/sin(x1);
590                 }
591                 if (clipsta)    *clipsta= la->clipsta;
592                 if (clipend)    *clipend= la->clipend;
593         }
594         else if(ob->type==OB_CAMERA) {
595                 Camera *cam= ob->data;
596                 if (lens)               *lens= cam->lens;
597                 if (clipsta)    *clipsta= cam->clipsta;
598                 if (clipend)    *clipend= cam->clipend;
599         }
600 }
601
602
603 /* Gets the view trasnformation from a camera
604 * currently dosnt take camzoom into account
605
606 * The dist is not modified for this function, if NULL its assimed zero
607 * */
608 void view_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens)
609 {       
610         float bmat[4][4];
611         float imat[4][4];
612         float tmat[3][3];
613         
614         if (!ob) return;
615         
616         /* Offset */
617         if (ofs) {
618                 where_is_object(ob);
619                 VECCOPY(ofs, ob->obmat[3]);
620                 VecMulf(ofs, -1.0f); /*flip the vector*/
621         }
622         
623         /* Quat */
624         if (quat) {
625                 Mat4CpyMat4(bmat, ob->obmat);
626                 Mat4Ortho(bmat);
627                 Mat4Invert(imat, bmat);
628                 Mat3CpyMat4(tmat, imat);
629                 Mat3ToQuat(tmat, quat);
630         }
631         
632         if (dist) {
633                 float vec[3];
634                 Mat3CpyMat4(tmat, ob->obmat);
635                 
636                 vec[0]= vec[1] = 0.0;
637                 vec[2]= -(*dist);
638                 Mat3MulVecfl(tmat, vec);
639                 VecSubf(ofs, ofs, vec);
640         }
641         
642         /* Lens */
643         if (lens)
644                 object_view_settings(ob, lens, NULL, NULL);
645 }
646
647
648 void obmat_to_viewmat(View3D *v3d, Object *ob, short smooth)
649 {
650         float bmat[4][4];
651         float tmat[3][3];
652         
653         v3d->view= 0; /* dont show the grid */
654         
655         Mat4CpyMat4(bmat, ob->obmat);
656         Mat4Ortho(bmat);
657         Mat4Invert(v3d->viewmat, bmat);
658         
659         /* view quat calculation, needed for add object */
660         Mat3CpyMat4(tmat, v3d->viewmat);
661         if (smooth) {
662                 float new_quat[4];
663                 if (v3d->persp==V3D_CAMOB && v3d->camera) {
664                         /* were from a camera view */
665                         
666                         float orig_ofs[3];
667                         float orig_dist= v3d->dist;
668                         float orig_lens= v3d->lens;
669                         VECCOPY(orig_ofs, v3d->ofs);
670                         
671                         /* Switch from camera view */
672                         Mat3ToQuat(tmat, new_quat);
673                         
674                         v3d->persp=V3D_PERSP;
675                         v3d->dist= 0.0;
676                         
677                         view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens);
678                         smooth_view(v3d, orig_ofs, new_quat, &orig_dist, &orig_lens);
679                         
680                         v3d->persp=V3D_CAMOB; /* just to be polite, not needed */
681                         
682                 } else {
683                         Mat3ToQuat(tmat, new_quat);
684                         smooth_view(v3d, NULL, new_quat, NULL, NULL);
685                 }
686         } else {
687                 Mat3ToQuat(tmat, v3d->viewquat);
688         }
689 }
690
691 /* dont set windows active in in here, is used by renderwin too */
692 void setviewmatrixview3d(View3D *v3d)
693 {
694         if(v3d->persp==V3D_CAMOB) {         /* obs/camera */
695                 if(v3d->camera) {
696                         where_is_object(v3d->camera);   
697                         obmat_to_viewmat(v3d, v3d->camera, 0);
698                 }
699                 else {
700                         QuatToMat4(v3d->viewquat, v3d->viewmat);
701                         v3d->viewmat[3][2]-= v3d->dist;
702                 }
703         }
704         else {
705                 
706                 QuatToMat4(v3d->viewquat, v3d->viewmat);
707                 if(v3d->persp==V3D_PERSP) v3d->viewmat[3][2]-= v3d->dist;
708                 if(v3d->ob_centre) {
709                         Object *ob= v3d->ob_centre;
710                         float vec[3];
711                         
712                         VECCOPY(vec, ob->obmat[3]);
713                         if(ob->type==OB_ARMATURE && v3d->ob_centre_bone[0]) {
714                                 bPoseChannel *pchan= get_pose_channel(ob->pose, v3d->ob_centre_bone);
715                                 if(pchan) {
716                                         VECCOPY(vec, pchan->pose_mat[3]);
717                                         Mat4MulVecfl(ob->obmat, vec);
718                                 }
719                         }
720                         i_translate(-vec[0], -vec[1], -vec[2], v3d->viewmat);
721                 }
722                 else i_translate(v3d->ofs[0], v3d->ofs[1], v3d->ofs[2], v3d->viewmat);
723         }
724 }
725
726 void setcameratoview3d(View3D *v3d)
727 {
728         Object *ob;
729         float dvec[3];
730         
731         ob= v3d->camera;
732         dvec[0]= v3d->dist*v3d->viewinv[2][0];
733         dvec[1]= v3d->dist*v3d->viewinv[2][1];
734         dvec[2]= v3d->dist*v3d->viewinv[2][2];                                  
735         VECCOPY(ob->loc, dvec);
736         VecSubf(ob->loc, ob->loc, v3d->ofs);
737         v3d->viewquat[0]= -v3d->viewquat[0];
738         /*  */
739         /*if (ob->transflag & OB_QUAT) {
740                 QUATCOPY(ob->quat, v3d->viewquat);
741         } else {*/
742         QuatToEul(v3d->viewquat, ob->rot);
743         /*}*/
744         v3d->viewquat[0]= -v3d->viewquat[0];
745 }
746
747
748 /* IGLuint-> GLuint*/
749 /* Warning: be sure to account for a negative return value
750 *   This is an error, "Too many objects in select buffer"
751 *   and no action should be taken (can crash blender) if this happens
752 */
753 short view3d_opengl_select(Scene *scene, ARegion *ar, View3D *v3d, unsigned int *buffer, unsigned int bufsize, rcti *input)
754 {
755         rctf rect;
756         short code, hits;
757         
758         G.f |= G_PICKSEL;
759         
760         /* case not a border select */
761         if(input->xmin==input->xmax) {
762                 rect.xmin= input->xmin-12;      // seems to be default value for bones only now
763                 rect.xmax= input->xmin+12;
764                 rect.ymin= input->ymin-12;
765                 rect.ymax= input->xmin+12;
766         }
767         else {
768                 rect.xmin= input->xmin;
769                 rect.xmax= input->xmax;
770                 rect.ymin= input->ymin;
771                 rect.ymax= input->ymax;
772         }
773         
774         setwinmatrixview3d(v3d, ar->winx, ar->winy, &rect);
775         Mat4MulMat4(v3d->persmat, v3d->viewmat, v3d->winmat);
776         
777         if(v3d->drawtype > OB_WIRE) {
778                 v3d->zbuf= TRUE;
779                 glEnable(GL_DEPTH_TEST);
780         }
781         
782         if(v3d->flag & V3D_CLIPPING)
783                 view3d_set_clipping(v3d);
784         
785         glSelectBuffer( bufsize, (GLuint *)buffer);
786         glRenderMode(GL_SELECT);
787         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
788         glPushName(-1);
789         code= 1;
790         
791         if(G.obedit && G.obedit->type==OB_MBALL) {
792                 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
793         }
794         else if ((G.obedit && G.obedit->type==OB_ARMATURE)) {
795                 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
796         }
797         else {
798                 Base *base;
799                 
800                 v3d->xray= TRUE;        // otherwise it postpones drawing
801                 for(base= scene->base.first; base; base= base->next) {
802                         if(base->lay & v3d->lay) {
803                                 
804                                 if (base->object->restrictflag & OB_RESTRICT_SELECT)
805                                         base->selcol= 0;
806                                 else {
807                                         base->selcol= code;
808                                         glLoadName(code);
809                                         draw_object(scene, ar, v3d, base, DRAW_PICKING|DRAW_CONSTCOLOR);
810                                         
811                                         /* we draw group-duplicators for selection too */
812                                         if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
813                                                 ListBase *lb;
814                                                 DupliObject *dob;
815                                                 Base tbase;
816                                                 
817                                                 tbase.flag= OB_FROMDUPLI;
818                                                 lb= object_duplilist(scene, base->object);
819                                                 
820                                                 for(dob= lb->first; dob; dob= dob->next) {
821                                                         tbase.object= dob->ob;
822                                                         Mat4CpyMat4(dob->ob->obmat, dob->mat);
823                                                         
824                                                         draw_object(scene, ar, v3d, &tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
825                                                         
826                                                         Mat4CpyMat4(dob->ob->obmat, dob->omat);
827                                                 }
828                                                 free_object_duplilist(lb);
829                                         }
830                                         code++;
831                                 }                               
832                         }
833                 }
834                 v3d->xray= FALSE;       // restore
835         }
836         
837         glPopName();    /* see above (pushname) */
838         hits= glRenderMode(GL_RENDER);
839         
840         G.f &= ~G_PICKSEL;
841         setwinmatrixview3d(v3d, ar->winx, ar->winy, NULL);
842         Mat4MulMat4(v3d->persmat, v3d->viewmat, v3d->winmat);
843         
844         if(v3d->drawtype > OB_WIRE) {
845                 v3d->zbuf= 0;
846                 glDisable(GL_DEPTH_TEST);
847         }
848 // XXX  persp(PERSP_WIN);
849         
850         if(v3d->flag & V3D_CLIPPING)
851                 view3d_clr_clipping();
852         
853         if(hits<0) printf("Too many objects in select buffer\n");       // XXX make error message
854         
855         return hits;
856 }
857
858 // XXX solve: localview on region level? no.... layers are area, so all regions in area have to be set
859 static unsigned int free_localbit(void)
860 {
861         unsigned int lay;
862         ScrArea *sa;
863         bScreen *sc;
864         
865         lay= 0;
866         
867         /* sometimes we loose a localview: when an area is closed */
868         /* check all areas: which localviews are in use? */
869         for(sc= G.main->screen.first; sc; sc= sc->id.next) {
870                 for(sa= sc->areabase.first; sa; sa= sa->next) {
871                         SpaceLink *sl= sa->spacedata.first;
872                         for(; sl; sl= sl->next) {
873                                 if(sl->spacetype==SPACE_VIEW3D) {
874                                         View3D *v3d= (View3D*) sl;
875                                         lay |= v3d->lay;
876                                 }
877                         }
878                 }
879         }
880         
881         if( (lay & 0x01000000)==0) return 0x01000000;
882         if( (lay & 0x02000000)==0) return 0x02000000;
883         if( (lay & 0x04000000)==0) return 0x04000000;
884         if( (lay & 0x08000000)==0) return 0x08000000;
885         if( (lay & 0x10000000)==0) return 0x10000000;
886         if( (lay & 0x20000000)==0) return 0x20000000;
887         if( (lay & 0x40000000)==0) return 0x40000000;
888         if( (lay & 0x80000000)==0) return 0x80000000;
889         
890         return 0;
891 }
892
893
894 void initlocalview(Scene *scene, ARegion *ar, View3D *v3d)
895 {
896         Base *base;
897         float size = 0.0, min[3], max[3], afm[3];
898         unsigned int locallay;
899         int ok=0;
900
901         if(v3d->localvd) return;
902
903         INIT_MINMAX(min, max);
904
905         locallay= free_localbit();
906
907         if(locallay==0) {
908                 printf("Sorry,  no more than 8 localviews\n");  // XXX error 
909                 ok= 0;
910         }
911         else {
912                 if(G.obedit) {
913                         minmax_object(G.obedit, min, max);
914                         
915                         ok= 1;
916                 
917                         BASACT->lay |= locallay;
918                         G.obedit->lay= BASACT->lay;
919                 }
920                 else {
921                         base= FIRSTBASE;
922                         while(base) {
923                                 if(TESTBASE(v3d, base))  {
924                                         minmax_object(base->object, min, max);
925                                         base->lay |= locallay;
926                                         base->object->lay= base->lay;
927                                         ok= 1;
928                                 }
929                                 base= base->next;
930                         }
931                 }
932                 
933                 afm[0]= (max[0]-min[0]);
934                 afm[1]= (max[1]-min[1]);
935                 afm[2]= (max[2]-min[2]);
936                 size= 0.7*MAX3(afm[0], afm[1], afm[2]);
937                 if(size<=0.01) size= 0.01;
938         }
939         
940         if(ok) {
941                 v3d->localvd= MEM_mallocN(sizeof(View3D), "localview");
942                 memcpy(v3d->localvd, v3d, sizeof(View3D));
943
944                 v3d->ofs[0]= -(min[0]+max[0])/2.0;
945                 v3d->ofs[1]= -(min[1]+max[1])/2.0;
946                 v3d->ofs[2]= -(min[2]+max[2])/2.0;
947
948                 v3d->dist= size;
949
950                 // correction for window aspect ratio
951                 if(ar->winy>2 && ar->winx>2) {
952                         size= (float)ar->winx/(float)ar->winy;
953                         if(size<1.0) size= 1.0/size;
954                         v3d->dist*= size;
955                 }
956                 
957                 if (v3d->persp==V3D_CAMOB) v3d->persp= V3D_PERSP;
958                 if (v3d->near> 0.1) v3d->near= 0.1;
959                 
960                 v3d->cursor[0]= -v3d->ofs[0];
961                 v3d->cursor[1]= -v3d->ofs[1];
962                 v3d->cursor[2]= -v3d->ofs[2];
963
964                 v3d->lay= locallay;
965                 
966 // XXX          countall();
967 // XXX          scrarea_queue_winredraw(curarea);
968         }
969         else {
970                 /* clear flags */ 
971                 base= FIRSTBASE;
972                 while(base) {
973                         if( base->lay & locallay ) {
974                                 base->lay-= locallay;
975                                 if(base->lay==0) base->lay= v3d->layact;
976                                 if(base->object != G.obedit) base->flag |= SELECT;
977                                 base->object->lay= base->lay;
978                         }
979                         base= base->next;
980                 }
981 // XXX          scrarea_queue_headredraw(curarea);
982                 
983                 v3d->localview= 0;
984         }
985 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
986 }
987
988 void restore_localviewdata(View3D *vd)
989 {
990         if(vd->localvd==0) return;
991         
992         VECCOPY(vd->ofs, vd->localvd->ofs);
993         vd->dist= vd->localvd->dist;
994         vd->persp= vd->localvd->persp;
995         vd->view= vd->localvd->view;
996         vd->near= vd->localvd->near;
997         vd->far= vd->localvd->far;
998         vd->lay= vd->localvd->lay;
999         vd->layact= vd->localvd->layact;
1000         vd->drawtype= vd->localvd->drawtype;
1001         vd->camera= vd->localvd->camera;
1002         QUATCOPY(vd->viewquat, vd->localvd->viewquat);
1003         
1004 }
1005
1006 void endlocalview(Scene *scene, ScrArea *sa)
1007 {
1008         View3D *v3d;
1009         struct Base *base;
1010         unsigned int locallay;
1011         
1012         if(sa->spacetype!=SPACE_VIEW3D) return;
1013         v3d= sa->spacedata.first;
1014         
1015         if(v3d->localvd) {
1016                 
1017                 locallay= v3d->lay & 0xFF000000;
1018                 
1019                 restore_localviewdata(v3d);
1020                 
1021                 MEM_freeN(v3d->localvd);
1022                 v3d->localvd= 0;
1023                 v3d->localview= 0;
1024
1025                 /* for when in other window the layers have changed */
1026                 if(v3d->scenelock) v3d->lay= scene->lay;
1027                 
1028                 base= FIRSTBASE;
1029                 while(base) {
1030                         if( base->lay & locallay ) {
1031                                 base->lay-= locallay;
1032                                 if(base->lay==0) base->lay= v3d->layact;
1033                                 if(base->object != G.obedit) {
1034                                         base->flag |= SELECT;
1035                                         base->object->flag |= SELECT;
1036                                 }
1037                                 base->object->lay= base->lay;
1038                         }
1039                         base= base->next;
1040                 }
1041
1042 // XXX          countall();
1043 // XXX          allqueue(REDRAWVIEW3D, 0);      /* because of select */
1044 // XXX          allqueue(REDRAWOOPS, 0);        /* because of select */
1045 // XXX          BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1046         } 
1047 }
1048
1049 void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3])
1050 {
1051         float alignaxis[3] = {0.0, 0.0, 0.0};
1052         float norm[3], axis[3], angle, new_quat[4];
1053         
1054         if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
1055         else alignaxis[-axisidx-1]= -1.0;
1056         
1057         VECCOPY(norm, vec);
1058         Normalize(norm);
1059         
1060         angle= (float)acos(Inpf(alignaxis, norm));
1061         Crossf(axis, alignaxis, norm);
1062         VecRotToQuat(axis, -angle, new_quat);
1063         
1064         v3d->view= 0;
1065         
1066         if (v3d->persp==V3D_CAMOB && v3d->camera) {
1067                 /* switch out of camera view */
1068                 float orig_ofs[3];
1069                 float orig_dist= v3d->dist;
1070                 float orig_lens= v3d->lens;
1071                 
1072                 VECCOPY(orig_ofs, v3d->ofs);
1073                 v3d->persp= V3D_PERSP;
1074                 v3d->dist= 0.0;
1075                 view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens);
1076                 smooth_view(v3d, orig_ofs, new_quat, &orig_dist, &orig_lens);
1077         } else {
1078                 if (v3d->persp==V3D_CAMOB) v3d->persp= V3D_PERSP; /* switch out of camera mode */
1079                 smooth_view(v3d, NULL, new_quat, NULL, NULL);
1080         }
1081 }
1082
1083
1084
1085 /* SMOOTHVIEW */
1086 void smooth_view(View3D *v3d, float *ofs, float *quat, float *dist, float *lens)
1087 {
1088         /* View Animation enabled */
1089         if (U.smooth_viewtx) {
1090                 int i;
1091                 char changed = 0;
1092                 float step = 0.0, step_inv;
1093                 float orig_dist;
1094                 float orig_lens;
1095                 float orig_quat[4];
1096                 float orig_ofs[3];
1097                 
1098                 double time_allowed, time_current, time_start;
1099                 
1100                 /* if there is no difference, return */
1101                 changed = 0; /* zero means no difference */
1102                 if (dist) {
1103                         if ((*dist) != v3d->dist)
1104                                 changed = 1;
1105                 }
1106                 
1107                 if (lens) {
1108                         if ((*lens) != v3d->lens)
1109                                 changed = 1;
1110                 }
1111                 
1112                 if (!changed && ofs) {
1113                         if ((ofs[0]!=v3d->ofs[0]) ||
1114                                 (ofs[1]!=v3d->ofs[1]) ||
1115                                 (ofs[2]!=v3d->ofs[2]) )
1116                                 changed = 1;
1117                 }
1118                 
1119                 if (!changed && quat ) {
1120                         if ((quat[0]!=v3d->viewquat[0]) ||
1121                                 (quat[1]!=v3d->viewquat[1]) ||
1122                                 (quat[2]!=v3d->viewquat[2]) ||
1123                                 (quat[3]!=v3d->viewquat[3]) )
1124                                 changed = 1;
1125                 }
1126                 
1127                 /* The new view is different from the old one
1128                         * so animate the view */
1129                 if (changed) {
1130                         
1131                         /* store original values */
1132                         VECCOPY(orig_ofs,       v3d->ofs);
1133                         QUATCOPY(orig_quat,     v3d->viewquat);
1134                         orig_dist =                     v3d->dist;
1135                         orig_lens =                     v3d->lens;
1136                         
1137                         time_allowed= (float)U.smooth_viewtx / 1000.0;
1138                         time_current = time_start = PIL_check_seconds_timer();
1139                         
1140                         /* if this is view rotation only
1141                                 * we can decrease the time allowed by
1142                                 * the angle between quats 
1143                                 * this means small rotations wont lag */
1144                         if (quat && !ofs && !dist) {
1145                                 float vec1[3], vec2[3];
1146                                 VECCOPY(vec1, quat);
1147                                 VECCOPY(vec2, v3d->viewquat);
1148                                 Normalize(vec1);
1149                                 Normalize(vec2);
1150                                 /* scale the time allowed by the rotation */
1151                                 time_allowed *= NormalizedVecAngle2(vec1, vec2)/(M_PI/2); 
1152                         }
1153                         
1154                         while (time_start + time_allowed > time_current) {
1155                                 
1156                                 step =  (float)((time_current-time_start) / time_allowed);
1157                                 
1158                                 /* ease in/out */
1159                                 if (step < 0.5) step = (float)pow(step*2, 2)/2;
1160                                 else                    step = (float)1-(pow(2*(1-step),2)/2);
1161                                 
1162                                 step_inv = 1-step;
1163                                 
1164                                 if (ofs)
1165                                         for (i=0; i<3; i++)
1166                                                 v3d->ofs[i] = ofs[i]*step + orig_ofs[i]*step_inv;
1167                                 
1168                                 
1169                                 if (quat)
1170                                         QuatInterpol(v3d->viewquat, orig_quat, quat, step);
1171                                 
1172                                 if (dist)
1173                                         v3d->dist = ((*dist)*step) + (orig_dist*step_inv);
1174                                 
1175                                 if (lens)
1176                                         v3d->lens = ((*lens)*step) + (orig_lens*step_inv);
1177                                 
1178                                 /*redraw the view*/
1179                                 //                              scrarea_do_windraw(ar);
1180                                 //                              screen_swapbuffers();
1181                                 
1182                                 time_current= PIL_check_seconds_timer();
1183                         }
1184                 }
1185         }
1186         
1187         /* set these values even if animation is enabled because flaot
1188         * error will make then not quite accurate */
1189         if (ofs)
1190                 VECCOPY(v3d->ofs, ofs);
1191         if (quat)
1192                 QUATCOPY(v3d->viewquat, quat);
1193         if (dist)
1194                 v3d->dist = *dist;
1195         if (lens)
1196                 v3d->lens = *lens;
1197         
1198 }
1199
1200 /* For use with smooth view
1201
1202 * the current view is unchanged, blend between the current view and the
1203 * camera view
1204 * */
1205 void smooth_view_to_camera(View3D *v3d)
1206 {
1207         if (!U.smooth_viewtx || !v3d->camera || v3d->persp != V3D_CAMOB) {
1208                 return;
1209         } else {
1210                 Object *ob = v3d->camera;
1211                 
1212                 float orig_ofs[3];
1213                 float orig_dist=v3d->dist;
1214                 float orig_lens=v3d->lens;
1215                 float new_dist=0.0;
1216                 float new_lens=35.0;
1217                 float new_quat[4];
1218                 float new_ofs[3];
1219                 
1220                 VECCOPY(orig_ofs, v3d->ofs);
1221                 
1222                 view_settings_from_ob(ob, new_ofs, new_quat, NULL, &new_lens);
1223                 
1224                 v3d->persp= V3D_PERSP;
1225                 smooth_view(v3d, new_ofs, new_quat, &new_dist, &new_lens);
1226                 VECCOPY(v3d->ofs, orig_ofs);
1227                 v3d->lens= orig_lens;
1228                 v3d->dist = orig_dist; /* restore the dist */
1229                 
1230                 v3d->camera = ob;
1231                 v3d->persp= V3D_CAMOB;
1232         }
1233 }
1234
1235