Fix T100633: Node Editor: Edge scrolling breaks node snapping

The view offset, calculated by the Edge Pan system, only affects the
position of the nodes, but forget to update:
- snapping data
- final value of transform
- values used for custom drawing

Therefore, to avoid having to update a lot of scattered data, the
`transformViewUpdate` utility has been implemented to recalculate input
values when the view changes.

This utility does more than is necessary to fix the bug, but with that,
it can work in any situation.
This commit is contained in:
Germano Cavalcante 2022-08-26 13:17:30 -03:00
parent cc9c4e2744
commit 3c060b2216
Notes: blender-bot 2023-02-14 06:47:29 +01:00
Referenced by issue #100633, Node Editor: Edge scrolling breaks node snapping
7 changed files with 262 additions and 84 deletions

View File

@ -355,10 +355,12 @@ typedef struct MouseInput {
/** Initial mouse position. */
int imval[2];
bool precision;
float precision_factor;
float imval_unproj[3];
float center[2];
float factor;
float precision_factor;
bool precision;
/** Additional data, if needed by the particular function. */
void *data;
@ -758,6 +760,7 @@ void applyMouseInput(struct TransInfo *t,
struct MouseInput *mi,
const int mval[2],
float output[3]);
void transform_input_update(TransInfo *t, const float fac);
void setCustomPoints(TransInfo *t, MouseInput *mi, const int start[2], const int end[2]);
void setCustomPointsFromDirection(TransInfo *t, MouseInput *mi, const float dir[2]);
@ -806,6 +809,7 @@ void calculateCenter2D(TransInfo *t);
void calculateCenterLocal(TransInfo *t, const float center_global[3]);
void calculateCenter(TransInfo *t);
void tranformViewUpdate(TransInfo *t);
/* API functions for getting center points */
void calculateCenterBound(TransInfo *t, float r_center[3]);

View File

@ -153,6 +153,7 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
static void flushTransNodes(TransInfo *t)
{
const float dpi_fac = UI_DPI_FAC;
float offset[2] = {0.0f, 0.0f};
View2DEdgePanData *customdata = (View2DEdgePanData *)t->custom.type.data;
@ -166,14 +167,16 @@ static void flushTransNodes(TransInfo *t)
t->region->winrct.xmin + t->mval[0],
t->region->winrct.ymin + t->mval[1],
};
const rctf rect = t->region->v2d.cur;
UI_view2d_edge_pan_apply(t->context, customdata, xy);
if (!BLI_rctf_compare(&rect, &t->region->v2d.cur, FLT_EPSILON)) {
/* Additional offset due to change in view2D rect. */
BLI_rctf_transform_pt_v(&t->region->v2d.cur, &rect, offset, offset);
tranformViewUpdate(t);
}
}
}
/* Initial and current view2D rects for additional transform due to view panning and zooming */
const rctf *rect_src = &customdata->initial_rect;
const rctf *rect_dst = &t->region->v2d.cur;
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
applyGridAbsolute(t);
@ -184,10 +187,7 @@ static void flushTransNodes(TransInfo *t)
bNode *node = td->extra;
float loc[2];
copy_v2_v2(loc, td2d->loc);
/* additional offset due to change in view2D rect */
BLI_rctf_transform_pt_v(rect_dst, rect_src, loc, loc);
add_v2_v2v2(loc, td2d->loc, offset);
#ifdef USE_NODE_CENTER
loc[0] -= 0.5f * BLI_rctf_size_x(&node->totr);

View File

