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