Index: source/blender/include/BSE_view.h =================================================================== --- source/blender/include/BSE_view.h (revision 11763) +++ source/blender/include/BSE_view.h (working copy) @@ -76,6 +76,7 @@ void calctrackballvecfirst(struct rcti *area, short *mval, float *vec); void calctrackballvec(struct rcti *area, short *mval, float *vec); void viewmove(int mode); +void viewdolly(float dfac); int get_view3d_viewplane(int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize); void setwinmatrixview3d(int winx, int winy, struct rctf *rect); Index: source/blender/makesdna/DNA_userdef_types.h =================================================================== --- source/blender/makesdna/DNA_userdef_types.h (revision 11763) +++ source/blender/makesdna/DNA_userdef_types.h (working copy) @@ -233,6 +233,7 @@ #define USER_SHOW_ROTVIEWICON 131072 #define USER_SHOW_VIEWPORTNAME 262144 #define USER_KEYINSERTNEED 524288 +#define USER_MOUSEPOSDOLLY 1048576 /* transopts */ Index: source/blender/makesdna/DNA_view3d_types.h =================================================================== --- source/blender/makesdna/DNA_view3d_types.h (revision 11763) +++ source/blender/makesdna/DNA_view3d_types.h (working copy) @@ -82,7 +82,8 @@ float winmat1[4][4]; // persp(1) storage, for swap matrices float viewmat1[4][4]; - float viewquat[4], dist, zfac, pad0; /* zfac is initgrabz() result */ + float viewquat[4], dist, zfac; /* zfac is initgrabz() result */ + short focus_pos[2]; /* 2D view focus coordinates at screen space (mainly to store current mouse cursor position) */ /** * 0 - ortho Index: source/blender/src/space.c =================================================================== --- source/blender/src/space.c (revision 11763) +++ source/blender/src/space.c (working copy) @@ -1192,6 +1192,7 @@ mouse_cursor(); break; case MIDDLEMOUSE: + getmouseco_areawin(G.vd->focus_pos); /* use '&' here, because of alt+leftmouse which emulates middlemouse */ if(U.flag & USER_VIEWMOVE) { if((G.qual==LR_SHIFTKEY) || ((U.flag & USER_TWOBUTTONMOUSE) && (G.qual==(LR_ALTKEY|LR_SHIFTKEY)))) @@ -1323,6 +1324,7 @@ break; /* View */ case MIDDLEMOUSE: + getmouseco_areawin(G.vd->focus_pos); handle_view_middlemouse(); break; case WHEELUPMOUSE: @@ -1549,6 +1551,7 @@ } break; case MIDDLEMOUSE: + getmouseco_areawin(G.vd->focus_pos); handle_view_middlemouse(); break; case RIGHTMOUSE: @@ -3343,28 +3346,32 @@ &(U.viewzoom), 40, USER_ZOOM_SCALE, 0, 0, "Zooms in and out like scaling the view, mouse movements relative to center."); uiBlockSetCol(block, TH_AUTO); /* end color */ + uiDefButBitI(block, TOG, USER_MOUSEPOSDOLLY, B_DRAWINFO, "Mouse Position Dolly", + (xpos+edgsp+mpref+(2*spref)+(3*midsp)),y4,mpref,buth, + &(U.uiflag), 0, 0, 0, 0, + "Dollying to the position of the mouse."); uiBlockEndAlign(block); uiDefBut(block, LABEL,0,"View rotation:", - (xpos+(2*edgsp)+mpref+(2*spref)+(2*midsp)),y4label,mpref,buth, + (xpos+(2*edgsp)+mpref+(2*spref)+(2*midsp)),y3label,mpref,buth, 0, 0, 0, 0, 0, ""); uiBlockBeginAlign(block); uiBlockSetCol(block, TH_BUT_SETTING1); /* mutually exclusive toggles, start color */ uiDefButBitI(block, TOG, USER_TRACKBALL, B_DRAWINFO, "Trackball", - (xpos+edgsp+mpref+(2*spref)+(3*midsp)),y3,(mpref/2),buth, + (xpos+edgsp+mpref+(2*spref)+(3*midsp)),y2,(mpref/2),buth, &(U.flag), 0, 0, 0, 0, "Allow the view to tumble freely when orbiting with the Middle Mouse Button"); uiDefButBitI(block, TOGN, USER_TRACKBALL, B_DRAWINFO, "Turntable", - (xpos+edgsp+mpref+(2*spref)+(3*midsp)+(mpref/2)),y3,(mpref/2),buth, + (xpos+edgsp+mpref+(2*spref)+(3*midsp)+(mpref/2)),y2,(mpref/2),buth, &(U.flag), 0, 0, 0, 0, "Use fixed up axis for orbiting with Middle Mouse Button"); uiBlockSetCol(block, TH_AUTO); /* end color */ uiDefButBitI(block, TOG, USER_AUTOPERSP, B_DRAWINFO, "Auto Perspective", - (xpos+edgsp+mpref+(2*spref)+(3*midsp)),y2,(mpref/2),buth, + (xpos+edgsp+mpref+(2*spref)+(3*midsp)),y1,(mpref/2),buth, &(U.uiflag), 0, 0, 0, 0, "Automatically switch between orthographic and perspective when changing from top/front/side views"); uiDefButBitI(block, TOG, USER_ORBIT_SELECTION, B_DRAWINFO, "Around Selection", - (xpos+edgsp+mpref+(2*spref)+(3*midsp)+(mpref/2)),y2,(mpref/2),buth, + (xpos+edgsp+mpref+(2*spref)+(3*midsp)+(mpref/2)),y1,(mpref/2),buth, &(U.uiflag), 0, 0, 0, 0, "Use selection as the orbiting center"); uiBlockEndAlign(block); @@ -3372,15 +3379,15 @@ uiBlockBeginAlign(block); uiDefButBitI(block, TOG, USER_SHOW_ROTVIEWICON, B_DRAWINFO, "Mini Axis", - (xpos+edgsp+(2*mpref)+(2*midsp)),y1,(mpref/3),buth, + (xpos+edgsp+(5*mpref)+(6*midsp)),y1,(mpref/3),buth, &(U.uiflag), 0, 0, 0, 0, "Show a small rotating 3D axis in the bottom left corner of the 3D View"); uiDefButS(block, NUM, B_DRAWINFO, "Size:", - (xpos+edgsp+(2*mpref)+(2*midsp)+(mpref/3)),y1,(mpref/3),buth, + ((xpos+edgsp+(5*mpref)+(6*midsp))+(mpref/3)),y1,(mpref/3),buth, &U.rvisize, 10, 64, 0, 0, "The axis icon's size"); uiDefButS(block, NUM, B_DRAWINFO, "Bright:", - (xpos+edgsp+(2*mpref)+(2*midsp)+2*(mpref/3)),y1,(mpref/3),buth, + ((xpos+edgsp+(5*mpref)+(6*midsp))+2*(mpref/3)),y1,(mpref/3),buth, &U.rvibright, 0, 10, 0, 0, "The brightness of the icon"); uiBlockEndAlign(block); Index: source/blender/src/toets.c =================================================================== --- source/blender/src/toets.c (revision 11763) +++ source/blender/src/toets.c (working copy) @@ -149,6 +149,10 @@ G.vd->view= view; } +#define VIEW_DOLLY_OUT_FACTOR (1.15f) +#define VIEW_DOLLY_IN_FACTOR (1.0f/VIEW_DOLLY_OUT_FACTOR) + + void persptoetsen(unsigned short event) { static Object *oldcamera=0; @@ -243,14 +247,20 @@ if(G.vd->persp==2) { G.vd->camzoom= MAX2(-30, G.vd->camzoom-5); } - else if(G.vd->dist<10.0*G.vd->far) G.vd->dist*=1.2f; + else if(G.vd->dist<10.0*G.vd->far) { + getmouseco_areawin(G.vd->focus_pos); + viewdolly(VIEW_DOLLY_OUT_FACTOR); + } if(G.vd->persp!=1) preview3d_event= 0; } else if(event==PADPLUSKEY) { if(G.vd->persp==2) { G.vd->camzoom= MIN2(300, G.vd->camzoom+5); } - else if(G.vd->dist> 0.001*G.vd->grid) G.vd->dist*=.83333f; + else if(G.vd->dist> 0.001*G.vd->grid) { + getmouseco_areawin(G.vd->focus_pos); + viewdolly(VIEW_DOLLY_IN_FACTOR); + } if(G.vd->persp!=1) preview3d_event= 0; } else if(event==PAD5) { Index: source/blender/src/view.c =================================================================== --- source/blender/src/view.c (revision 11763) +++ source/blender/src/view.c (working copy) @@ -730,7 +730,7 @@ else if(mode==2) { if(U.viewzoom==USER_ZOOM_CONT) { // oldstyle zoom - G.vd->dist*= 1.0+(float)(mvalo[0]-mval[0]+mvalo[1]-mval[1])/1000.0; + viewdolly(1.0+(float)(mvalo[0]-mval[0]+mvalo[1]-mval[1])/1000.0); } else if(U.viewzoom==USER_ZOOM_SCALE) { int ctr[2], len1, len2; @@ -742,13 +742,13 @@ len1 = (int)sqrt((ctr[0] - mval[0])*(ctr[0] - mval[0]) + (ctr[1] - mval[1])*(ctr[1] - mval[1])) + 5; len2 = (int)sqrt((ctr[0] - mvalo[0])*(ctr[0] - mvalo[0]) + (ctr[1] - mvalo[1])*(ctr[1] - mvalo[1])) + 5; - G.vd->dist= dist0 * ((float)len2/len1); + viewdolly(dist0 * ((float)len2/len1) / G.vd->dist); } else { /* USER_ZOOM_DOLLY */ float len1 = (curarea->winrct.ymax - mval[1]) + 5; float len2 = (curarea->winrct.ymax - mvalo[1]) + 5; - G.vd->dist= dist0 * (2.0*((len2/len1)-1.0) + 1.0); + viewdolly(dist0 * (2.0*((len2/len1)-1.0) + 1.0) / G.vd->dist); } /* these limits are in toets.c too */ @@ -800,6 +800,52 @@ } +/* + * no bounds check + * set G.vd->focus_pos first + */ +void viewdolly(float dfac) +{ + if(U.uiflag & USER_MOUSEPOSDOLLY) { + short vb[2]; + float dvec[3]; + float tvec[3]; + float tpos[3]; + float new_dist; + + /* find the current window width and height */ + vb[0] = G.vd->area->winx; + vb[1] = G.vd->area->winy; + + tpos[0] = -G.vd->ofs[0]; + tpos[1] = -G.vd->ofs[1]; + tpos[2] = -G.vd->ofs[2]; + + /* Project cursor position into 3D space */ + initgrabz(tpos[0], tpos[1], tpos[2]); + window_to_3d(dvec, G.vd->focus_pos[0]-vb[0]/2, + G.vd->focus_pos[1]-vb[1]/2); + + /* Calculate view target position for dolly */ + tvec[0] = -(tpos[0] + dvec[0]); + tvec[1] = -(tpos[1] + dvec[1]); + tvec[2] = -(tpos[2] + dvec[2]); + + /* Offset to target position and dolly */ + new_dist = G.vd->dist * dfac; + smooth_view(G.vd, tvec, NULL, &new_dist, NULL); + + /* Calculate final offset */ + dvec[0] = tvec[0] + dvec[0] * dfac; + dvec[1] = tvec[1] + dvec[1] * dfac; + dvec[2] = tvec[2] + dvec[2] * dfac; + + smooth_view(G.vd, dvec, NULL, NULL, NULL); + } else { + G.vd->dist *= dfac; + } +} + /* Gets the lens and clipping values from a camera of lamp type object */ void object_view_settings(Object *ob, float *lens, float *clipsta, float *clipend) {