@ -1132,6 +1132,33 @@ static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[
}
}
static void calculateZfac(TransInfo *t)
{
/* ED_view3d_calc_zfac() defines a factor for perspective depth correction,
* used in ED_view3d_win_to_delta() */
/* zfac is only used convertViewVec only in cases operator was invoked in RGN_TYPE_WINDOW
* and never used in other cases.
*
* We need special case here as well, since ED_view3d_calc_zfac will crash when called
* for a region different from RGN_TYPE_WINDOW.
*/
if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
t->zfac = ED_view3d_calc_zfac(t->region->regiondata, t->center_global);
}
else if (t->spacetype == SPACE_IMAGE) {
SpaceImage *sima = t->area->spacedata.first;
t->zfac = 1.0f / sima->zoom;
}
else {
View2D *v2d = &t->region->v2d;
/* Get zoom fac the same way as in
* `ui_view2d_curRect_validate_resize` - better keep in sync! */
const float zoomx = (float)(BLI_rcti_size_x(&v2d->mask) + 1) / BLI_rctf_size_x(&v2d->cur);
t->zfac = 1.0f / zoomx;
}
}
void calculateCenter(TransInfo *t)
{
if ((t->flag & T_OVERRIDE_CENTER) == 0) {
@ -1166,22 +1193,46 @@ void calculateCenter(TransInfo *t)
}
}
if (t->spacetype == SPACE_VIEW3D) {
/* #ED_view3d_calc_zfac() defines a factor for perspective depth correction,
* used in #ED_view3d_win_to_delta(). */
calculateZfac(t);
}
/* NOTE: `t->zfac` is only used #convertViewVec only in cases operator was invoked in
* #RGN_TYPE_WINDOW and never used in other cases.
*
* We need special case here as well, since #ED_view3d_calc_zfac will crash when called
* for a region different from #RGN_TYPE_WINDOW. */
if (t->region->regiontype == RGN_TYPE_WINDOW) {
t->zfac = ED_view3d_calc_zfac(t->region->regiondata, t->center_global);
/* Called every time the view changes due to navigation.
* Adjusts the mouse position relative to the object. */
void tranformViewUpdate(TransInfo *t)
{
float zoom_prev = t->zfac;
float zoom_new;
if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
if (!t->persp) {
zoom_prev *= len_v3(t->persinv[0]);
}
else {
t->zfac = 0.0f;
setTransformViewMatrices(t);
calculateZfac(t);
zoom_new = t->zfac;
if (!t->persp) {
zoom_new *= len_v3(t->persinv[0]);
}
for (int i = 0; i < ARRAY_SIZE(t->orient); i++) {
if (t->orient[i].type == V3D_ORIENT_VIEW) {
copy_m3_m4(t->orient[i].matrix, t->viewinv);
normalize_m3(t->orient[i].matrix);
if (t->orient_curr == i) {
copy_m3_m3(t->spacemtx, t->orient[i].matrix);
invert_m3_m3_safe_ortho(t->spacemtx_inv, t->spacemtx);
}
}
}
}
else {
calculateZfac(t);
zoom_new = t->zfac;
}
calculateCenter2D(t);
transform_input_update(t, zoom_prev / zoom_new);
}
void calculatePropRatio(TransInfo *t)

View File

@ -8,6 +8,7 @@
#include <stdlib.h>
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "BKE_context.h"
@ -18,6 +19,7 @@
#include "WM_types.h"
#include "transform.h"
#include "transform_mode.h"
#include "MEM_guardedalloc.h"
@ -251,11 +253,8 @@ void setCustomPointsFromDirection(TransInfo *t, MouseInput *mi, const float dir[
/** \name Setup & Handle Mouse Input
* \{ */
void initMouseInput(TransInfo *UNUSED(t),
MouseInput *mi,
const float center[2],
const int mval[2],
const bool precision)
void initMouseInput(
TransInfo *t, MouseInput *mi, const float center[2], const int mval[2], const bool precision)
{
mi->factor = 0;
mi->precision = precision;
@ -266,6 +265,12 @@ void initMouseInput(TransInfo *UNUSED(t),
mi->imval[0] = mval[0];
mi->imval[1] = mval[1];
if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
float delta[3] = {mval[0] - center[0], mval[1] - center[1]};
ED_view3d_win_to_delta(t->region, delta, t->zfac, delta);
add_v3_v3v3(mi->imval_unproj, t->center_global, delta);
}
mi->post = NULL;
}
@ -441,4 +446,52 @@ void applyMouseInput(TransInfo *t, MouseInput *mi, const int mval[2], float outp
}
}
void transform_input_update(TransInfo *t, const float fac)
{
MouseInput *mi = &t->mouse;
t->mouse.factor *= fac;
if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
projectIntView(t, mi->imval_unproj, mi->imval);
}
else {
int offset[2], center_2d_int[2] = {mi->center[0], mi->center[1]};
sub_v2_v2v2_int(offset, mi->imval, center_2d_int);
offset[0] *= fac;
offset[1] *= fac;
center_2d_int[0] = t->center2d[0];
center_2d_int[1] = t->center2d[1];
add_v2_v2v2_int(mi->imval, center_2d_int, offset);
}
float center_old[2];
copy_v2_v2(center_old, mi->center);
copy_v2_v2(mi->center, t->center2d);
if (mi->use_virtual_mval) {
/* Update accumulator. */
double mval_delta[2];
sub_v2_v2v2_db(mval_delta, mi->virtual_mval.accum, mi->virtual_mval.prev);
mval_delta[0] *= fac;
mval_delta[1] *= fac;
copy_v2_v2_db(mi->virtual_mval.accum, mi->virtual_mval.prev);
add_v2_v2_db(mi->virtual_mval.accum, mval_delta);
}
if (ELEM(mi->apply, InputAngle, InputAngleSpring)) {
float offset_center[2];
sub_v2_v2v2(offset_center, mi->center, center_old);
struct InputAngle_Data *data = mi->data;
data->mval_prev[0] += offset_center[0];
data->mval_prev[1] += offset_center[1];
}
if (t->mode == TFM_EDGE_SLIDE) {
transform_mode_edge_slide_reproject_input(t);
}
else if (t->mode == TFM_VERT_SLIDE) {
transform_mode_vert_slide_reproject_input(t);
}
}
/** \} */

View File

@ -117,6 +117,7 @@ void drawEdgeSlide(TransInfo *t);
void initEdgeSlide_ex(
TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp);
void initEdgeSlide(TransInfo *t);
void transform_mode_edge_slide_reproject_input(TransInfo *t);
/* transform_mode_gpopacity.c */
@ -191,3 +192,4 @@ void initTranslation(TransInfo *t);
void drawVertSlide(TransInfo *t);
void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp);
void initVertSlide(TransInfo *t);
void transform_mode_vert_slide_reproject_input(TransInfo *t);

