diff options
author | Campbell Barton <ideasman42@gmail.com> | 2015-04-23 17:12:16 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2015-04-23 17:18:42 +0300 |
commit | 27e03dcd21872d9daf73adf42c69c04c5806ac07 (patch) | |
tree | 9e13fe7835e178603accadf343be26e114734187 /source/blender/editors/space_view3d | |
parent | 22b564f93ef4bd7c981a7986addf5fe466954592 (diff) |
Fix T44422: Zoom to mouse fails in camera view
Camera now supports all zoom styles too.
Diffstat (limited to 'source/blender/editors/space_view3d')
-rw-r--r-- | source/blender/editors/space_view3d/view3d_edit.c | 231 |
1 files changed, 163 insertions, 68 deletions
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 236fefc7088..3f6f17da334 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -517,6 +517,7 @@ void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip) typedef struct ViewOpsData { /* context pointers (assigned by viewops_data_alloc) */ + Scene *scene; ScrArea *sa; ARegion *ar; View3D *v3d; @@ -589,6 +590,7 @@ static void viewops_data_alloc(bContext *C, wmOperator *op) /* store data */ op->customdata = vod; + vod->scene = CTX_data_scene(C); vod->sa = CTX_wm_area(C); vod->ar = CTX_wm_region(C); vod->v3d = vod->sa->spacedata.first; @@ -2093,16 +2095,63 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom"); } -static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my) +static void view_zoom_mouseloc_camera( + Scene *scene, View3D *v3d, + ARegion *ar, float dfac, int mx, int my) { RegionView3D *rv3d = ar->regiondata; + const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom); + const float zoomfac_new = CLAMPIS(zoomfac * (1.0f / dfac), RV3D_CAMZOOM_MIN_FACTOR, RV3D_CAMZOOM_MAX_FACTOR); + const float camzoom_new = BKE_screen_view3d_zoom_from_fac(zoomfac_new); + + + if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) { + float zoomfac_px; + rctf camera_frame_old; + rctf camera_frame_new; + + const float pt_src[2] = {mx, my}; + float pt_dst[2]; + float delta_px[2]; + + ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &camera_frame_old, false); + BLI_rctf_translate(&camera_frame_old, ar->winrct.xmin, ar->winrct.ymin); + + rv3d->camzoom = camzoom_new; + CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX); + + ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &camera_frame_new, false); + BLI_rctf_translate(&camera_frame_new, ar->winrct.xmin, ar->winrct.ymin); + + BLI_rctf_transform_pt_v(&camera_frame_new, &camera_frame_old, pt_dst, pt_src); + sub_v2_v2v2(delta_px, pt_dst, pt_src); + + /* translate the camera offset using pixel space delta + * mapped back to the camera (same logic as panning in camera view) */ + zoomfac_px = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom) * 2.0f; + + rv3d->camdx += delta_px[0] / (ar->winx * zoomfac_px); + rv3d->camdy += delta_px[1] / (ar->winy * zoomfac_px); + CLAMP(rv3d->camdx, -1.0f, 1.0f); + CLAMP(rv3d->camdy, -1.0f, 1.0f); + } + else { + rv3d->camzoom = camzoom_new; + CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX); + } +} + +static void view_zoom_mouseloc_3d(ARegion *ar, float dfac, int mx, int my) +{ + RegionView3D *rv3d = ar->regiondata; + const float dist_new = rv3d->dist * dfac; if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) { float dvec[3]; float tvec[3]; float tpos[3]; float mval_f[2]; - float new_dist; + float zfac; negate_v3_v3(tpos, rv3d->ofs); @@ -2119,105 +2168,133 @@ static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my) negate_v3(tvec); /* Offset to target position and dolly */ - new_dist = rv3d->dist * dfac; - copy_v3_v3(rv3d->ofs, tvec); - rv3d->dist = new_dist; + rv3d->dist = dist_new; /* Calculate final offset */ madd_v3_v3v3fl(rv3d->ofs, tvec, dvec, dfac); } else { - rv3d->dist *= dfac; + rv3d->dist = dist_new; } } - -static void viewzoom_apply(ViewOpsData *vod, const int xy[2], const short viewzoom, const short zoom_invert) +static float viewzoom_scale_value( + const rcti *winrct, + const short viewzoom, + const bool zoom_invert, const bool zoom_invert_force, + const int xy[2], const int xy_orig[2], + const float val, const float val_orig, + double *r_timer_lastdraw) { - float zfac = 1.0; - bool use_cam_zoom; - float dist_range[2]; - - use_cam_zoom = (vod->rv3d->persp == RV3D_CAMOB) && !(vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)); - - ED_view3d_dist_range_get(vod->v3d, dist_range); - - if (use_cam_zoom) { - float delta; - delta = (xy[0] - vod->origx + xy[1] - vod->origy) / 10.0f; - vod->rv3d->camzoom = vod->camzoom_prev + (zoom_invert ? -delta : delta); - - CLAMP(vod->rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX); - } + float zfac; if (viewzoom == USER_ZOOM_CONT) { double time = PIL_check_seconds_timer(); - float time_step = (float)(time - vod->timer_lastdraw); + float time_step = (float)(time - *r_timer_lastdraw); float fac; if (U.uiflag & USER_ZOOM_HORIZ) { - fac = (float)(vod->origx - xy[0]); + fac = (float)(xy_orig[0] - xy[0]); } else { - fac = (float)(vod->origy - xy[1]); + fac = (float)(xy_orig[1] - xy[1]); } - if (zoom_invert) { + if (zoom_invert != zoom_invert_force) { fac = -fac; } /* oldstyle zoom */ zfac = 1.0f + ((fac / 20.0f) * time_step); - vod->timer_lastdraw = time; + *r_timer_lastdraw = time; } else if (viewzoom == USER_ZOOM_SCALE) { /* method which zooms based on how far you move the mouse */ const int ctr[2] = { - BLI_rcti_cent_x(&vod->ar->winrct), - BLI_rcti_cent_y(&vod->ar->winrct), + BLI_rcti_cent_x(winrct), + BLI_rcti_cent_y(winrct), }; - const float len_new = 5 + len_v2v2_int(ctr, xy); - const float len_old = 5 + len_v2v2_int(ctr, &vod->origx); - zfac = vod->dist_prev * ((len_old + 5) / (len_new + 5)) / vod->rv3d->dist; + float len_new = 5 + len_v2v2_int(ctr, xy); + float len_old = 5 + len_v2v2_int(ctr, xy_orig); + + /* intentionally ignore 'zoom_invert' for scale */ + if (zoom_invert_force) { + SWAP(float, len_new, len_old); + } + + zfac = val_orig * (len_old / max_ff(len_new, 1.0f)) / val; } else { /* USER_ZOOM_DOLLY */ - float len1, len2; - + float len_new = 5; + float len_old = 5; + if (U.uiflag & USER_ZOOM_HORIZ) { - len1 = (vod->ar->winrct.xmax - xy[0]) + 5; - len2 = (vod->ar->winrct.xmax - vod->origx) + 5; + len_new += (winrct->xmax - xy[0]); + len_old += (winrct->xmax - xy_orig[0]); } else { - len1 = (vod->ar->winrct.ymax - xy[1]) + 5; - len2 = (vod->ar->winrct.ymax - vod->origy) + 5; - } - if (zoom_invert) { - SWAP(float, len1, len2); + len_new += (winrct->ymax - xy[1]); + len_old += (winrct->ymax - xy_orig[1]); } - - if (use_cam_zoom) { - /* zfac is ignored in this case, see below */ -#if 0 - zfac = vod->camzoom_prev * (2.0f * ((len1 / len2) - 1.0f) + 1.0f) / vod->rv3d->camzoom; -#endif - } - else { - zfac = vod->dist_prev * (2.0f * ((len1 / len2) - 1.0f) + 1.0f) / vod->rv3d->dist; + + if (zoom_invert != zoom_invert_force) { + SWAP(float, len_new, len_old); } + + zfac = val_orig * (2.0f * ((len_new / max_ff(len_old, 1.0f)) - 1.0f) + 1.0f) / val; } - if (!use_cam_zoom) { - if (zfac != 1.0f) { - const float zfac_min = dist_range[0] / vod->rv3d->dist; - const float zfac_max = dist_range[1] / vod->rv3d->dist; - CLAMP(zfac, zfac_min, zfac_max); - if (zfac != 1.0f) { - view_zoom_mouseloc(vod->ar, zfac, vod->oldx, vod->oldy); - } - } + return zfac; +} + +static void viewzoom_apply_camera( + ViewOpsData *vod, const int xy[2], + const short viewzoom, const bool zoom_invert) +{ + float zfac; + float zoomfac_prev = BKE_screen_view3d_zoom_to_fac(vod->camzoom_prev) * 2.0f; + float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f; + + zfac = viewzoom_scale_value( + &vod->ar->winrct, viewzoom, zoom_invert, true, xy, &vod->origx, + zoomfac, zoomfac_prev, + &vod->timer_lastdraw); + + if (zfac != 1.0f && zfac != 0.0f) { + /* calculate inverted, then invert again (needed because of camera zoom scaling) */ + zfac = 1.0f / zfac; + view_zoom_mouseloc_camera( + vod->scene, vod->v3d, + vod->ar, zfac, vod->oldx, vod->oldy); + } + + ED_region_tag_redraw(vod->ar); +} + +static void viewzoom_apply_3d( + ViewOpsData *vod, const int xy[2], + const short viewzoom, const bool zoom_invert) +{ + float zfac; + float dist_range[2]; + + ED_view3d_dist_range_get(vod->v3d, dist_range); + + zfac = viewzoom_scale_value( + &vod->ar->winrct, viewzoom, zoom_invert, false, xy, &vod->origx, + vod->rv3d->dist, vod->dist_prev, + &vod->timer_lastdraw); + + if (zfac != 1.0f) { + const float zfac_min = dist_range[0] / vod->rv3d->dist; + const float zfac_max = dist_range[1] / vod->rv3d->dist; + CLAMP(zfac, zfac_min, zfac_max); + + view_zoom_mouseloc_3d( + vod->ar, zfac, vod->oldx, vod->oldy); } /* these limits were in old code too */ @@ -2231,6 +2308,19 @@ static void viewzoom_apply(ViewOpsData *vod, const int xy[2], const short viewzo ED_region_tag_redraw(vod->ar); } +static void viewzoom_apply( + ViewOpsData *vod, const int xy[2], + const short viewzoom, const bool zoom_invert) +{ + if ((vod->rv3d->persp == RV3D_CAMOB) && + (vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) == 0) + { + viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert); + } + else { + viewzoom_apply_3d(vod, xy, viewzoom, zoom_invert); + } +} static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event) { @@ -2291,6 +2381,7 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event) static int viewzoom_exec(bContext *C, wmOperator *op) { + Scene *scene = CTX_data_scene(C); View3D *v3d; RegionView3D *rv3d; ScrArea *sa; @@ -2323,22 +2414,26 @@ static int viewzoom_exec(bContext *C, wmOperator *op) ED_view3d_dist_range_get(v3d, dist_range); if (delta < 0) { + const float step = 1.2f; /* this min and max is also in viewmove() */ if (use_cam_zoom) { - rv3d->camzoom -= 10.0f; - if (rv3d->camzoom < RV3D_CAMZOOM_MIN) rv3d->camzoom = RV3D_CAMZOOM_MIN; + view_zoom_mouseloc_camera(scene, v3d, ar, step, mx, my); } - else if (rv3d->dist < dist_range[1]) { - view_zoom_mouseloc(ar, 1.2f, mx, my); + else { + if (rv3d->dist < dist_range[1]) { + view_zoom_mouseloc_3d(ar, step, mx, my); + } } } else { + const float step = 1.0f / 1.2f; if (use_cam_zoom) { - rv3d->camzoom += 10.0f; - if (rv3d->camzoom > RV3D_CAMZOOM_MAX) rv3d->camzoom = RV3D_CAMZOOM_MAX; + view_zoom_mouseloc_camera(scene, v3d, ar, step, mx, my); } - else if (rv3d->dist > dist_range[0]) { - view_zoom_mouseloc(ar, 0.83333f, mx, my); + else { + if (rv3d->dist > dist_range[0]) { + view_zoom_mouseloc_3d(ar, step, mx, my); + } } } |