4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
20 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21 * All rights reserved.
23 * Trackball math (in calctrackballvec()) Copyright (C) Silicon Graphics, Inc.
25 * The Original Code is: all of this file.
27 * Contributor(s): none yet.
29 * ***** END GPL LICENSE BLOCK *****
45 #include "MEM_guardedalloc.h"
47 #include "BLI_blenlib.h"
48 #include "BLI_arithb.h"
50 #include "DNA_action_types.h"
51 #include "DNA_armature_types.h"
52 #include "DNA_camera_types.h"
53 #include "DNA_lamp_types.h"
54 #include "DNA_object_types.h"
55 #include "DNA_screen_types.h"
56 #include "DNA_scene_types.h"
57 #include "DNA_space_types.h"
58 #include "DNA_userdef_types.h"
59 #include "DNA_view3d_types.h"
61 #include "BKE_action.h"
63 #include "BKE_global.h"
65 #include "BKE_object.h"
66 #include "BKE_sculpt.h"
67 #include "BKE_utildefines.h"
69 #include "BIF_transform.h"
70 #include "BIF_editparticle.h"
72 #include "BIF_previewrender.h"
73 #include "BIF_mywindow.h"
74 #include "BIF_retopo.h"
75 #include "BIF_space.h"
76 #include "BIF_screen.h"
77 #include "BIF_toolbox.h"
78 #include "BIF_sketch.h"
81 #include "BSE_edit.h" /* For countall */
82 #include "BSE_drawview.h" /* For inner_play_anim_loop */
84 #include "BDR_drawobject.h" /* For draw_object */
85 #include "BDR_editface.h" /* For minmax_tface */
86 #include "BDR_sculptmode.h"
87 #include "BDR_sketch.h"
91 #include "transform.h"
93 #include "PIL_time.h" /* smoothview */
96 #define TRACKBALLSIZE (1.1)
97 #define BL_NEAR_CLIP 0.001
99 #define COS45 0.70710678118654746
103 /* local prototypes ----------*/
104 void setcameratoview3d(void); /* windows.c & toets.c */
106 void persp_general(int a)
108 /* for all window types, not 3D */
112 glMatrixMode(GL_PROJECTION);
114 glMatrixMode(GL_MODELVIEW);
116 myortho2(-0.375f, ((float)(curarea->winx))-0.375f, -0.375f, ((float)(curarea->winy))-0.375f);
120 glMatrixMode(GL_PROJECTION);
122 glMatrixMode(GL_MODELVIEW);
129 /* only 3D windows */
131 if(curarea->spacetype!=SPACE_VIEW3D) persp_general(a);
132 else if(a == PERSP_STORE) { // only store
133 glMatrixMode(GL_PROJECTION);
134 mygetmatrix(G.vd->winmat1);
135 glMatrixMode(GL_MODELVIEW);
136 mygetmatrix(G.vd->viewmat1);
138 else if(a== PERSP_WIN) { // only set
139 myortho2(-0.375f, (float)(curarea->winx)-0.375f, -0.375f, (float)(curarea->winy)-0.375f);
142 else if(a== PERSP_VIEW) {
143 glMatrixMode(GL_PROJECTION);
144 myloadmatrix(G.vd->winmat1); // put back
145 Mat4CpyMat4(curarea->winmat, G.vd->winmat1); // to be sure?
146 glMatrixMode(GL_MODELVIEW);
147 myloadmatrix(G.vd->viewmat); // put back
152 /* create intersection ray in view Z direction at mouse coordinates */
153 void viewray(short mval[2], float ray_start[3], float ray_normal[3])
156 viewline(mval, ray_start, ray_end);
157 VecSubf(ray_normal, ray_end, ray_start);
158 Normalize(ray_normal);
161 /* create intersection coordinates in view Z direction at mouse coordinates */
162 void viewline(short mval[2], float ray_start[3], float ray_end[3])
166 if(G.vd->persp != V3D_ORTHO){
167 vec[0]= 2.0f * mval[0] / curarea->winx - 1;
168 vec[1]= 2.0f * mval[1] / curarea->winy - 1;
172 Mat4MulVec4fl(G.vd->persinv, vec);
173 VecMulf(vec, 1.0f / vec[3]);
175 VECCOPY(ray_start, G.vd->viewinv[3]);
176 VECSUB(vec, vec, ray_start);
179 VECADDFAC(ray_start, G.vd->viewinv[3], vec, G.vd->near);
180 VECADDFAC(ray_end, G.vd->viewinv[3], vec, G.vd->far);
183 vec[0] = 2.0f * mval[0] / curarea->winx - 1;
184 vec[1] = 2.0f * mval[1] / curarea->winy - 1;
188 Mat4MulVec4fl(G.vd->persinv, vec);
190 VECADDFAC(ray_start, vec, G.vd->viewinv[2], 1000.0f);
191 VECADDFAC(ray_end, vec, G.vd->viewinv[2], -1000.0f);
195 void initgrabz(float x, float y, float z)
197 if(G.vd==NULL) return;
198 G.vd->zfac= G.vd->persmat[0][3]*x+ G.vd->persmat[1][3]*y+ G.vd->persmat[2][3]*z+ G.vd->persmat[3][3];
200 /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that
201 * (accounting for near zero values)
203 if (G.vd->zfac < 1.e-6f && G.vd->zfac > -1.e-6f) G.vd->zfac = 1.0f;
205 /* Negative zfac means x, y, z was behind the camera (in perspective).
206 * This gives flipped directions, so revert back to ok default case.
208 if (G.vd->zfac < 0.0f) G.vd->zfac = 1.0f;
211 void window_to_3d(float *vec, short mx, short my)
213 /* always call initgrabz */
216 dx= 2.0f*mx*G.vd->zfac/curarea->winx;
217 dy= 2.0f*my*G.vd->zfac/curarea->winy;
219 vec[0]= (G.vd->persinv[0][0]*dx + G.vd->persinv[1][0]*dy);
220 vec[1]= (G.vd->persinv[0][1]*dx + G.vd->persinv[1][1]*dy);
221 vec[2]= (G.vd->persinv[0][2]*dx + G.vd->persinv[1][2]*dy);
224 void project_short(float *vec, short *adr) /* clips */
226 float fx, fy, vec4[4];
230 if(G.vd->flag & V3D_CLIPPING) {
231 if(view3d_test_clipping(G.vd, vec))
237 Mat4MulVec4fl(G.vd->persmat, vec4);
239 if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
240 fx= (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
242 if( fx>0 && fx<curarea->winx) {
244 fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
246 if(fy>0.0 && fy< (float)curarea->winy) {
247 adr[0]= (short)floor(fx);
248 adr[1]= (short)floor(fy);
254 void project_int(float *vec, int *adr)
256 float fx, fy, vec4[4];
258 adr[0]= (int)2140000000.0f;
262 Mat4MulVec4fl(G.vd->persmat, vec4);
264 if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
265 fx= (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
267 if( fx>-2140000000.0f && fx<2140000000.0f) {
268 fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
270 if(fy>-2140000000.0f && fy<2140000000.0f) {
271 adr[0]= (int)floor(fx);
272 adr[1]= (int)floor(fy);
278 void project_int_noclip(float *vec, int *adr)
280 float fx, fy, vec4[4];
285 Mat4MulVec4fl(G.vd->persmat, vec4);
287 if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
288 fx = (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
289 fy = (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
291 adr[0] = (int)floor(fx);
292 adr[1] = (int)floor(fy);
296 adr[0] = curarea->winx / 2;
297 adr[1] = curarea->winy / 2;
301 void project_short_noclip(float *vec, short *adr)
303 float fx, fy, vec4[4];
309 Mat4MulVec4fl(G.vd->persmat, vec4);
311 if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
312 fx= (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
314 if( fx>-32700 && fx<32700) {
316 fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
318 if(fy>-32700.0 && fy<32700.0) {
319 adr[0]= (short)floor(fx);
320 adr[1]= (short)floor(fy);
326 void project_float(float *vec, float *adr)
334 Mat4MulVec4fl(G.vd->persmat, vec4);
336 if( vec4[3]>BL_NEAR_CLIP ) {
337 adr[0] = (float)(curarea->winx/2.0)+(curarea->winx/2.0)*vec4[0]/vec4[3];
338 adr[1] = (float)(curarea->winy/2.0)+(curarea->winy/2.0)*vec4[1]/vec4[3];
342 void project_float_noclip(float *vec, float *adr)
349 Mat4MulVec4fl(G.vd->persmat, vec4);
351 if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
352 adr[0] = (float)(curarea->winx/2.0)+(curarea->winx/2.0)*vec4[0]/vec4[3];
353 adr[1] = (float)(curarea->winy/2.0)+(curarea->winy/2.0)*vec4[1]/vec4[3];
357 adr[0] = curarea->winx / 2.0f;
358 adr[1] = curarea->winy / 2.0f;
362 void view3d_get_object_project_mat(ScrArea *area, Object *ob, float pmat[4][4], float vmat[4][4])
364 if (area->spacetype!=SPACE_VIEW3D || !area->spacedata.first) {
368 View3D *vd = area->spacedata.first;
370 Mat4MulMat4(vmat, ob->obmat, vd->viewmat);
371 Mat4MulMat4(pmat, vmat, vd->winmat1);
372 Mat4CpyMat4(vmat, ob->obmat);
376 /* projectmat brings it to window coords, wmat to rotated world space */
377 void view3d_project_short_clip(ScrArea *area, float *vec, short *adr, float projmat[4][4], float wmat[4][4])
379 View3D *v3d= area->spacedata.first;
380 float fx, fy, vec4[4];
384 /* clipplanes in eye space */
385 if(v3d->flag & V3D_CLIPPING) {
387 Mat4MulVecfl(wmat, vec4);
388 if(view3d_test_clipping(v3d, vec4))
395 Mat4MulVec4fl(projmat, vec4);
397 /* clipplanes in window space */
398 if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
399 fx= (area->winx/2)*(1 + vec4[0]/vec4[3]);
401 if( fx>0 && fx<area->winx) {
403 fy= (area->winy/2)*(1 + vec4[1]/vec4[3]);
405 if(fy>0.0 && fy< (float)area->winy) {
406 adr[0]= (short)floor(fx);
407 adr[1]= (short)floor(fy);
413 void view3d_project_short_noclip(ScrArea *area, float *vec, short *adr, float mat[4][4])
415 float fx, fy, vec4[4];
422 Mat4MulVec4fl(mat, vec4);
424 if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
425 fx= (area->winx/2)*(1 + vec4[0]/vec4[3]);
427 if( fx>-32700 && fx<32700) {
429 fy= (area->winy/2)*(1 + vec4[1]/vec4[3]);
431 if(fy>-32700.0 && fy<32700.0) {
432 adr[0]= (short)floor(fx);
433 adr[1]= (short)floor(fy);
439 void view3d_project_float(ScrArea *area, float *vec, float *adr, float mat[4][4])
447 Mat4MulVec4fl(mat, vec4);
449 if( vec4[3]>FLT_EPSILON ) {
450 adr[0] = (float)(area->winx/2.0f)+(area->winx/2.0f)*vec4[0]/vec4[3];
451 adr[1] = (float)(area->winy/2.0f)+(area->winy/2.0f)*vec4[1]/vec4[3];
453 adr[0] = adr[1] = 0.0f;
457 int boundbox_clip(float obmat[][4], BoundBox *bb)
462 float vec[4], min, max;
465 if(bb==NULL) return 1;
466 if(bb->flag & OB_BB_DISABLED) return 1;
468 Mat4MulMat4(mat, obmat, G.vd->persmat);
471 VECCOPY(vec, bb->vec[a]);
473 Mat4MulVec4fl(mat, vec);
478 if(vec[0] < min) fl+= 1;
479 if(vec[0] > max) fl+= 2;
480 if(vec[1] < min) fl+= 4;
481 if(vec[1] > max) fl+= 8;
482 if(vec[2] < min) fl+= 16;
483 if(vec[2] > max) fl+= 32;
486 if(flag==0) return 1;
493 void fdrawline(float x1, float y1, float x2, float y2)
497 glBegin(GL_LINE_STRIP);
498 v[0] = x1; v[1] = y1;
500 v[0] = x2; v[1] = y2;
505 void fdrawbox(float x1, float y1, float x2, float y2)
509 glBegin(GL_LINE_STRIP);
511 v[0] = x1; v[1] = y1;
513 v[0] = x1; v[1] = y2;
515 v[0] = x2; v[1] = y2;
517 v[0] = x2; v[1] = y1;
519 v[0] = x1; v[1] = y1;
525 void sdrawline(short x1, short y1, short x2, short y2)
529 glBegin(GL_LINE_STRIP);
530 v[0] = x1; v[1] = y1;
532 v[0] = x2; v[1] = y2;
537 void sdrawbox(short x1, short y1, short x2, short y2)
541 glBegin(GL_LINE_STRIP);
543 v[0] = x1; v[1] = y1;
545 v[0] = x1; v[1] = y2;
547 v[0] = x2; v[1] = y2;
549 v[0] = x2; v[1] = y1;
551 v[0] = x1; v[1] = y1;
557 /* the central math in this function was copied from trackball.cpp, sample code from the
558 Developers Toolbox series by SGI. */
560 /* trackball: better one than a full spherical solution */
562 void calctrackballvecfirst(rcti *area, short *mval, float *vec)
564 float x, y, radius, d, z, t;
566 radius= TRACKBALLSIZE;
568 /* normalize x and y */
569 x= (area->xmax + area->xmin)/2 -mval[0];
570 x/= (float)((area->xmax - area->xmin)/2);
571 y= (area->ymax + area->ymin)/2 -mval[1];
572 y/= (float)((area->ymax - area->ymin)/2);
575 if (d < radius*M_SQRT1_2) /* Inside sphere */
576 z = sqrt(radius*radius - d*d);
579 t = radius / M_SQRT2;
585 vec[2]= -z; /* yah yah! */
587 if( fabs(vec[2])>fabs(vec[1]) && fabs(vec[2])>fabs(vec[0]) ) {
590 if(vec[2]>0.0) vec[2]= 1.0; else vec[2]= -1.0;
592 else if( fabs(vec[1])>fabs(vec[0]) && fabs(vec[1])>fabs(vec[2]) ) {
595 if(vec[1]>0.0) vec[1]= 1.0; else vec[1]= -1.0;
600 if(vec[0]>0.0) vec[0]= 1.0; else vec[0]= -1.0;
604 void calctrackballvec(rcti *area, short *mval, float *vec)
606 float x, y, radius, d, z, t;
608 radius= TRACKBALLSIZE;
610 /* x en y normalizeren */
611 x= (area->xmax + area->xmin)/2 -mval[0];
612 x/= (float)((area->xmax - area->xmin)/4);
613 y= (area->ymax + area->ymin)/2 -mval[1];
614 y/= (float)((area->ymax - area->ymin)/2);
617 if (d < radius*M_SQRT1_2) /* Inside sphere */
618 z = sqrt(radius*radius - d*d);
621 t = radius / M_SQRT2;
627 vec[2]= -z; /* yah yah! */
632 // ndof scaling will be moved to user setting.
633 // In the mean time this is just a place holder.
635 // Note: scaling in the plugin and ghostwinlay.c
636 // should be removed. With driver default setting,
637 // each axis returns approx. +-200 max deflection.
639 // The values I selected are based on the older
640 // polling i/f. With event i/f, the sensistivity
641 // can be increased for improved response from
642 // small deflections of the device input.
645 // lukep notes : i disagree on the range.
646 // the normal 3Dconnection driver give +/-400
647 // on defaut range in other applications
648 // and up to +/- 1000 if set to maximum
649 // because i remove the scaling by delta,
650 // which was a bad idea as it depend of the system
651 // speed and os, i changed the scaling values, but
652 // those are still not ok
655 float ndof_axis_scale[6] = {
664 // statics for controlling G.vd->dist corrections.
665 // viewmoveNDOF zeros and adjusts G.vd->ofs.
666 // viewmove restores based on dz_flag state.
671 void viewmoveNDOFfly(int mode)
676 // static fval[6] for low pass filter; device input vector is dval[6]
677 static float fval[6];
678 float tvec[3],rvec[3];
684 /*----------------------------------------------------
685 * sometimes this routine is called from headerbuttons
686 * viewmove needs to refresh the screen
688 areawinset(curarea->win);
691 // fetch the current state of the ndof device
694 if (G.vd->ndoffilter)
695 filterNDOFvalues(fval);
697 // Scale input values
699 // if(dval[6] == 0) return; // guard against divide by zero
704 dval[i] = dval[i] * ndof_axis_scale[i];
708 // low pass filter with zero crossing reset
711 if((dval[i] * fval[i]) >= 0)
712 dval[i] = (fval[i] * 15 + dval[i]) / 16;
718 // force perspective mode. This is a hack and is
719 // incomplete. It doesn't actually effect the view
720 // until the first draw and doesn't update the menu
721 // to reflect persp mode.
723 G.vd->persp = V3D_PERSP;
726 // Correct the distance jump if G.vd->dist != 0
728 // This is due to a side effect of the original
729 // mouse view rotation code. The rotation point is
730 // set a distance in front of the viewport to
731 // make rotating with the mouse look better.
732 // The distance effect is written at a low level
733 // in the view management instead of the mouse
734 // view function. This means that all other view
735 // movement devices must subtract this from their
736 // view transformations.
738 if(G.vd->dist != 0.0) {
741 upvec[0] = upvec[1] = 0;
742 upvec[2] = G.vd->dist;
743 Mat3CpyMat4(mat, G.vd->viewinv);
744 Mat3MulVecfl(mat, upvec);
745 VecSubf(G.vd->ofs, G.vd->ofs, upvec);
751 // Rotations feel relatively faster than translations only in fly mode, so
752 // we have no choice but to fix that here (not in the plugins)
753 rvec[0] = -0.5 * dval[3];
754 rvec[1] = -0.5 * dval[4];
755 rvec[2] = -0.5 * dval[5];
757 // rotate device x and y by view z
759 Mat3CpyMat4(mat, G.vd->viewinv);
761 Mat3MulVecfl(mat, rvec);
765 phi = Normalize(rvec);
767 VecRotToQuat(rvec,phi,q1);
768 QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
778 // the next three lines rotate the x and y translation coordinates
779 // by the current z axis angle
781 Mat3CpyMat4(mat, G.vd->viewinv);
783 Mat3MulVecfl(mat, tvec);
785 // translate the view
787 VecSubf(G.vd->ofs, G.vd->ofs, tvec);
790 /*----------------------------------------------------
793 scrarea_do_windraw(curarea);
794 screen_swapbuffers();
796 // update render preview window
798 BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
801 int view_autodist( float mouse_worldloc[3] ) //, float *autodist )
805 /* Zooms in on a border drawn by the user */
809 /* ZBuffer depth vars */
811 float depth, depth_close= MAXFLOAT;
813 double cent[2], p[3];
816 getmouseco_areawin(mval);
820 rect.xmax = mval[0] + 4;
821 rect.ymax = mval[1] + 4;
823 rect.xmin = mval[0] - 4;
824 rect.ymin = mval[1] - 4;
826 /* Get Z Depths, needed for perspective, nice for ortho */
828 draw_depth(curarea, (void *)v3d, NULL);
833 v3d->depths->damaged = 1;
836 view3d_update_depths(v3d);
838 /* Constrain rect to depth bounds */
839 if (rect.xmin < 0) rect.xmin = 0;
840 if (rect.ymin < 0) rect.ymin = 0;
841 if (rect.xmax >= v3d->depths->w) rect.xmax = v3d->depths->w-1;
842 if (rect.ymax >= v3d->depths->h) rect.ymax = v3d->depths->h-1;
844 /* Find the closest Z pixel */
845 for (xs=rect.xmin; xs < rect.xmax; xs++) {
846 for (ys=rect.ymin; ys < rect.ymax; ys++) {
847 depth= v3d->depths->depths[ys*v3d->depths->w+xs];
848 if(depth < v3d->depths->depth_range[1] && depth > v3d->depths->depth_range[0]) {
849 if (depth_close > depth) {
856 if (depth_close==MAXFLOAT)
860 MEM_freeN(v3d->depths->depths);
861 v3d->depths->depths = NULL;
863 v3d->depths->damaged = 1;
865 cent[0] = (double)mval[0];
866 cent[1] = (double)mval[1];
868 if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, mats.viewport, &p[0], &p[1], &p[2]))
871 mouse_worldloc[0] = (float)p[0];
872 mouse_worldloc[1] = (float)p[1];
873 mouse_worldloc[2] = (float)p[2];
877 void viewmove(int mode)
879 static float lastofs[3] = {0,0,0};
881 float firstvec[3], newvec[3], dvec[3];
882 float reverse, oldquat[4], q1[4], si, phi, dist0;
883 float ofs[3], obofs[3]= {0.0f, 0.0f, 0.0f};
885 short mvalball[2], mval[2], mvalo[2], mval_area[2], mvali[2];
887 short preview3d_event= 1;
889 // locals for dist correction
893 /* 3D window may not be defined */
895 fprintf( stderr, "G.vd == NULL in viewmove()\n" );
899 // dist correction from other movement devices
900 if((dz_flag)||G.vd->dist==0) {
903 upvec[0] = upvec[1] = 0;
904 upvec[2] = G.vd->dist;
905 Mat3CpyMat4(mat, G.vd->viewinv);
906 Mat3MulVecfl(mat, upvec);
907 VecAddf(G.vd->ofs, G.vd->ofs, upvec);
910 /* sometimes this routine is called from headerbuttons */
912 areawinset(curarea->win);
914 QUATCOPY(oldquat, G.vd->viewquat);
916 getmouseco_areawin(mval_area); /* for zoom to mouse loc */
917 getmouseco_sc(mvali); /* work with screen coordinates because of trackball function */
918 mvalball[0]= mvalo[0] = mvali[0]; /* needed for turntable to work */
919 mvalball[1]= mvalo[1] = mvali[1];
922 calctrackballvec(&curarea->winrct, mvalo, firstvec);
926 if(!G.obedit && (G.f & G_SCULPTMODE) && ob && G.vd->pivot_last) {
928 VecCopyf(ofs, G.vd->ofs);
930 VecCopyf(obofs, sculpt_data()->pivot);
931 Mat4MulVecfl(ob->obmat, obofs);
936 else if (U.uiflag & USER_ORBIT_SELECTION) {
939 VECCOPY(ofs, G.vd->ofs);
941 /* If there's no selection, lastofs is unmodified and last value since static */
942 calculateTransformCenter(V3D_CENTROID, lastofs);
944 VECCOPY(obofs, lastofs);
945 VecMulf(obofs, -1.0f);
947 else if (U.uiflag & USER_ORBIT_ZBUF) {
948 if ((use_sel=view_autodist(obofs))) {
949 if (G.vd->persp==V3D_PERSP) {
950 float my_origin[3]; /* original G.vd->ofs */
951 float my_pivot[3]; /* view */
953 VECCOPY(my_origin, G.vd->ofs);
954 VecMulf(my_origin, -1.0f); /* ofs is flipped */
956 /* Set the dist value to be the distance from this 3d point */
957 /* this means youll always be able to zoom into it and panning wont go bad when dist was zero */
959 /* remove dist value */
960 upvec[0] = upvec[1] = 0;
961 upvec[2] = G.vd->dist;
962 Mat3CpyMat4(mat, G.vd->viewinv);
963 Mat3MulVecfl(mat, upvec);
964 VecSubf(my_pivot, G.vd->ofs, upvec);
965 VecMulf(my_pivot, -1.0f); /* ofs is flipped */
967 /* find a new ofs value that is allong the view axis (rather then the mouse location) */
968 lambda_cp_line_ex(obofs, my_pivot, my_origin, dvec);
969 dist0 = G.vd->dist = VecLenf(my_pivot, dvec);
971 VecMulf(dvec, -1.0f);
972 VECCOPY(G.vd->ofs, dvec);
974 VecMulf(obofs, -1.0f);
975 VECCOPY(ofs, G.vd->ofs);
977 ofs[0] = ofs[1] = ofs[2] = 0.0f;
981 ofs[0] = ofs[1] = ofs[2] = 0.0f;
983 initgrabz(-G.vd->ofs[0], -G.vd->ofs[1], -G.vd->ofs[2]);
986 if (G.vd->persmat[2][1] < 0.0f)
992 // if playanim = alt+A, screenhandlers are for animated UI, python, etc
993 if( (mode==2 && U.viewzoom==USER_ZOOM_CONT) || /* continues zoom always update */
994 mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || /* mouse moved, so update */
995 (G.f & G_PLAYANIM) || do_screenhandlers(G.curscreen)
1001 /* are we translating, rotating or zooming? */
1003 if(G.vd->view!=0) scrarea_queue_headredraw(curarea); /*for button */
1005 if(G.vd->persp==V3D_CAMOB && mode!=1 && G.vd->camera) {
1006 G.vd->persp= V3D_PERSP;
1007 scrarea_do_windraw(curarea);
1008 scrarea_queue_headredraw(curarea);
1012 if(mode==0) { /* view rotate */
1013 G.vd->view= 0; /* need to reset everytime because of view snapping */
1015 if (U.uiflag & USER_AUTOPERSP) G.vd->persp= V3D_PERSP;
1017 if (U.flag & USER_TRACKBALL) mvalball[0]= mval[0];
1018 mvalball[1]= mval[1];
1020 calctrackballvec(&curarea->winrct, mvalball, newvec);
1022 VecSubf(dvec, newvec, firstvec);
1024 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
1025 si/= (2.0*TRACKBALLSIZE);
1027 if (U.flag & USER_TRACKBALL) {
1028 Crossf(q1+1, firstvec, newvec);
1032 /* Allow for rotation beyond the interval
1037 /* This relation is used instead of
1038 * phi = asin(si) so that the angle
1039 * of rotation is linearly proportional
1040 * to the distance that the mouse is
1042 phi = si * M_PI / 2.0;
1049 QuatMul(G.vd->viewquat, q1, oldquat);
1052 /* compute the post multiplication quat, to rotate the offset correctly */
1053 QUATCOPY(q1, oldquat);
1055 QuatMul(q1, q1, G.vd->viewquat);
1057 QuatConj(q1); /* conj == inv for unit quat */
1058 VECCOPY(G.vd->ofs, ofs);
1059 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
1060 QuatMulVecf(q1, G.vd->ofs);
1061 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
1064 /* New turntable view code by John Aughey */
1068 float xvec[3] = {1,0,0};
1069 /* Sensitivity will control how fast the viewport rotates. 0.0035 was
1070 obtained experimentally by looking at viewport rotation sensitivities
1071 on other modeling programs. */
1072 /* Perhaps this should be a configurable user parameter. */
1073 const float sensitivity = 0.0035;
1075 /* Get the 3x3 matrix and its inverse from the quaternion */
1076 QuatToMat3(G.vd->viewquat, m);
1079 /* Determine the direction of the x vector (for rotating up and down) */
1080 /* This can likely be compuated directly from the quaternion. */
1081 Mat3MulVecfl(m_inv,xvec);
1083 /* Perform the up/down rotation */
1084 phi = sensitivity * -(mval[1] - mvalo[1]);
1087 q1[1] = si * xvec[0];
1088 q1[2] = si * xvec[1];
1089 q1[3] = si * xvec[2];
1090 QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
1093 QuatConj(q1); /* conj == inv for unit quat */
1094 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
1095 QuatMulVecf(q1, G.vd->ofs);
1096 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
1099 /* Perform the orbital rotation */
1100 phi = sensitivity * reverse * (mval[0] - mvalo[0]);
1102 q1[1] = q1[2] = 0.0;
1104 QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
1108 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
1109 QuatMulVecf(q1, G.vd->ofs);
1110 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
1114 /* check for view snap */
1115 if (G.qual==LR_CTRLKEY){
1117 float viewmat[3][3];
1119 static const float thres = 0.93f; //cos(20 deg);
1121 static float snapquats[39][6] = {
1122 /*{q0, q1, q3, q4, view, oposite_direction}*/
1123 {COS45, -SIN45, 0.0, 0.0, 1, 0}, //front
1124 {0.0, 0.0, -SIN45, -SIN45, 1, 1}, //back
1125 {1.0, 0.0, 0.0, 0.0, 7, 0}, //top
1126 {0.0, -1.0, 0.0, 0.0, 7, 1}, //bottom
1127 {0.5, -0.5, -0.5, -0.5, 3, 0}, //left
1128 {0.5, -0.5, 0.5, 0.5, 3, 1}, //right
1130 /* some more 45 deg snaps */
1131 {0.65328145027160645, -0.65328145027160645, 0.27059805393218994, 0.27059805393218994, 0, 0},
1132 {0.92387950420379639, 0.0, 0.0, 0.38268342614173889, 0, 0},
1133 {0.0, -0.92387950420379639, 0.38268342614173889, 0.0, 0, 0},
1134 {0.35355335474014282, -0.85355335474014282, 0.35355338454246521, 0.14644660055637360, 0, 0},
1135 {0.85355335474014282, -0.35355335474014282, 0.14644660055637360, 0.35355338454246521, 0, 0},
1136 {0.49999994039535522, -0.49999994039535522, 0.49999997019767761, 0.49999997019767761, 0, 0},
1137 {0.27059802412986755, -0.65328145027160645, 0.65328145027160645, 0.27059802412986755, 0, 0},
1138 {0.65328145027160645, -0.27059802412986755, 0.27059802412986755, 0.65328145027160645, 0, 0},
1139 {0.27059799432754517, -0.27059799432754517, 0.65328139066696167, 0.65328139066696167, 0, 0},
1140 {0.38268336653709412, 0.0, 0.0, 0.92387944459915161, 0, 0},
1141 {0.0, -0.38268336653709412, 0.92387944459915161, 0.0, 0, 0},
1142 {0.14644658565521240, -0.35355335474014282, 0.85355335474014282, 0.35355335474014282, 0, 0},
1143 {0.35355335474014282, -0.14644658565521240, 0.35355335474014282, 0.85355335474014282, 0, 0},
1144 {0.0, 0.0, 0.92387944459915161, 0.38268336653709412, 0, 0},
1145 {-0.0, 0.0, 0.38268336653709412, 0.92387944459915161, 0, 0},
1146 {-0.27059802412986755, 0.27059802412986755, 0.65328133106231689, 0.65328133106231689, 0, 0},
1147 {-0.38268339633941650, 0.0, 0.0, 0.92387938499450684, 0, 0},
1148 {0.0, 0.38268339633941650, 0.92387938499450684, 0.0, 0, 0},
1149 {-0.14644658565521240, 0.35355338454246521, 0.85355329513549805, 0.35355332493782043, 0, 0},
1150 {-0.35355338454246521, 0.14644658565521240, 0.35355332493782043, 0.85355329513549805, 0, 0},
1151 {-0.49999991059303284, 0.49999991059303284, 0.49999985098838806, 0.49999985098838806, 0, 0},
1152 {-0.27059799432754517, 0.65328145027160645, 0.65328139066696167, 0.27059799432754517, 0, 0},
1153 {-0.65328145027160645, 0.27059799432754517, 0.27059799432754517, 0.65328139066696167, 0, 0},
1154 {-0.65328133106231689, 0.65328133106231689, 0.27059793472290039, 0.27059793472290039, 0, 0},
1155 {-0.92387932538986206, 0.0, 0.0, 0.38268333673477173, 0, 0},
1156 {0.0, 0.92387932538986206, 0.38268333673477173, 0.0, 0, 0},
1157 {-0.35355329513549805, 0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0, 0},
1158 {-0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0.35355329513549805, 0, 0},
1159 {-0.38268330693244934, 0.92387938499450684, 0.0, 0.0, 0, 0},
1160 {-0.92387938499450684, 0.38268330693244934, 0.0, 0.0, 0, 0},
1161 {-COS45, 0.0, 0.0, SIN45, 0, 0},
1162 {COS45, 0.0, 0.0, SIN45, 0, 0},
1163 {0.0, 0.0, 0.0, 1.0, 0, 0}
1166 QuatToMat3(G.vd->viewquat, viewmat);
1168 for (i = 0 ; i < 39; i++){
1169 float snapmat[3][3];
1170 float view = (int)snapquats[i][4];
1171 float oposite_dir = (int)snapquats[i][5];
1173 QuatToMat3(snapquats[i], snapmat);
1175 if ((Inpf(snapmat[0], viewmat[0]) > thres) &&
1176 (Inpf(snapmat[1], viewmat[1]) > thres) &&
1177 (Inpf(snapmat[2], viewmat[2]) > thres)){
1179 QUATCOPY(G.vd->viewquat, snapquats[i]);
1184 G.vd->flag2 |= V3D_OPP_DIRECTION_NAME;
1186 G.vd->flag2 &= ~V3D_OPP_DIRECTION_NAME;
1195 else if(mode==1) { /* translate */
1196 if(G.vd->persp==V3D_CAMOB) {
1197 float max= (float)MAX2(curarea->winx, curarea->winy);
1199 G.vd->camdx += (mvalo[0]-mval[0])/(max);
1200 G.vd->camdy += (mvalo[1]-mval[1])/(max);
1201 CLAMP(G.vd->camdx, -1.0f, 1.0f);
1202 CLAMP(G.vd->camdy, -1.0f, 1.0f);
1206 window_to_3d(dvec, mval[0]-mvalo[0], mval[1]-mvalo[1]);
1207 VecAddf(G.vd->ofs, G.vd->ofs, dvec);
1213 /* use initial value (do not use mvalo (that is used to detect mouse moviments)) */
1214 mvalo[0] = mvali[0];
1215 mvalo[1] = mvali[1];
1217 if(U.viewzoom==USER_ZOOM_CONT) {
1219 zfac = 1.0+(float)(mvalo[0]-mval[0]+mvalo[1]-mval[1])/1000.0;
1221 else if(U.viewzoom==USER_ZOOM_SCALE) {
1222 int ctr[2], len1, len2;
1223 // method which zooms based on how far you move the mouse
1225 ctr[0] = (curarea->winrct.xmax + curarea->winrct.xmin)/2;
1226 ctr[1] = (curarea->winrct.ymax + curarea->winrct.ymin)/2;
1228 len1 = (int)sqrt((ctr[0] - mval[0])*(ctr[0] - mval[0]) + (ctr[1] - mval[1])*(ctr[1] - mval[1])) + 5;
1229 len2 = (int)sqrt((ctr[0] - mvalo[0])*(ctr[0] - mvalo[0]) + (ctr[1] - mvalo[1])*(ctr[1] - mvalo[1])) + 5;
1231 zfac = dist0 * ((float)len2/len1) / G.vd->dist;
1233 else { /* USER_ZOOM_DOLLY */
1234 float len1 = (curarea->winrct.ymax - mval[1]) + 5;
1235 float len2 = (curarea->winrct.ymax - mvalo[1]) + 5;
1236 zfac = dist0 * (2.0*((len2/len1)-1.0) + 1.0) / G.vd->dist;
1239 if(zfac != 1.0 && zfac*G.vd->dist > 0.001*G.vd->grid &&
1240 zfac*G.vd->dist < 10.0*G.vd->far)
1241 view_zoom_mouseloc(zfac, mval_area);
1244 if ((U.uiflag & USER_ORBIT_ZBUF) && (U.viewzoom==USER_ZOOM_CONT) && (G.vd->persp==V3D_PERSP)) {
1245 /* Secret apricot feature, translate the view when in continues mode */
1246 upvec[0] = upvec[1] = 0;
1247 upvec[2] = (dist0 - G.vd->dist) * G.vd->grid;
1249 Mat3CpyMat4(mat, G.vd->viewinv);
1250 Mat3MulVecfl(mat, upvec);
1251 VecAddf(G.vd->ofs, G.vd->ofs, upvec);
1253 /* these limits are in toets.c too */
1254 if(G.vd->dist<0.001*G.vd->grid) G.vd->dist= 0.001*G.vd->grid;
1255 if(G.vd->dist>10.0*G.vd->far) G.vd->dist=10.0*G.vd->far;
1258 if(G.vd->persp==V3D_ORTHO || G.vd->persp==V3D_CAMOB) preview3d_event= 0;
1266 if(G.f & G_PLAYANIM) inner_play_anim_loop(0, 0);
1268 /* If in retopo paint mode, update lines */
1269 if(retopo_mesh_paint_check() && G.vd->retopo_view_data) {
1270 G.vd->retopo_view_data->queue_matrix_update= 1;
1271 retopo_paint_view_update(G.vd);
1274 scrarea_do_windraw(curarea);
1275 screen_swapbuffers();
1279 unsigned short event;
1280 /* we need to empty the queue... when you do this very long it overflows */
1281 while(qtest()) event= extern_qread(&val);
1283 BIF_wait_for_statechange();
1286 /* this in the end, otherwise get_mbut does not work on a PC... */
1287 if( !(get_mbut() & (L_MOUSE|M_MOUSE))) break;
1290 if(G.vd->depths) G.vd->depths->damaged= 1;
1291 retopo_queue_updates(G.vd);
1292 allqueue(REDRAWVIEW3D, 0);
1295 BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1297 BIF_view3d_previewrender_signal(curarea, PR_PROJECTED);
1301 void view_zoom_mouseloc(float dfac, short *mouseloc)
1303 if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
1310 /* find the current window width and height */
1311 vb[0] = G.vd->area->winx;
1312 vb[1] = G.vd->area->winy;
1314 tpos[0] = -G.vd->ofs[0];
1315 tpos[1] = -G.vd->ofs[1];
1316 tpos[2] = -G.vd->ofs[2];
1318 /* Project cursor position into 3D space */
1319 initgrabz(tpos[0], tpos[1], tpos[2]);
1320 window_to_3d(dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2);
1322 /* Calculate view target position for dolly */
1323 tvec[0] = -(tpos[0] + dvec[0]);
1324 tvec[1] = -(tpos[1] + dvec[1]);
1325 tvec[2] = -(tpos[2] + dvec[2]);
1327 /* Offset to target position and dolly */
1328 new_dist = G.vd->dist * dfac;
1330 VECCOPY(G.vd->ofs, tvec);
1331 G.vd->dist = new_dist;
1333 /* Calculate final offset */
1334 dvec[0] = tvec[0] + dvec[0] * dfac;
1335 dvec[1] = tvec[1] + dvec[1] * dfac;
1336 dvec[2] = tvec[2] + dvec[2] * dfac;
1338 VECCOPY(G.vd->ofs, dvec);
1344 void viewmoveNDOF(int mode)
1348 float sbadjust = 1.0f;
1354 float xvec[3] = {1,0,0};
1355 float yvec[3] = {0,-1,0};
1356 float zvec[3] = {0,0,1};
1362 float d, curareaX, curareaY;
1366 /* Sensitivity will control how fast the view rotates. The value was
1367 * obtained experimentally by tweaking until the author didn't get dizzy watching.
1368 * Perhaps this should be a configurable user parameter.
1370 float psens = 0.005f * (float) U.ndof_pan; /* pan sensitivity */
1371 float rsens = 0.005f * (float) U.ndof_rotate; /* rotate sensitivity */
1372 float zsens = 0.3f; /* zoom sensitivity */
1374 const float minZoom = -30.0f;
1375 const float maxZoom = 300.0f;
1379 //printf("passing here \n");
1381 if (G.obedit==NULL && ob && !(ob->flag & OB_POSEMODE)) {
1385 if((dz_flag)||G.vd->dist==0) {
1387 G.vd->dist = m_dist;
1388 upvec[0] = upvec[1] = 0;
1389 upvec[2] = G.vd->dist;
1390 Mat3CpyMat4(mat, G.vd->viewinv);
1391 Mat3MulVecfl(mat, upvec);
1392 VecAddf(G.vd->ofs, G.vd->ofs, upvec);
1395 /*----------------------------------------------------
1396 * sometimes this routine is called from headerbuttons
1397 * viewmove needs to refresh the screen
1399 areawinset(curarea->win);
1401 /*----------------------------------------------------
1402 * record how much time has passed. clamp at 10 Hz
1403 * pretend the previous frame occured at the clamped time
1405 // now = PIL_check_seconds_timer();
1406 // frametime = (now - prevTime);
1407 // if (frametime > 0.1f){ /* if more than 1/10s */
1408 // frametime = 1.0f/60.0; /* clamp at 1/60s so no jumps when starting to move */
1411 // sbadjust *= 60 * frametime; /* normalize ndof device adjustments to 100Hz for framerate independence */
1413 /* fetch the current state of the ndof device & enforce dominant mode if selected */
1415 if (G.vd->ndoffilter)
1416 filterNDOFvalues(fval);
1419 // put scaling back here, was previously in ghostwinlay
1420 fval[0] = fval[0] * (1.0f/600.0f);
1421 fval[1] = fval[1] * (1.0f/600.0f);
1422 fval[2] = fval[2] * (1.0f/1100.0f);
1423 fval[3] = fval[3] * 0.00005f;
1424 fval[4] =-fval[4] * 0.00005f;
1425 fval[5] = fval[5] * 0.00005f;
1426 fval[6] = fval[6] / 1000000.0f;
1428 // scale more if not in perspective mode
1429 if (G.vd->persp == V3D_ORTHO) {
1430 fval[0] = fval[0] * 0.05f;
1431 fval[1] = fval[1] * 0.05f;
1432 fval[2] = fval[2] * 0.05f;
1433 fval[3] = fval[3] * 0.9f;
1434 fval[4] = fval[4] * 0.9f;
1435 fval[5] = fval[5] * 0.9f;
1440 /* set object offset */
1442 obofs[0] = -ob->obmat[3][0];
1443 obofs[1] = -ob->obmat[3][1];
1444 obofs[2] = -ob->obmat[3][2];
1447 VECCOPY(obofs, G.vd->ofs);
1450 /* calc an adjustment based on distance from camera
1451 disabled per patch 14402 */
1455 VecSubf(diff, obofs, G.vd->ofs);
1456 d = VecLength(diff);
1460 reverse = (G.vd->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
1462 /*----------------------------------------------------
1466 curareaX = sbadjust * psens * fval[0];
1467 curareaY = sbadjust * psens * fval[1];
1468 dvec[0] = curareaX * G.vd->persinv[0][0] + curareaY * G.vd->persinv[1][0];
1469 dvec[1] = curareaX * G.vd->persinv[0][1] + curareaY * G.vd->persinv[1][1];
1470 dvec[2] = curareaX * G.vd->persinv[0][2] + curareaY * G.vd->persinv[1][2];
1471 VecAddf(G.vd->ofs, G.vd->ofs, dvec);
1473 /*----------------------------------------------------
1476 len = zsens * sbadjust * fval[2];
1478 if (G.vd->persp==V3D_CAMOB) {
1479 if(G.vd->persp==V3D_CAMOB) { /* This is stupid, please fix - TODO */
1480 G.vd->camzoom+= 10.0f * -len;
1482 if (G.vd->camzoom < minZoom) G.vd->camzoom = minZoom;
1483 else if (G.vd->camzoom > maxZoom) G.vd->camzoom = maxZoom;
1485 else if ((G.vd->dist> 0.001*G.vd->grid) && (G.vd->dist<10.0*G.vd->far)) {
1486 G.vd->dist*=(1.0 + len);
1490 /*----------------------------------------------------
1491 * ndof device turntable
1492 * derived from the turntable code in viewmove
1495 /* Get the 3x3 matrix and its inverse from the quaternion */
1496 QuatToMat3(G.vd->viewquat, m);
1499 /* Determine the direction of the x vector (for rotating up and down) */
1500 /* This can likely be compuated directly from the quaternion. */
1501 Mat3MulVecfl(m_inv,xvec);
1502 Mat3MulVecfl(m_inv,yvec);
1503 Mat3MulVecfl(m_inv,zvec);
1505 /* Perform the up/down rotation */
1506 phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
1509 q1[1] = si * xvec[0];
1510 q1[2] = si * xvec[1];
1511 q1[3] = si * xvec[2];
1512 QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
1515 QuatConj(q1); /* conj == inv for unit quat */
1516 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
1517 QuatMulVecf(q1, G.vd->ofs);
1518 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
1521 /* Perform the orbital rotation */
1522 /* Perform the orbital rotation
1523 If the seen Up axis is parallel to the zoom axis, rotation should be
1524 achieved with a pure Roll motion (no Spin) on the device. When you start
1525 to tilt, moving from Top to Side view, Spinning will increasingly become
1526 more relevant while the Roll component will decrease. When a full
1527 Side view is reached, rotations around the world's Up axis are achieved
1528 with a pure Spin-only motion. In other words the control of the spinning
1529 around the world's Up axis should move from the device's Spin axis to the
1530 device's Roll axis depending on the orientation of the world's Up axis
1531 relative to the screen. */
1532 //phi = sbadjust * rsens * reverse * fval[4]; /* spin the knob, y axis */
1533 phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
1535 q1[1] = q1[2] = 0.0;
1537 QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
1541 VecSubf(G.vd->ofs, G.vd->ofs, obofs);
1542 QuatMulVecf(q1, G.vd->ofs);
1543 VecAddf(G.vd->ofs, G.vd->ofs, obofs);
1546 /*----------------------------------------------------
1547 * refresh the screen
1549 scrarea_do_windraw(curarea);
1550 screen_swapbuffers();
1554 /* Gets the lens and clipping values from a camera of lamp type object */
1555 void object_view_settings(Object *ob, float *lens, float *clipsta, float *clipend)
1559 if(ob->type==OB_LAMP ) {
1560 Lamp *la = ob->data;
1563 fac= cos( M_PI*la->spotsize/360.0);
1565 *lens= 16.0*fac/sin(x1);
1567 if (clipsta) *clipsta= la->clipsta;
1568 if (clipend) *clipend= la->clipend;
1570 else if(ob->type==OB_CAMERA) {
1571 Camera *cam= ob->data;
1572 if (lens) *lens= cam->lens;
1573 if (clipsta) *clipsta= cam->clipsta;
1574 if (clipend) *clipend= cam->clipend;
1579 int get_view3d_viewplane(int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
1582 float lens, fac, x1, y1, x2, y2;
1583 float winx= (float)winxi, winy= (float)winyi;
1588 *clipsta= G.vd->near;
1589 *clipend= G.vd->far;
1592 * Cant use this since we need the fac and x1 values set
1593 * if(G.vd->persp==V3D_CAMOB)
1594 object_view_settings(G.vd->camera, &lens, &(*clipsta), &(*clipend));*/
1596 if(G.vd->persp==V3D_CAMOB) {
1598 if(G.vd->camera->type==OB_LAMP ) {
1601 la= G.vd->camera->data;
1602 fac= cos( M_PI*la->spotsize/360.0);
1605 lens= 16.0*fac/sin(x1);
1607 *clipsta= la->clipsta;
1608 *clipend= la->clipend;
1610 else if(G.vd->camera->type==OB_CAMERA) {
1611 cam= G.vd->camera->data;
1613 *clipsta= cam->clipsta;
1614 *clipend= cam->clipend;
1619 if(G.vd->persp==V3D_ORTHO) {
1620 if(winx>winy) x1= -G.vd->dist;
1621 else x1= -winx*G.vd->dist/winy;
1624 if(winx>winy) y1= -winy*G.vd->dist/winx;
1625 else y1= -G.vd->dist;
1628 *clipend *= 0.5; // otherwise too extreme low zbuffer quality
1629 *clipsta= - *clipend;
1633 /* fac for zoom, also used for camdx */
1634 if(G.vd->persp==V3D_CAMOB) {
1635 fac= (1.41421+( (float)G.vd->camzoom )/50.0);
1640 /* viewplane size depends... */
1641 if(cam && cam->type==CAM_ORTHO) {
1642 /* ortho_scale == 1 means exact 1 to 1 mapping */
1643 float dfac= 2.0*cam->ortho_scale/fac;
1645 if(winx>winy) x1= -dfac;
1646 else x1= -winx*dfac/winy;
1649 if(winx>winy) y1= -winy*dfac/winx;
1657 if(winx>winy) dfac= 64.0/(fac*winx*lens);
1658 else dfac= 64.0/(fac*winy*lens);
1660 x1= - *clipsta * winx*dfac;
1662 y1= - *clipsta * winy*dfac;
1666 /* cam view offset */
1668 float dx= 0.5*fac*G.vd->camdx*(x2-x1);
1669 float dy= 0.5*fac*G.vd->camdy*(y2-y1);
1681 viewfac= (winx >= winy)? winx: winy;
1682 *pixsize= 1.0f/viewfac;
1685 viewfac= (((winx >= winy)? winx: winy)*lens)/32.0;
1686 *pixsize= *clipsta/viewfac;
1690 viewplane->xmin= x1;
1691 viewplane->ymin= y1;
1692 viewplane->xmax= x2;
1693 viewplane->ymax= y2;
1698 /* important to not set windows active in here, can be renderwin for example */
1699 void setwinmatrixview3d(int winx, int winy, rctf *rect) /* rect: for picking */
1702 float clipsta, clipend, x1, y1, x2, y2;
1705 orth= get_view3d_viewplane(winx, winy, &viewplane, &clipsta, &clipend, NULL);
1706 // printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
1712 if(rect) { /* picking */
1713 rect->xmin/= (float)curarea->winx;
1714 rect->xmin= x1+rect->xmin*(x2-x1);
1715 rect->ymin/= (float)curarea->winy;
1716 rect->ymin= y1+rect->ymin*(y2-y1);
1717 rect->xmax/= (float)curarea->winx;
1718 rect->xmax= x1+rect->xmax*(x2-x1);
1719 rect->ymax/= (float)curarea->winy;
1720 rect->ymax= y1+rect->ymax*(y2-y1);
1722 if(orth) myortho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
1723 else mywindow(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
1727 if(orth) myortho(x1, x2, y1, y2, clipsta, clipend);
1728 else mywindow(x1, x2, y1, y2, clipsta, clipend);
1731 /* not sure what this was for? (ton) */
1732 glMatrixMode(GL_PROJECTION);
1733 mygetmatrix(curarea->winmat);
1734 glMatrixMode(GL_MODELVIEW);
1737 void obmat_to_viewmat(Object *ob, short smooth)
1742 G.vd->view= 0; /* dont show the grid */
1744 Mat4CpyMat4(bmat, ob->obmat);
1746 Mat4Invert(G.vd->viewmat, bmat);
1748 /* view quat calculation, needed for add object */
1749 Mat3CpyMat4(tmat, G.vd->viewmat);
1752 if (G.vd->persp==V3D_CAMOB && G.vd->camera) {
1753 /* were from a camera view */
1756 float orig_dist= G.vd->dist;
1757 float orig_lens= G.vd->lens;
1758 VECCOPY(orig_ofs, G.vd->ofs);
1760 /* Switch from camera view */
1761 Mat3ToQuat(tmat, new_quat);
1763 G.vd->persp=V3D_PERSP;
1766 view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
1767 smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
1769 G.vd->persp=V3D_CAMOB; /* just to be polite, not needed */
1772 Mat3ToQuat(tmat, new_quat);
1773 smooth_view(G.vd, NULL, new_quat, NULL, NULL);
1776 Mat3ToQuat(tmat, G.vd->viewquat);
1780 /* dont set windows active in in here, is used by renderwin too */
1781 void setviewmatrixview3d()
1783 if(G.vd->persp==V3D_CAMOB) { /* obs/camera */
1785 where_is_object(G.vd->camera);
1786 obmat_to_viewmat(G.vd->camera, 0);
1789 QuatToMat4(G.vd->viewquat, G.vd->viewmat);
1790 G.vd->viewmat[3][2]-= G.vd->dist;
1795 QuatToMat4(G.vd->viewquat, G.vd->viewmat);
1796 if(G.vd->persp==V3D_PERSP) G.vd->viewmat[3][2]-= G.vd->dist;
1797 if(G.vd->ob_centre) {
1798 Object *ob= G.vd->ob_centre;
1801 VECCOPY(vec, ob->obmat[3]);
1802 if(ob->type==OB_ARMATURE && G.vd->ob_centre_bone[0]) {
1803 bPoseChannel *pchan= get_pose_channel(ob->pose, G.vd->ob_centre_bone);
1805 VECCOPY(vec, pchan->pose_mat[3]);
1806 Mat4MulVecfl(ob->obmat, vec);
1809 i_translate(-vec[0], -vec[1], -vec[2], G.vd->viewmat);
1811 else i_translate(G.vd->ofs[0], G.vd->ofs[1], G.vd->ofs[2], G.vd->viewmat);
1815 void setcameratoview3d(void)
1821 dvec[0]= G.vd->dist*G.vd->viewinv[2][0];
1822 dvec[1]= G.vd->dist*G.vd->viewinv[2][1];
1823 dvec[2]= G.vd->dist*G.vd->viewinv[2][2];
1824 VECCOPY(ob->loc, dvec);
1825 VecSubf(ob->loc, ob->loc, G.vd->ofs);
1826 G.vd->viewquat[0]= -G.vd->viewquat[0];
1828 /*if (ob->transflag & OB_QUAT) {
1829 QUATCOPY(ob->quat, G.vd->viewquat);
1831 QuatToEul(G.vd->viewquat, ob->rot);
1833 G.vd->viewquat[0]= -G.vd->viewquat[0];
1836 /* IGLuint-> GLuint*/
1837 /* Warning: be sure to account for a negative return value
1838 * This is an error, "Too many objects in select buffer"
1839 * and no action should be taken (can crash blender) if this happens
1841 short view3d_opengl_select(unsigned int *buffer, unsigned int bufsize, short x1, short y1, short x2, short y2)
1844 short mval[2], code, hits;
1848 if(x1==0 && x2==0 && y1==0 && y2==0) {
1849 getmouseco_areawin(mval);
1850 rect.xmin= mval[0]-12; // seems to be default value for bones only now
1851 rect.xmax= mval[0]+12;
1852 rect.ymin= mval[1]-12;
1853 rect.ymax= mval[1]+12;
1861 /* get rid of overlay button matrix */
1863 setwinmatrixview3d(curarea->winx, curarea->winy, &rect);
1864 Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
1866 if(G.vd->drawtype > OB_WIRE) {
1868 glEnable(GL_DEPTH_TEST);
1871 if(G.vd->flag & V3D_CLIPPING)
1872 view3d_set_clipping(G.vd);
1874 glSelectBuffer( bufsize, (GLuint *)buffer);
1875 glRenderMode(GL_SELECT);
1876 glInitNames(); /* these two calls whatfor? It doesnt work otherwise */
1880 if(G.obedit && G.obedit->type==OB_MBALL) {
1881 draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1883 else if ((G.obedit && G.obedit->type==OB_ARMATURE)) {
1884 if (BIF_fullSketchMode())
1886 BDR_drawSketchNames();
1890 draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1896 G.vd->xray= TRUE; // otherwise it postpones drawing
1897 for(base= G.scene->base.first; base; base= base->next) {
1898 if(base->lay & G.vd->lay) {
1900 if (base->object->restrictflag & OB_RESTRICT_SELECT)
1905 draw_object(base, DRAW_PICKING|DRAW_CONSTCOLOR);
1907 /* we draw group-duplicators for selection too */
1908 if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1913 tbase.flag= OB_FROMDUPLI;
1914 lb= object_duplilist(G.scene, base->object);
1916 for(dob= lb->first; dob; dob= dob->next) {
1917 tbase.object= dob->ob;
1918 Mat4CpyMat4(dob->ob->obmat, dob->mat);
1920 draw_object(&tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1922 Mat4CpyMat4(dob->ob->obmat, dob->omat);
1924 free_object_duplilist(lb);
1930 G.vd->xray= FALSE; // restore
1933 glPopName(); /* see above (pushname) */
1934 hits= glRenderMode(GL_RENDER);
1937 setwinmatrixview3d(curarea->winx, curarea->winy, NULL);
1938 Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
1940 if(G.vd->drawtype > OB_WIRE) {
1942 glDisable(GL_DEPTH_TEST);
1946 if(G.vd->flag & V3D_CLIPPING)
1947 view3d_clr_clipping();
1949 if(hits<0) error("Too many objects in select buffer");
1954 float *give_cursor()
1956 if(G.vd && G.vd->localview) return G.vd->cursor;
1957 else return G.scene->cursor;
1960 unsigned int free_localbit()
1968 /* sometimes we loose a localview: when an area is closed */
1969 /* check all areas: which localviews are in use? */
1970 sc= G.main->screen.first;
1972 sa= sc->areabase.first;
1974 SpaceLink *sl= sa->spacedata.first;
1976 if(sl->spacetype==SPACE_VIEW3D) {
1977 View3D *v3d= (View3D*) sl;
1987 if( (lay & 0x01000000)==0) return 0x01000000;
1988 if( (lay & 0x02000000)==0) return 0x02000000;
1989 if( (lay & 0x04000000)==0) return 0x04000000;
1990 if( (lay & 0x08000000)==0) return 0x08000000;
1991 if( (lay & 0x10000000)==0) return 0x10000000;
1992 if( (lay & 0x20000000)==0) return 0x20000000;
1993 if( (lay & 0x40000000)==0) return 0x40000000;
1994 if( (lay & 0x80000000)==0) return 0x80000000;
2000 void initlocalview()
2003 float size = 0.0, min[3], max[3], afm[3];
2004 unsigned int locallay;
2007 if(G.vd->localvd) return;
2009 INIT_MINMAX(min, max);
2011 locallay= free_localbit();
2014 error("Sorry, no more than 8 localviews");
2019 minmax_object(G.obedit, min, max);
2023 BASACT->lay |= locallay;
2024 G.obedit->lay= BASACT->lay;
2030 minmax_object(base->object, min, max);
2031 base->lay |= locallay;
2032 base->object->lay= base->lay;
2039 afm[0]= (max[0]-min[0]);
2040 afm[1]= (max[1]-min[1]);
2041 afm[2]= (max[2]-min[2]);
2042 size= 0.7*MAX3(afm[0], afm[1], afm[2]);
2043 if(size<=0.01) size= 0.01;
2047 G.vd->localvd= MEM_mallocN(sizeof(View3D), "localview");
2048 memcpy(G.vd->localvd, G.vd, sizeof(View3D));
2050 G.vd->ofs[0]= -(min[0]+max[0])/2.0;
2051 G.vd->ofs[1]= -(min[1]+max[1])/2.0;
2052 G.vd->ofs[2]= -(min[2]+max[2])/2.0;
2056 // correction for window aspect ratio
2057 if(curarea->winy>2 && curarea->winx>2) {
2058 size= (float)curarea->winx/(float)curarea->winy;
2059 if(size<1.0) size= 1.0/size;
2063 if (G.vd->persp==V3D_CAMOB) G.vd->persp= V3D_PERSP;
2064 if (G.vd->near> 0.1) G.vd->near= 0.1;
2066 G.vd->cursor[0]= -G.vd->ofs[0];
2067 G.vd->cursor[1]= -G.vd->ofs[1];
2068 G.vd->cursor[2]= -G.vd->ofs[2];
2070 G.vd->lay= locallay;
2073 scrarea_queue_winredraw(curarea);
2079 if( base->lay & locallay ) {
2080 base->lay-= locallay;
2081 if(base->lay==0) base->lay= G.vd->layact;
2082 if(base->object != G.obedit) base->flag |= SELECT;
2083 base->object->lay= base->lay;
2087 scrarea_queue_headredraw(curarea);
2091 BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
2094 void centerview() /* like a localview without local! */
2097 float size, min[3], max[3], afm[3];
2104 INIT_MINMAX(min, max);
2106 if (G.f & G_WEIGHTPAINT) {
2107 /* hardcoded exception, we look for the one selected armature */
2108 /* this is weak code this way, we should make a generic active/selection callback interface once... */
2110 for(base=FIRSTBASE; base; base= base->next) {
2111 if(TESTBASELIB(base)) {
2112 if(base->object->type==OB_ARMATURE)
2113 if(base->object->flag & OB_POSEMODE)
2123 ok = minmax_verts(min, max); /* only selected */
2125 else if(ob && (ob->flag & OB_POSEMODE)) {
2127 bArmature *arm= ob->data;
2128 bPoseChannel *pchan;
2131 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
2132 if(pchan->bone->flag & BONE_SELECTED) {
2133 if(pchan->bone->layer & arm->layer) {
2135 VECCOPY(vec, pchan->pose_head);
2136 Mat4MulVecfl(ob->obmat, vec);
2137 DO_MINMAX(vec, min, max);
2138 VECCOPY(vec, pchan->pose_tail);
2139 Mat4MulVecfl(ob->obmat, vec);
2140 DO_MINMAX(vec, min, max);
2146 else if (FACESEL_PAINT_TEST) {
2147 ok= minmax_tface(min, max);
2149 else if (G.f & G_PARTICLEEDIT) {
2150 ok= PE_minmax(min, max);
2153 Base *base= FIRSTBASE;
2156 minmax_object(base->object, min, max);
2157 /* account for duplis */
2158 minmax_object_duplis(base->object, min, max);
2168 afm[0]= (max[0]-min[0]);
2169 afm[1]= (max[1]-min[1]);
2170 afm[2]= (max[2]-min[2]);
2171 size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
2173 if(size <= G.vd->near*1.5f) size= G.vd->near*1.5f;
2175 new_ofs[0]= -(min[0]+max[0])/2.0f;
2176 new_ofs[1]= -(min[1]+max[1])/2.0f;
2177 new_ofs[2]= -(min[2]+max[2])/2.0f;
2181 /* correction for window aspect ratio */
2182 if(curarea->winy>2 && curarea->winx>2) {
2183 size= (float)curarea->winx/(float)curarea->winy;
2184 if(size<1.0f) size= 1.0f/size;
2188 G.vd->cursor[0]= -new_ofs[0];
2189 G.vd->cursor[1]= -new_ofs[1];
2190 G.vd->cursor[2]= -new_ofs[2];
2192 if (G.vd->persp==V3D_CAMOB && G.vd->camera) {
2193 float orig_lens= G.vd->lens;
2195 G.vd->persp=V3D_PERSP;
2197 view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
2198 smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
2200 if(G.vd->persp==V3D_CAMOB)
2201 G.vd->persp= V3D_PERSP;
2203 smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
2205 scrarea_queue_winredraw(curarea);
2206 BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
2211 void restore_localviewdata(View3D *vd)
2213 if(vd->localvd==0) return;
2215 VECCOPY(vd->ofs, vd->localvd->ofs);
2216 vd->dist= vd->localvd->dist;
2217 vd->persp= vd->localvd->persp;
2218 vd->view= vd->localvd->view;
2219 vd->near= vd->localvd->near;
2220 vd->far= vd->localvd->far;
2221 vd->lay= vd->localvd->lay;
2222 vd->layact= vd->localvd->layact;
2223 vd->drawtype= vd->localvd->drawtype;
2224 vd->camera= vd->localvd->camera;
2225 QUATCOPY(vd->viewquat, vd->localvd->viewquat);
2229 void endlocalview(ScrArea *sa)
2233 unsigned int locallay;
2235 if(sa->spacetype!=SPACE_VIEW3D) return;
2236 v3d= sa->spacedata.first;
2240 locallay= v3d->lay & 0xFF000000;
2242 restore_localviewdata(v3d);
2244 MEM_freeN(v3d->localvd);
2248 /* for when in other window the layers have changed */
2249 if(v3d->scenelock) v3d->lay= G.scene->lay;
2253 if( base->lay & locallay ) {
2254 base->lay-= locallay;
2255 if(base->lay==0) base->lay= v3d->layact;
2256 if(base->object != G.obedit) {
2257 base->flag |= SELECT;
2258 base->object->flag |= SELECT;
2260 base->object->lay= base->lay;
2266 allqueue(REDRAWVIEW3D, 0); /* because of select */
2267 allqueue(REDRAWOOPS, 0); /* because of select */
2268 BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
2272 void view3d_home(int center)
2275 float size, min[3], max[3], afm[3];
2276 int ok= 1, onedone=0;
2279 min[0]= min[1]= min[2]= 0.0f;
2280 max[0]= max[1]= max[2]= 0.0f;
2283 INIT_MINMAX(min, max);
2286 for(base= FIRSTBASE; base; base= base->next) {
2287 if(base->lay & G.vd->lay) {
2289 minmax_object(base->object, min, max);
2292 if(!onedone) return;
2294 afm[0]= (max[0]-min[0]);
2295 afm[1]= (max[1]-min[1]);
2296 afm[2]= (max[2]-min[2]);
2297 size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
2298 if(size==0.0) ok= 0;
2305 new_ofs[0]= -(min[0]+max[0])/2.0f;
2306 new_ofs[1]= -(min[1]+max[1])/2.0f;
2307 new_ofs[2]= -(min[2]+max[2])/2.0f;
2309 // correction for window aspect ratio
2310 if(curarea->winy>2 && curarea->winx>2) {
2311 size= (float)curarea->winx/(float)curarea->winy;
2312 if(size<1.0) size= 1.0f/size;
2316 if (G.vd->persp==V3D_CAMOB && G.vd->camera) {
2317 /* switch out of camera view */
2318 float orig_lens= G.vd->lens;
2320 G.vd->persp= V3D_PERSP;
2322 view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
2323 smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
2326 if(G.vd->persp==V3D_CAMOB) G.vd->persp= V3D_PERSP;
2327 smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
2329 scrarea_queue_winredraw(curarea);
2331 BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
2336 void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3])
2338 float alignaxis[3] = {0.0, 0.0, 0.0};
2339 float norm[3], axis[3], angle, new_quat[4];
2341 if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
2342 else alignaxis[-axisidx-1]= -1.0;
2347 angle= (float)acos(Inpf(alignaxis, norm));
2348 Crossf(axis, alignaxis, norm);
2349 VecRotToQuat(axis, -angle, new_quat);
2353 if (v3d->persp==V3D_CAMOB && v3d->camera) {
2354 /* switch out of camera view */
2356 float orig_dist= v3d->dist;
2357 float orig_lens= v3d->lens;
2359 VECCOPY(orig_ofs, v3d->ofs);
2360 G.vd->persp= V3D_PERSP;
2362 view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens);
2363 smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
2365 if (v3d->persp==V3D_CAMOB) v3d->persp= V3D_PERSP; /* switch out of camera mode */
2366 smooth_view(v3d, NULL, new_quat, NULL, NULL);
2373 void smooth_view(View3D *v3d, float *ofs, float *quat, float *dist, float *lens)
2375 /* View Animation enabled */
2376 if (U.smooth_viewtx) {
2379 float step = 0.0, step_inv;
2385 double time_allowed, time_current, time_start;
2387 /* if there is no difference, return */
2388 changed = 0; /* zero means no difference */
2390 if ((*dist) != v3d->dist)
2395 if ((*lens) != v3d->lens)
2399 if (!changed && ofs) {
2400 if ((ofs[0]!=v3d->ofs[0]) ||
2401 (ofs[1]!=v3d->ofs[1]) ||
2402 (ofs[2]!=v3d->ofs[2]) )
2406 if (!changed && quat ) {
2407 if ((quat[0]!=v3d->viewquat[0]) ||
2408 (quat[1]!=v3d->viewquat[1]) ||
2409 (quat[2]!=v3d->viewquat[2]) ||
2410 (quat[3]!=v3d->viewquat[3]) )
2414 /* The new view is different from the old one
2415 * so animate the view */
2418 /* store original values */
2419 VECCOPY(orig_ofs, v3d->ofs);
2420 QUATCOPY(orig_quat, v3d->viewquat);
2421 orig_dist = v3d->dist;
2422 orig_lens = v3d->lens;
2424 time_allowed= (float)U.smooth_viewtx / 1000.0;
2425 time_current = time_start = PIL_check_seconds_timer();
2427 /* if this is view rotation only
2428 * we can decrease the time allowed by
2429 * the angle between quats
2430 * this means small rotations wont lag */
2431 if (quat && !ofs && !dist) {
2432 float vec1[3], vec2[3];
2433 VECCOPY(vec1, quat);
2434 VECCOPY(vec2, v3d->viewquat);
2437 /* scale the time allowed by the rotation */
2438 time_allowed *= NormalizedVecAngle2(vec1, vec2)/(M_PI/2);
2441 while (time_start + time_allowed > time_current) {
2443 step = (float)((time_current-time_start) / time_allowed);
2446 if (step < 0.5) step = (float)pow(step*2, 2)/2;
2447 else step = (float)1-(pow(2*(1-step),2)/2);
2453 v3d->ofs[i] = ofs[i]*step + orig_ofs[i]*step_inv;
2457 QuatInterpol(v3d->viewquat, orig_quat, quat, step);
2460 v3d->dist = ((*dist)*step) + (orig_dist*step_inv);
2463 v3d->lens = ((*lens)*step) + (orig_lens*step_inv);
2466 scrarea_do_windraw(curarea);
2467 screen_swapbuffers();
2469 time_current= PIL_check_seconds_timer();
2474 /* set these values even if animation is enabled because flaot
2475 * error will make then not quite accurate */
2477 VECCOPY(v3d->ofs, ofs);
2479 QUATCOPY(v3d->viewquat, quat);
2489 /* Gets the view trasnformation from a camera
2490 * currently dosnt take camzoom into account
2492 * The dist is not modified for this function, if NULL its assimed zero
2494 void view_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens)
2504 where_is_object(ob);
2505 VECCOPY(ofs, ob->obmat[3]);
2506 VecMulf(ofs, -1.0f); /*flip the vector*/
2511 Mat4CpyMat4(bmat, ob->obmat);
2513 Mat4Invert(imat, bmat);
2514 Mat3CpyMat4(tmat, imat);
2515 Mat3ToQuat(tmat, quat);
2520 Mat3CpyMat4(tmat, ob->obmat);
2522 vec[0]= vec[1] = 0.0;
2524 Mat3MulVecfl(tmat, vec);
2525 VecSubf(ofs, ofs, vec);
2530 object_view_settings(ob, lens, NULL, NULL);
2533 /* For use with smooth view
2535 * the current view is unchanged, blend between the current view and the
2538 void smooth_view_to_camera(View3D *v3d)
2540 if (!U.smooth_viewtx || !v3d->camera || G.vd->persp != V3D_CAMOB) {
2543 Object *ob = v3d->camera;
2546 float orig_dist=v3d->dist;
2547 float orig_lens=v3d->lens;
2549 float new_lens=35.0;
2553 VECCOPY(orig_ofs, v3d->ofs);
2555 view_settings_from_ob(ob, new_ofs, new_quat, NULL, &new_lens);
2557 G.vd->persp= V3D_PERSP;
2558 smooth_view(v3d, new_ofs, new_quat, &new_dist, &new_lens);
2559 VECCOPY(v3d->ofs, orig_ofs);
2560 v3d->lens= orig_lens;
2561 v3d->dist = orig_dist; /* restore the dist */
2564 v3d->persp= V3D_CAMOB;