View File

@ -292,6 +292,73 @@ static BMLoop *get_next_loop(
return NULL;
}
static void edge_slide_projmat_get(TransInfo *t, TransDataContainer *tc, float r_projectMat[4][4])
{
RegionView3D *rv3d = NULL;
if (t->spacetype == SPACE_VIEW3D) {
/* Background mode support. */
rv3d = t->region ? t->region->regiondata : NULL;
}
if (!rv3d) {
/* Ok, let's try to survive this. */
unit_m4(r_projectMat);
}
else {
ED_view3d_ob_project_mat_get(rv3d, tc->obedit, r_projectMat);
}
}
static void edge_slide_pair_project(TransDataEdgeSlideVert *sv,
ARegion *region,
float projectMat[4][4],
float r_sco_a[3],
float r_sco_b[3])
{
BMVert *v = sv->v;
if (sv->v_side[1]) {
ED_view3d_project_float_v3_m4(region, sv->v_side[1]->co, r_sco_b, projectMat);
}
else {
add_v3_v3v3(r_sco_b, v->co, sv->dir_side[1]);
ED_view3d_project_float_v3_m4(region, r_sco_b, r_sco_b, projectMat);
}
if (sv->v_side[0]) {
ED_view3d_project_float_v3_m4(region, sv->v_side[0]->co, r_sco_a, projectMat);
}
else {
add_v3_v3v3(r_sco_a, v->co, sv->dir_side[0]);
ED_view3d_project_float_v3_m4(region, r_sco_a, r_sco_a, projectMat);
}
}
static void edge_slide_data_init_mval(MouseInput *mi, EdgeSlideData *sld, float *mval_dir)
{
/* Possible all of the edge loops are pointing directly at the view. */
if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) {
mval_dir[0] = 0.0f;
mval_dir[1] = 100.0f;
}
float mval_start[2], mval_end[2];
/* Zero out Start. */
zero_v2(mval_start);
/* dir holds a vector along edge loop */
copy_v2_v2(mval_end, mval_dir);
mul_v2_fl(mval_end, 0.5f);
sld->mval_start[0] = mi->imval[0] + mval_start[0];
sld->mval_start[1] = mi->imval[1] + mval_start[1];
sld->mval_end[0] = mi->imval[0] + mval_end[0];
sld->mval_end[1] = mi->imval[1] + mval_end[1];
}
/**
* Calculate screenspace `mval_start` / `mval_end`, optionally slide direction.
*/
@ -308,29 +375,20 @@ static void calcEdgeSlide_mval_range(TransInfo *t,
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
ARegion *region = t->region;
View3D *v3d = NULL;
RegionView3D *rv3d = NULL;
float projectMat[4][4];
BMBVHTree *bmbvh;
/* only for use_calc_direction */
float(*loop_dir)[3] = NULL, *loop_maxdist = NULL;
float mval_start[2], mval_end[2];
float mval_dir[3], dist_best_sq;
if (t->spacetype == SPACE_VIEW3D) {
/* background mode support */
v3d = t->area ? t->area->spacedata.first : NULL;
rv3d = t->region ? t->region->regiondata : NULL;
}
if (!rv3d) {
/* ok, let's try to survive this */
unit_m4(projectMat);
}
else {
ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat);
}
edge_slide_projmat_get(t, tc, projectMat);
if (use_occlude_geometry) {
bmbvh = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false);
@ -379,21 +437,7 @@ static void calcEdgeSlide_mval_range(TransInfo *t,
continue;
}
if (sv->v_side[1]) {
ED_view3d_project_float_v3_m4(region, sv->v_side[1]->co, sco_b, projectMat);
}
else {
add_v3_v3v3(sco_b, v->co, sv->dir_side[1]);
ED_view3d_project_float_v3_m4(region, sco_b, sco_b, projectMat);
}
if (sv->v_side[0]) {
ED_view3d_project_float_v3_m4(region, sv->v_side[0]->co, sco_a, projectMat);
}
else {
add_v3_v3v3(sco_a, v->co, sv->dir_side[0]);
ED_view3d_project_float_v3_m4(region, sco_a, sco_a, projectMat);
}
edge_slide_pair_project(sv, region, projectMat, sco_a, sco_b);
/* global direction */
dist_sq = dist_squared_to_line_segment_v2(mval, sco_b, sco_a);
@ -433,24 +477,7 @@ static void calcEdgeSlide_mval_range(TransInfo *t,
MEM_freeN(loop_maxdist);
}
/* possible all of the edge loops are pointing directly at the view */
if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) {
mval_dir[0] = 0.0f;
mval_dir[1] = 100.0f;
}
/* zero out start */
zero_v2(mval_start);
/* dir holds a vector along edge loop */
copy_v2_v2(mval_end, mval_dir);
mul_v2_fl(mval_end, 0.5f);
sld->mval_start[0] = t->mval[0] + mval_start[0];
sld->mval_start[1] = t->mval[1] + mval_start[1];
sld->mval_end[0] = t->mval[0] + mval_end[0];
sld->mval_end[1] = t->mval[1] + mval_end[1];
edge_slide_data_init_mval(&t->mouse, sld, mval_dir);
if (bmbvh) {
BKE_bmbvh_free(bmbvh);
@ -466,7 +493,6 @@ static void calcEdgeSlide_even(TransInfo *t,
if (sld->totsv > 0) {
ARegion *region = t->region;
RegionView3D *rv3d = NULL;
float projectMat[4][4];
int i = 0;
@ -475,18 +501,7 @@ static void calcEdgeSlide_even(TransInfo *t,
float dist_sq = 0;
float dist_min_sq = FLT_MAX;
if (t->spacetype == SPACE_VIEW3D) {
/* background mode support */
rv3d = t->region ? t->region->regiondata : NULL;
}
if (!rv3d) {
/* ok, let's try to survive this */
unit_m4(projectMat);
}
else {
ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat);
}
edge_slide_projmat_get(t, tc, projectMat);
for (i = 0; i < sld->totsv; i++, sv++) {
/* Set length */
@ -1553,3 +1568,32 @@ void initEdgeSlide(TransInfo *t)
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Mouse Input Utilities
* \{ */
void transform_mode_edge_slide_reproject_input(TransInfo *t)
{
ARegion *region = t->region;
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
EdgeSlideData *sld = tc->custom.mode.data;
if (sld) {
float projectMat[4][4];
edge_slide_projmat_get(t, tc, projectMat);
TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
float mval_dir[3], sco_a[3], sco_b[3];
edge_slide_pair_project(curr_sv, region, projectMat, sco_a, sco_b);
sub_v3_v3v3(mval_dir, sco_b, sco_a);
edge_slide_data_init_mval(&t->mouse, sld, mval_dir);
}
}
EdgeSlideData *sld = edgeSlideFirstGet(t);
setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start);
}
/** \} */

View File

@ -68,7 +68,7 @@ typedef struct VertSlideParams {
bool flipped;
} VertSlideParams;
static void calcVertSlideCustomPoints(struct TransInfo *t)
static void vert_slide_update_input(TransInfo *t)
{
VertSlideParams *slp = t->custom.mode.data;
VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
@ -94,6 +94,11 @@ static void calcVertSlideCustomPoints(struct TransInfo *t)
else {
setCustomPoints(t, &t->mouse, mval_end, mval_start);
}
}
static void calcVertSlideCustomPoints(struct TransInfo *t)
{
vert_slide_update_input(t);
/* setCustomPoints isn't normally changing as the mouse moves,
* in this case apply mouse input immediately so we don't refresh
@ -673,3 +678,22 @@ void initVertSlide(TransInfo *t)
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Mouse Input Utilities
* \{ */
void transform_mode_vert_slide_reproject_input(TransInfo *t)
{
if (t->spacetype == SPACE_VIEW3D) {
RegionView3D *rv3d = t->region->regiondata;
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
VertSlideData *sld = tc->custom.mode.data;
ED_view3d_ob_project_mat_get(rv3d, tc->obedit, sld->proj_mat);
}
}
vert_slide_update_input(t);
}
/** \} */