forked from bartvdbraak/blender
Fix T44422: Zoom to mouse fails in camera view
Camera now supports all zoom styles too.
This commit is contained in:
parent
22b564f93e
commit
27e03dcd21
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user