Fix T44422: Zoom to mouse fails in camera view

Camera now supports all zoom styles too.
This commit is contained in:
Campbell Barton 2015-04-24 00:12:16 +10:00
parent 22b564f93e
commit 27e03dcd21
Notes: blender-bot 2023-02-14 09:24:53 +01:00
Referenced by issue #44422, "Zoom to mouse position" doesn't work in camera view
2 changed files with 167 additions and 69 deletions

View File

@ -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;
len_new += (winrct->ymax - xy[1]);
len_old += (winrct->ymax - xy_orig[1]);
}
if (zoom_invert) {
SWAP(float, len1, len2);
}
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);
}
}
}

View File

@ -379,6 +379,9 @@ enum {
#define RV3D_CAMZOOM_MIN -30
#define RV3D_CAMZOOM_MAX 600
/* #BKE_screen_view3d_zoom_to_fac() values above */
#define RV3D_CAMZOOM_MIN_FACTOR 0.1657359312880714853f
#define RV3D_CAMZOOM_MAX_FACTOR 44.9852813742385702928f
#endif