WIP: Snapping & precision modeling improvements #105941

Draft
Germano Cavalcante wants to merge 4 commits from mano-wii/blender:transform_improvements into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
27 changed files with 787 additions and 264 deletions

View File

@ -80,4 +80,15 @@ def keyconfig_update(keyconfig_data, keyconfig_version):
km_items.append(('ROTATE_NORMALS', {"type": 'N', "value": 'PRESS'}, None))
break
if keyconfig_version <= (3, 6, 2):
if not has_copy:
keyconfig_data = copy.deepcopy(keyconfig_data)
has_copy = True
# "Snap Source Toggle" did not exist until then.
for km_name, _km_parms, km_items_data in keyconfig_data:
if km_name == "Transform Modal Map":
km_items_data["items"].append(("EDIT_SNAP_SOURCE", {"type": 'B', "value": 'PRESS'}, None))
break
return keyconfig_data

View File

@ -346,7 +346,6 @@ url_manual_mapping = (
("bpy.types.toolsettings.use_edge_path_live_unwrap*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-use-edge-path-live-unwrap"),
("bpy.types.toolsettings.use_gpencil_draw_additive*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-draw-additive"),
("bpy.types.toolsettings.use_snap_backface_culling*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-backface-culling"),
("bpy.types.toolsettings.use_snap_uv_grid_absolute*", "editors/uv/controls/snapping.html#bpy-types-toolsettings-use-snap-uv-grid-absolute"),
("bpy.types.toolsettings.use_transform_data_origin*", "scene_layout/object/tools/tool_settings.html#bpy-types-toolsettings-use-transform-data-origin"),
("bpy.types.view3doverlay.sculpt_mode_mask_opacity*", "sculpt_paint/sculpting/editing/mask.html#bpy-types-view3doverlay-sculpt-mode-mask-opacity"),
("bpy.types.view3doverlay.viewer_attribute_opacity*", "modeling/geometry_nodes/output/viewer.html#bpy-types-view3doverlay-viewer-attribute-opacity"),
@ -538,7 +537,6 @@ url_manual_mapping = (
("bpy.types.spacespreadsheet.show_only_selected*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-show-only-selected"),
("bpy.types.spacespreadsheetrowfilter.operation*", "editors/spreadsheet.html#bpy-types-spacespreadsheetrowfilter-operation"),
("bpy.types.spacespreadsheetrowfilter.threshold*", "editors/spreadsheet.html#bpy-types-spacespreadsheetrowfilter-threshold"),
("bpy.types.toolsettings.use_snap_grid_absolute*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-grid-absolute"),
("bpy.types.transformsequence.use_uniform_scale*", "video_editing/edit/montage/strips/effects/transform.html#bpy-types-transformsequence-use-uniform-scale"),
("bpy.types.view3doverlay.show_face_orientation*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-show-face-orientation"),
("bpy.types.view3doverlay.show_viewer_attribute*", "modeling/geometry_nodes/output/viewer.html#bpy-types-view3doverlay-show-viewer-attribute"),

View File

@ -5882,6 +5882,7 @@ def km_transform_modal_map(params):
("TRACKBALL", {"type": 'R', "value": 'PRESS'}, None),
("RESIZE", {"type": 'S', "value": 'PRESS'}, None),
("ROTATE_NORMALS", {"type": 'N', "value": 'PRESS'}, None),
("EDIT_SNAP_SOURCE", {"type": 'B', "value": 'PRESS'}, None),
("SNAP_TOGGLE", {"type": 'TAB', "value": 'PRESS', "shift": True}, None),
("SNAP_INV_ON", {"type": 'LEFT_CTRL', "value": 'PRESS', "any": True}, None),
("SNAP_INV_OFF", {"type": 'LEFT_CTRL', "value": 'RELEASE', "any": True}, None),

View File

@ -4034,6 +4034,7 @@ def km_transform_modal_map(_params):
("TRACKBALL", {"type": 'R', "value": 'PRESS'}, None),
("RESIZE", {"type": 'S', "value": 'PRESS'}, None),
("ROTATE_NORMALS", {"type": 'N', "value": 'PRESS'}, None),
("EDIT_SNAP_SOURCE", {"type": 'B', "value": 'PRESS'}, None),
("SNAP_TOGGLE", {"type": 'TAB', "value": 'PRESS', "shift": True}, None),
("SNAP_INV_ON", {"type": 'LEFT_CTRL', "value": 'PRESS', "any": True}, None),
("SNAP_INV_OFF", {"type": 'LEFT_CTRL', "value": 'RELEASE', "any": True}, None),

View File

@ -978,8 +978,6 @@ class IMAGE_PT_snapping(Panel):
row.prop(tool_settings, "snap_target", expand=True)
col.separator()
if 'INCREMENT' in tool_settings.snap_uv_element:
col.prop(tool_settings, "use_snap_uv_grid_absolute")
col.label(text="Affect")
row = col.row(align=True)

View File

@ -7029,8 +7029,6 @@ class VIEW3D_PT_snapping(Panel):
col.prop(tool_settings, "snap_elements", expand=True)
col.separator()
if 'INCREMENT' in snap_elements:
col.prop(tool_settings, "use_snap_grid_absolute")
if snap_elements != {'INCREMENT'}:
if snap_elements != {'FACE_NEAREST'}:

View File

@ -25,7 +25,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 2
#define BLENDER_FILE_SUBVERSION 3
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file

View File

@ -136,7 +136,7 @@ static bool v3d_cursor_snap_calc_incremental(
return false;
}
if (scene->toolsettings->snap_flag & SCE_SNAP_ABS_GRID) {
if (scene->toolsettings->snap_mode & SCE_SNAP_MODE_GRID) {
co_relative = NULL;
}

View File

@ -219,7 +219,7 @@ static bool idp_snap_calc_incremental(
return false;
}
if (scene->toolsettings->snap_flag & SCE_SNAP_ABS_GRID) {
if (scene->toolsettings->snap_mode & SCE_SNAP_MODE_GRID) {
co_relative = NULL;
}

View File

@ -82,6 +82,7 @@ set(SRC
transform_mode_shear.c
transform_mode_shrink_fatten.c
transform_mode_skin_resize.c
transform_mode_snapsource.c
transform_mode_tilt.c
transform_mode_timescale.c
transform_mode_timeslide.c

View File

@ -542,6 +542,19 @@ static void viewRedrawPost(bContext *C, TransInfo *t)
static bool transform_modal_item_poll(const wmOperator *op, int value)
{
const TransInfo *t = op->customdata;
if (t->modifiers & MOD_EDIT_SNAP_SOURCE) {
if (value == TFM_MODAL_EDIT_SNAP_SOURCE) {
return true;
}
else if (!ELEM(value,
TFM_MODAL_CANCEL,
TFM_MODAL_CONFIRM,
TFM_MODAL_ADD_SNAP,
TFM_MODAL_REMOVE_SNAP)) {
return false;
}
}
switch (value) {
case TFM_MODAL_CANCEL: {
/* TODO: Canceling with LMB is not possible when the operator is activated
@ -669,6 +682,21 @@ static bool transform_modal_item_poll(const wmOperator *op, int value)
}
break;
}
case TFM_MODAL_EDIT_SNAP_SOURCE: {
if (t->spacetype != SPACE_VIEW3D) {
return false;
}
if (!ELEM(t->mode,
TFM_TRANSLATION,
TFM_ROTATION,
TFM_RESIZE,
TFM_EDGE_SLIDE,
TFM_VERT_SLIDE)) {
/* More modes can be added over time if this feature proves useful for them. */
return false;
}
break;
}
}
return true;
}
@ -685,6 +713,7 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
{TFM_MODAL_PLANE_Y, "PLANE_Y", 0, "Y Plane", ""},
{TFM_MODAL_PLANE_Z, "PLANE_Z", 0, "Z Plane", ""},
{TFM_MODAL_CONS_OFF, "CONS_OFF", 0, "Clear Constraints", ""},
{TFM_MODAL_EDIT_SNAP_SOURCE, "EDIT_SNAP_SOURCE", 0, "Set Snap Base", ""},
{TFM_MODAL_SNAP_INV_ON, "SNAP_INV_ON", 0, "Snap Invert", ""},
{TFM_MODAL_SNAP_INV_OFF, "SNAP_INV_OFF", 0, "Snap Invert (Off)", ""},
{TFM_MODAL_SNAP_TOGGLE, "SNAP_TOGGLE", 0, "Snap Toggle", ""},
@ -954,12 +983,16 @@ int transformEvent(TransInfo *t, const wmEvent *event)
else if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
case TFM_MODAL_CANCEL:
t->state = TRANS_CANCEL;
handled = true;
if (!(t->modifiers & MOD_EDIT_SNAP_SOURCE)) {
t->state = TRANS_CANCEL;
handled = true;
}
break;
case TFM_MODAL_CONFIRM:
t->state = TRANS_CONFIRM;
handled = true;
if (!(t->modifiers & MOD_EDIT_SNAP_SOURCE)) {
t->state = TRANS_CONFIRM;
handled = true;
}
break;
case TFM_MODAL_TRANSLATE:
case TFM_MODAL_ROTATE:
@ -1244,6 +1277,12 @@ int transformEvent(TransInfo *t, const wmEvent *event)
t->redraw |= TREDRAW_HARD;
}
break;
case TFM_MODAL_EDIT_SNAP_SOURCE:
if (event->prev_val == KM_PRESS) {
transform_mode_snap_source_init(t);
t->redraw |= TREDRAW_HARD;
}
break;
default:
break;
}
@ -1751,43 +1790,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
static void initSnapSpatial(TransInfo *t, float r_snap[3], float *r_snap_precision)
{
/* Default values. */
r_snap[0] = r_snap[1] = 1.0f;
r_snap[2] = 0.0f;
*r_snap_precision = 0.1f;
if (t->spacetype == SPACE_VIEW3D) {
if (t->region->regiondata) {
View3D *v3d = t->area->spacedata.first;
r_snap[0] = r_snap[1] = r_snap[2] = ED_view3d_grid_view_scale(
t->scene, v3d, t->region, NULL);
}
}
else if (t->spacetype == SPACE_IMAGE) {
SpaceImage *sima = t->area->spacedata.first;
View2D *v2d = &t->region->v2d;
int grid_size = SI_GRID_STEPS_LEN;
float zoom_factor = ED_space_image_zoom_level(v2d, grid_size);
float grid_steps_x[SI_GRID_STEPS_LEN];
float grid_steps_y[SI_GRID_STEPS_LEN];
ED_space_image_grid_steps(sima, grid_steps_x, grid_steps_y, grid_size);
/* Snapping value based on what type of grid is used (adaptive-subdividing or custom-grid). */
r_snap[0] = ED_space_image_increment_snap_value(grid_size, grid_steps_x, zoom_factor);
r_snap[1] = ED_space_image_increment_snap_value(grid_size, grid_steps_y, zoom_factor);
*r_snap_precision = 0.5f;
}
else if (t->spacetype == SPACE_CLIP) {
r_snap[0] = r_snap[1] = 0.125f;
*r_snap_precision = 0.5f;
}
else if (t->spacetype == SPACE_NODE) {
r_snap[0] = r_snap[1] = ED_node_grid_size();
}
}
bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode)
{
int options = 0;
@ -1952,7 +1954,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
initSnapping(t, op); /* Initialize snapping data AFTER mode flags */
initSnapSpatial(t, t->snap_spatial, &t->snap_spatial_precision);
transform_snap_grid_init(t);
/* EVIL! posemode code can switch translation to rotate when 1 bone is selected.
* will be removed (ton) */

View File

@ -157,6 +157,7 @@ typedef enum {
MOD_CONSTRAINT_SELECT_PLANE = 1 << 4,
MOD_NODE_ATTACH = 1 << 5,
MOD_SNAP_FORCED = 1 << 6,
MOD_EDIT_SNAP_SOURCE = 1 << 7,
} eTModifier;
ENUM_OPERATORS(eTModifier, MOD_NODE_ATTACH)
@ -164,10 +165,8 @@ ENUM_OPERATORS(eTModifier, MOD_NODE_ATTACH)
typedef enum eTSnap {
SNAP_RESETTED = 0,
SNAP_SOURCE_FOUND = 1 << 0,
/* Special flag for snap to grid. */
SNAP_TARGET_GRID_FOUND = 1 << 1,
SNAP_TARGET_FOUND = 1 << 2,
SNAP_MULTI_POINTS = 1 << 3,
SNAP_TARGET_FOUND = 1 << 1,
SNAP_MULTI_POINTS = 1 << 2,
} eTSnap;
ENUM_OPERATORS(eTSnap, SNAP_MULTI_POINTS)
@ -270,6 +269,8 @@ enum {
TFM_MODAL_VERT_EDGE_SLIDE = 31,
TFM_MODAL_TRACKBALL = 32,
TFM_MODAL_ROTATE_NORMALS = 33,
TFM_MODAL_EDIT_SNAP_SOURCE = 34,
};
/** \} */
@ -300,7 +301,6 @@ typedef struct TransSnap {
float snap_source[3];
/** to this point (in global-space). */
float snap_target[3];
float snap_target_grid[3];
float snapNormal[3];
char snapNodeBorder;
ListBase points;
@ -768,6 +768,7 @@ void applyMouseInput(struct TransInfo *t,
const int mval[2],
float output[3]);
void transform_input_update(TransInfo *t, const float fac);
void transform_input_reset(TransInfo *t, const int mval[2]);
void setCustomPoints(TransInfo *t, MouseInput *mi, const int start[2], const int end[2]);
void setCustomPointsFromDirection(TransInfo *t, MouseInput *mi, const float dir[2]);

View File

@ -101,6 +101,20 @@ static void constraint_plane_calc(const TransInfo *t, float r_plane[4])
r_plane[3] = -dot_v3v3(r_plane, t->center_global);
}
static void constraint_axis_calc(const TransInfo *t, float r_dir[4])
{
if (t->con.mode & CON_AXIS0) {
copy_v3_v3(r_dir, t->spacemtx[0]);
}
else if (t->con.mode & CON_AXIS1) {
copy_v3_v3(r_dir, t->spacemtx[1]);
}
else {
BLI_assert(t->con.mode & CON_AXIS2);
copy_v3_v3(r_dir, t->spacemtx[2]);
}
}
void constraintNumInput(TransInfo *t, float vec[3])
{
int mode = t->con.mode;
@ -170,6 +184,20 @@ static void viewAxisCorrectCenter(const TransInfo *t, float t_con_center[3])
}
}
static bool isAxisProjectionViewAligned(const TransInfo *t, const float axis[3])
{
float angle = fabsf(angle_v3v3(axis, t->viewinv[2]));
if (angle > (float)M_PI_2) {
angle = (float)M_PI - angle;
}
if (angle < DEG2RADF(5.0f)) {
return true;
}
return false;
}
/**
* Axis calculation taking the view into account, correcting view-aligned axis.
*/
@ -178,7 +206,7 @@ static void axisProjection(const TransInfo *t,
const float in[3],
float out[3])
{
float vec[3], factor, angle;
float vec[3], factor;
float t_con_center[3];
if (is_zero_v3(in)) {
@ -190,15 +218,10 @@ static void axisProjection(const TransInfo *t,
/* checks for center being too close to the view center */
viewAxisCorrectCenter(t, t_con_center);
angle = fabsf(angle_v3v3(axis, t->viewinv[2]));
if (angle > (float)M_PI_2) {
angle = (float)M_PI - angle;
}
/* For when view is parallel to constraint... will cause NaNs otherwise
* So we take vertical motion in 3D space and apply it to the
* constraint axis. Nice for camera grab + MMB */
if (angle < DEG2RADF(5.0f)) {
if (isAxisProjectionViewAligned(t, axis)) {
project_v3_v3v3(vec, in, t->viewinv[1]);
factor = dot_v3v3(t->viewinv[1], vec) * 2.0f;
/* Since camera distance is quite relative, use quadratic relationship.
@ -434,17 +457,7 @@ static void applyAxisConstraintVec(const TransInfo *t,
}
else if (dims == 1) {
float c[3];
if (t->con.mode & CON_AXIS0) {
copy_v3_v3(c, t->spacemtx[0]);
}
else if (t->con.mode & CON_AXIS1) {
copy_v3_v3(c, t->spacemtx[1]);
}
else {
BLI_assert(t->con.mode & CON_AXIS2);
copy_v3_v3(c, t->spacemtx[2]);
}
constraint_axis_calc(t, c);
if (is_snap_to_edge) {
transform_constraint_snap_axis_to_edge(t, c, out);
@ -1250,3 +1263,34 @@ int getConstraintSpaceDimension(const TransInfo *t)
}
/** \} */
bool transform_constraint_isect_ray(const TransInfo *t,
const float ray_co[3],
const float ray_dir[3],
float out[3])
{
float lambda;
const int dims = getConstraintSpaceDimension(t);
if (dims == 2) {
float plane[4];
constraint_plane_calc(t, plane);
if (!isPlaneProjectionViewAligned(t, plane)) {
if (isect_ray_plane_v3(ray_co, ray_dir, plane, &lambda, false)) {
madd_v3_v3v3fl(out, ray_co, ray_dir, lambda);
return true;
}
}
}
else if (dims == 1) {
float axis[3];
constraint_axis_calc(t, axis);
if (!isAxisProjectionViewAligned(t, axis)) {
if (isect_ray_ray_v3(t->center_global, axis, ray_co, ray_dir, &lambda, NULL)) {
madd_v3_v3v3fl(out, t->center_global, axis, lambda);
return true;
}
}
}
return false;
}

View File

@ -7,6 +7,10 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
struct TransInfo;
void constraintNumInput(TransInfo *t, float vec[3]);
@ -57,3 +61,12 @@ bool isLockConstraint(const TransInfo *t);
* (Which could happen for weird constraints not yet designed. Along a path for example.)
*/
int getConstraintSpaceDimension(const TransInfo *t);
bool transform_constraint_isect_ray(const TransInfo *t,
const float ray_co[3],
const float ray_dir[3],
float out[3]);
#ifdef __cplusplus
}
#endif

View File

@ -1229,6 +1229,7 @@ void tranformViewUpdate(TransInfo *t)
calculateCenter2D(t);
transform_input_update(t, zoom_prev / zoom_new);
transform_snap_grid_init(t);
}
void calculatePropRatio(TransInfo *t)

View File

@ -494,4 +494,16 @@ void transform_input_update(TransInfo *t, const float fac)
}
}
void transform_input_reset(TransInfo *t, const int mval[2])
{
MouseInput *mi = &t->mouse;
copy_v2_v2_int(mi->imval, mval);
if (ELEM(mi->apply, InputAngle, InputAngleSpring)) {
struct InputAngle_Data *data = mi->data;
data->mval_prev[0] = mi->imval[0];
data->mval_prev[1] = mi->imval[1];
data->angle = 0.0f;
}
}
/** \} */

View File

@ -155,6 +155,10 @@ void initShrinkFatten(TransInfo *t);
void initSkinResize(TransInfo *t);
/* transform_mode_snapsource.c */
void transform_mode_snap_source_init(TransInfo *t);
/* transform_mode_tilt.c */
void initTilt(TransInfo *t);

View File

@ -1483,6 +1483,41 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
ED_area_status_text(t->area, str);
}
static void edge_slide_transform_matrix_fn(struct TransInfo *t, float mat_xform[4][4])
{
float delta[3], orig_co[3], final_co[3];
EdgeSlideParams *slp = t->custom.mode.data;
TransDataContainer *tc = edge_slide_container_first_ok(t);
EdgeSlideData *sld_active = tc->custom.mode.data;
TransDataEdgeSlideVert *sv_active = &sld_active->sv[sld_active->curr_sv_index];
copy_v3_v3(orig_co, sv_active->v_co_orig);
const float fac = t->values_final[0];
float curr_length_fac = 0.0f;
if (slp->use_even) {
curr_length_fac = sv_active->edge_len * (((slp->flipped ? fac : -fac) + 1.0f) / 2.0f);
}
edge_slide_apply_elem(sv_active,
fac,
curr_length_fac,
slp->curr_side_unclamp,
!(t->flag & T_ALT_TRANSFORM),
slp->use_even,
slp->flipped,
final_co);
if (tc->use_local_mat) {
mul_m4_v3(tc->mat, orig_co);
mul_m4_v3(tc->mat, final_co);
}
sub_v3_v3v3(delta, final_co, orig_co);
add_v3_v3(mat_xform[3], delta);
}
void initEdgeSlide_ex(
TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp)
{
@ -1492,7 +1527,7 @@ void initEdgeSlide_ex(
t->mode = TFM_EDGE_SLIDE;
t->transform = applyEdgeSlide;
t->handleEvent = handleEventEdgeSlide;
t->transform_matrix = NULL;
t->transform_matrix = edge_slide_transform_matrix_fn;
t->tsnap.snap_mode_apply_fn = edge_slide_snap_apply;
t->tsnap.snap_mode_distance_fn = transform_snap_distance_len_squared_fn;

View File

@ -281,11 +281,19 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
ED_area_status_text(t->area, str);
}
static void resize_transform_matrix_fn(struct TransInfo *t, float mat_xform[4][4])
{
float mat4[4][4];
copy_m4_m3(mat4, t->mat);
transform_pivot_set_m4(mat4, t->center_global);
mul_m4_m4m4(mat_xform, mat4, mat_xform);
}
void initResize(TransInfo *t, float mouse_dir_constraint[3])
{
t->mode = TFM_RESIZE;
t->transform = applyResize;
t->transform_matrix = NULL;
t->transform_matrix = resize_transform_matrix_fn;
t->tsnap.snap_mode_apply_fn = ApplySnapResize;
t->tsnap.snap_mode_distance_fn = ResizeBetween;

View File

@ -0,0 +1,247 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2001-2002 NaN Holding BV. All rights reserved. */
/** \file
* \ingroup edtransform
*/
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "DNA_windowmanager_types.h"
#include "BKE_context.h"
#include "ED_screen.h"
#include "ED_transform_snap_object_context.h"
#include "transform.h"
#include "transform_convert.h"
#include "transform_gizmo.h"
#include "transform_snap.h"
#include "transform_mode.h"
#define RESET_TRANSFORMATION
#define REMOVE_GIZMO
/* -------------------------------------------------------------------- */
/** \name Transform Element
* \{ */
/**
* \note Small arrays / data-structures should be stored copied for faster memory access.
*/
struct SnapSouceCustomData {
void (*transform_prev)(struct TransInfo *, const int[2]);
eRedrawFlag (*handleEvent_prev)(struct TransInfo *, const struct wmEvent *);
void *customdata_mode_prev;
eSnapTargetOP target_operation_prev;
struct {
void (*apply)(struct TransInfo *t,
struct MouseInput *mi,
const double mval[2],
float output[3]);
void (*post)(struct TransInfo *t, float values[3]);
bool use_virtual_mval;
} mouse_prev;
};
static void snapsource_end(TransInfo *t)
{
t->modifiers &= ~MOD_EDIT_SNAP_SOURCE;
/* Restore. */
struct SnapSouceCustomData *customdata = t->custom.mode.data;
t->transform = customdata->transform_prev;
t->custom.mode.data = customdata->customdata_mode_prev;
t->handleEvent = customdata->handleEvent_prev;
t->tsnap.target_operation = customdata->target_operation_prev;
t->mouse.apply = customdata->mouse_prev.apply;
t->mouse.post = customdata->mouse_prev.post;
t->mouse.use_virtual_mval = customdata->mouse_prev.use_virtual_mval;
transform_gizmo_3d_model_from_constraint_and_mode_set(t);
MEM_freeN(customdata);
t->tsnap.snap_source_fn = NULL;
tranform_snap_source_restore_context(t);
}
static void snapsource_confirm(TransInfo *t)
{
BLI_assert(t->modifiers & MOD_EDIT_SNAP_SOURCE);
getSnapPoint(t, t->tsnap.snap_source);
int mval[2];
#ifndef RESET_TRANSFORMATION
if (true) {
if (t->transform_matrix) {
float mat_inv[4][4];
unit_m4(mat_inv);
t->transform_matrix(t, mat_inv);
invert_m4(mat_inv);
mul_m4_v3(mat_inv, t->tsnap.snap_source);
}
else {
float mat_inv[3][3];
invert_m3_m3(mat_inv, t->mat);
mul_m3_v3(mat_inv, t->tsnap.snap_source);
sub_v3_v3(t->tsnap.snap_source, t->vec);
}
projectIntView(t, t->tsnap.snap_source, mval);
}
else
#endif
{
copy_v2_v2_int(mval, t->mval);
}
snapsource_end(t);
transform_input_reset(t, mval);
/* Remote individual snap projection since this mode does not use the new `snap_source`. */
t->tsnap.flag &= ~SCE_SNAP_PROJECT;
}
static eRedrawFlag snapsource_handle_event_fn(struct TransInfo *t, const struct wmEvent *event)
{
if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
case TFM_MODAL_CONFIRM:
case TFM_MODAL_EDIT_SNAP_SOURCE:
if (t->modifiers & MOD_EDIT_SNAP_SOURCE) {
snapsource_confirm(t);
BLI_assert(t->state != TRANS_CONFIRM);
}
else {
t->modifiers |= MOD_EDIT_SNAP_SOURCE;
}
break;
case TFM_MODAL_CANCEL:
snapsource_end(t);
t->state = TRANS_CANCEL;
return TREDRAW_SOFT;
default:
break;
}
}
else if (event->val == KM_RELEASE && t->state == TRANS_CONFIRM) {
if (t->flag & T_RELEASE_CONFIRM && t->modifiers & MOD_EDIT_SNAP_SOURCE) {
snapsource_confirm(t);
t->flag &= ~T_RELEASE_CONFIRM;
t->state = TRANS_RUNNING;
}
}
return TREDRAW_NOTHING;
}
static void snapsource_transform_fn(TransInfo *t, const int UNUSED(mval[2]))
{
BLI_assert(t->modifiers & MOD_EDIT_SNAP_SOURCE);
t->tsnap.snap_target_fn(t, NULL);
t->redraw |= TREDRAW_SOFT;
}
void transform_mode_snap_source_init(TransInfo *t)
{
if (t->transform == snapsource_transform_fn) {
/* Already running. */
return;
}
if (ELEM(t->mode, TFM_INIT, TFM_DUMMY)) {
/* Fallback */
transform_mode_init(t, NULL, TFM_TRANSLATION);
}
struct SnapSouceCustomData *customdata = MEM_callocN(sizeof(*customdata), __func__);
customdata->transform_prev = t->transform;
customdata->customdata_mode_prev = t->custom.mode.data;
customdata->handleEvent_prev = t->handleEvent;
customdata->target_operation_prev = t->tsnap.target_operation;
customdata->mouse_prev.apply = t->mouse.apply;
customdata->mouse_prev.post = t->mouse.post;
customdata->mouse_prev.use_virtual_mval = t->mouse.use_virtual_mval;
t->custom.mode.data = customdata;
// t->custom.mode.use_free = true;
t->transform = snapsource_transform_fn;
t->handleEvent = snapsource_handle_event_fn;
if (!(t->modifiers & MOD_SNAP) || !transformModeUseSnap(t)) {
t->modifiers |= (MOD_SNAP | MOD_SNAP_FORCED);
}
t->tsnap.target_operation = SCE_SNAP_TARGET_ALL;
if ((t->tsnap.status & SNAP_SOURCE_FOUND) == 0) {
if (t->tsnap.snap_source_fn) {
/* Calculate the current snap source for perpendicular snap. */
t->tsnap.snap_source_fn(t);
}
if ((t->tsnap.status & SNAP_SOURCE_FOUND) == 0) {
/* Fallback. */
copy_v3_v3(t->tsnap.snap_source, t->center_global);
t->tsnap.status |= SNAP_SOURCE_FOUND;
}
}
if (t->tsnap.mode == SCE_SNAP_MODE_INCREMENT) {
/* Initialize snap modes for geometry. */
t->tsnap.mode &= ~SCE_SNAP_MODE_INCREMENT;
t->tsnap.mode |= SCE_SNAP_MODE_GEOM | SCE_SNAP_MODE_GRID & ~SCE_SNAP_MODE_FACE_NEAREST;
}
if (t->data_type == &TransConvertType_Mesh) {
ED_transform_snap_object_context_set_editmesh_callbacks(
t->tsnap.object_context, NULL, NULL, NULL, NULL);
}
#ifdef RESET_TRANSFORMATION
/* Temporarily disable snapping.
* We don't want #SCE_SNAP_PROJECT to affect `recalcData` for example. */
t->tsnap.flag &= ~SCE_SNAP;
restoreTransObjects(t);
/* Restore snapping status. */
transform_snap_flag_from_modifiers_set(t);
/* Reset initial values to restore gizmo position. */
applyMouseInput(t, &t->mouse, t->mouse.imval, t->values_final);
#endif
#ifdef REMOVE_GIZMO
struct wmGizmo *gz = WM_gizmomap_get_modal(t->region->gizmo_map);
if (gz) {
const struct wmEvent *event = CTX_wm_window(t->context)->eventstate;
# ifdef RESET_TRANSFORMATION
wmGizmoFnModal modal_fn = gz->custom_modal ? gz->custom_modal : gz->type->modal;
modal_fn(t->context, gz, event, 0);
# endif
WM_gizmo_modal_set_while_modal(t->region->gizmo_map, t->context, NULL, event);
}
#endif
t->mouse.apply = NULL;
t->mouse.post = NULL;
t->mouse.use_virtual_mval = false;
}
/** \} */

View File

@ -348,90 +348,6 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
/** \name Transform (Translation) Snapping
* \{ */
static void translate_snap_target_grid_ensure(TransInfo *t)
{
/* Only need to calculate once. */
if ((t->tsnap.status & SNAP_TARGET_GRID_FOUND) == 0) {
if (t->data_type == &TransConvertType_Cursor3D) {
/* Use a fallback when transforming the cursor.
* In this case the center is _not_ derived from the cursor which is being transformed. */
copy_v3_v3(t->tsnap.snap_target_grid, TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->data->iloc);
}
else if (t->around == V3D_AROUND_CURSOR) {
/* Use a fallback for cursor selection,
* this isn't useful as a global center for absolute grid snapping
* since its not based on the position of the selection. */
tranform_snap_target_median_calc(t, t->tsnap.snap_target_grid);
}
else {
copy_v3_v3(t->tsnap.snap_target_grid, t->center_global);
}
t->tsnap.status |= SNAP_TARGET_GRID_FOUND;
}
}
static void translate_snap_grid_apply(TransInfo *t,
const int max_index,
const float grid_dist[3],
const float loc[3],
float r_out[3])
{
BLI_assert(max_index <= 2);
translate_snap_target_grid_ensure(t);
const float *center_global = t->tsnap.snap_target_grid;
const float *asp = t->aspect;
float in[3];
if (t->con.mode & CON_APPLY) {
BLI_assert(t->tsnap.snapElem == SCE_SNAP_MODE_NONE);
t->con.applyVec(t, NULL, NULL, loc, in);
}
else {
copy_v3_v3(in, loc);
}
for (int i = 0; i <= max_index; i++) {
const float iter_fac = grid_dist[i] * asp[i];
r_out[i] = iter_fac * roundf((in[i] + center_global[i]) / iter_fac) - center_global[i];
}
}
static bool translate_snap_grid(TransInfo *t, float *val)
{
if (!transform_snap_is_active(t)) {
return false;
}
if (!(t->tsnap.mode & SCE_SNAP_MODE_GRID) || validSnap(t)) {
/* Don't do grid snapping if there is a valid snap point. */
return false;
}
/* Don't do grid snapping if not in 3D viewport or UV editor */
if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) {
return false;
}
if (t->mode != TFM_TRANSLATION) {
return false;
}
float grid_dist[3];
copy_v3_v3(grid_dist, t->snap_spatial);
if (t->modifiers & MOD_PRECISION) {
mul_v3_fl(grid_dist, t->snap_spatial_precision);
}
/* Early bailing out if no need to snap */
if (is_zero_v3(grid_dist)) {
return false;
}
translate_snap_grid_apply(t, t->idx_max, grid_dist, val, val);
t->tsnap.snapElem = SCE_SNAP_MODE_GRID;
return true;
}
static void ApplySnapTranslation(TransInfo *t, float vec[3])
{
float point[3];
@ -459,7 +375,7 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3])
}
}
sub_v3_v3v3(vec, point, t->tsnap.snap_source);
sub_v3_v3v3(vec, point, t->tsnap.snap_source);
}
}
@ -610,7 +526,6 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
}
transform_snap_mixed_apply(t, global_dir);
translate_snap_grid(t, global_dir);
if (t->con.mode & CON_APPLY) {
float in[3];

View File

@ -609,13 +609,42 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
ED_area_status_text(t->area, str);
}
static void vert_slide_transform_matrix_fn(struct TransInfo *t, float mat_xform[4][4])
{
float delta[3], orig_co[3], final_co[3];
VertSlideParams *slp = t->custom.mode.data;
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t);
VertSlideData *sld_active = tc->custom.mode.data;
TransDataVertSlideVert *sv_active = &sld_active->sv[sld_active->curr_sv_index];
copy_v3_v3(orig_co, sv_active->co_orig_3d);
float tperc = t->values_final[0];
if (slp->use_even) {
const float edge_len_curr = len_v3v3(sv_active->co_orig_3d,
sv_active->co_link_orig_3d[sv_active->co_link_curr]);
tperc *= edge_len_curr;
}
vert_slide_apply_elem(sv_active, tperc, slp->use_even, slp->flipped, final_co);
if (tc->use_local_mat) {
mul_m4_v3(tc->mat, orig_co);
mul_m4_v3(tc->mat, final_co);
}
sub_v3_v3v3(delta, final_co, orig_co);
add_v3_v3(mat_xform[3], delta);
}
void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
{
t->mode = TFM_VERT_SLIDE;
t->transform = applyVertSlide;
t->handleEvent = handleEventVertSlide;
t->transform_matrix = NULL;
t->transform_matrix = vert_slide_transform_matrix_fn;
t->tsnap.snap_mode_apply_fn = vert_slide_snap_apply;
t->tsnap.snap_mode_distance_fn = transform_snap_distance_len_squared_fn;

View File

@ -32,6 +32,7 @@
#include "WM_types.h"
#include "ED_gizmo_library.h"
#include "ED_image.h"
#include "ED_markers.h"
#include "ED_node.h"
#include "ED_transform_snap_object_context.h"
@ -48,6 +49,7 @@
#include "MEM_guardedalloc.h"
#include "transform.h"
#include "transform_constraints.h"
#include "transform_convert.h"
#include "transform_snap.h"
@ -165,17 +167,33 @@ static bool doForceIncrementSnap(const TransInfo *t)
return !transformModeUseSnap(t);
}
static void snap_source_transformed(TransInfo *t, float r_vec[3])
{
float mat[4][4];
unit_m4(mat);
if (t->transform_matrix) {
t->transform_matrix(t, mat);
}
mul_v3_m4v3(r_vec, mat, t->tsnap.snap_source);
}
void drawSnapping(const struct bContext *C, TransInfo *t)
{
uchar col[4], selectedCol[4], activeCol[4];
if (!transform_snap_is_active(t)) {
if (!(transform_snap_is_active(t) || t->modifiers & MOD_EDIT_SNAP_SOURCE)) {
return;
}
bool draw_source = (t->spacetype == SPACE_VIEW3D) && (t->tsnap.status & SNAP_SOURCE_FOUND) &&
(t->tsnap.mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR);
const bool draw_source = (t->spacetype == SPACE_VIEW3D) &&
(t->tsnap.status & SNAP_SOURCE_FOUND) &&
(t->tsnap.mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR);
if (!(draw_source || validSnap(t))) {
bool draw_source_transformed = (t->spacetype == SPACE_VIEW3D) &&
(t->tsnap.status & SNAP_SOURCE_FOUND) &&
!(t->modifiers & MOD_EDIT_SNAP_SOURCE);
if (!(draw_source || draw_source_transformed || validSnap(t))) {
return;
}
@ -201,8 +219,8 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
GPU_depth_test(GPU_DEPTH_NONE);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
if (!BLI_listbase_is_empty(&t->tsnap.points)) {
RegionView3D *rv3d = (RegionView3D *)t->region->regiondata;
if (draw_source_transformed || !BLI_listbase_is_empty(&t->tsnap.points)) {
/* Draw snap points. */
float size = 2.0f * UI_GetThemeValuef(TH_VERTEX_SIZE);
@ -214,14 +232,68 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
LISTBASE_FOREACH (TransSnapPoint *, p, &t->tsnap.points) {
if (p == t->tsnap.selectedPoint) {
immUniformColor4ubv(selectedCol);
float snap_source_tranformed[3];
if (draw_source_transformed) {
snap_source_transformed(t, snap_source_tranformed);
}
if (!BLI_listbase_is_empty(&t->tsnap.points)) {
LISTBASE_FOREACH (TransSnapPoint *, p, &t->tsnap.points) {
if (p == t->tsnap.selectedPoint) {
immUniformColor4ubv(selectedCol);
}
else {
immUniformColor4ubv(col);
}
imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size, view_inv, pos);
}
else {
immUniformColor4ubv(col);
if (t->modifiers & MOD_EDIT_SNAP_SOURCE) {
/* Indicate the new snap source position. */
getSnapPoint(t, snap_source_tranformed);
draw_source_transformed = true;
}
imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size, view_inv, pos);
}
if (draw_source_transformed &&
!compare_v3v3(snap_source_tranformed, t->tsnap.snap_target, FLT_EPSILON))
{
float view_inv[4][4];
copy_m4_m4(view_inv, rv3d->viewinv);
float vx[3], vy[3], v[3];
float size_tmp = ED_view3d_pixel_size(rv3d, snap_source_tranformed) * size;
float size_fac = 0.5f;
mul_v3_v3fl(vx, view_inv[0], size_tmp);
mul_v3_v3fl(vy, view_inv[1], size_tmp);
immUniformColor4ubv(col);
imm_drawcircball(snap_source_tranformed, size_tmp, view_inv, pos);
immBegin(GPU_PRIM_LINES, 8);
add_v3_v3v3(v, snap_source_tranformed, vx);
immVertex3fv(pos, v);
madd_v3_v3fl(v, vx, size_fac);
immVertex3fv(pos, v);
sub_v3_v3v3(v, snap_source_tranformed, vx);
immVertex3fv(pos, v);
madd_v3_v3fl(v, vx, -size_fac);
immVertex3fv(pos, v);
add_v3_v3v3(v, snap_source_tranformed, vy);
immVertex3fv(pos, v);
madd_v3_v3fl(v, vy, size_fac);
immVertex3fv(pos, v);
sub_v3_v3v3(v, snap_source_tranformed, vy);
immVertex3fv(pos, v);
madd_v3_v3fl(v, vy, -size_fac);
immVertex3fv(pos, v);
immEnd();
}
immUnbindProgram();
@ -236,7 +308,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
loc_prev = t->tsnap.snap_source;
}
if (validSnap(t)) {
if (t->tsnap.status & SNAP_TARGET_FOUND) {
loc_cur = t->tsnap.snap_target;
}
@ -528,7 +600,7 @@ void transform_snap_mixed_apply(TransInfo *t, float *vec)
return;
}
if (t->tsnap.mode & ~(SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) {
if (t->tsnap.mode != SCE_SNAP_MODE_INCREMENT) {
double current = PIL_check_seconds_timer();
/* Time base quirky code to go around find-nearest slowness. */
@ -643,14 +715,7 @@ static eSnapMode snap_mode_from_spacetype(TransInfo *t)
}
if (t->spacetype == SPACE_IMAGE) {
eSnapMode snap_mode = eSnapMode(ts->snap_uv_mode);
if ((snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_uv_flag & SCE_SNAP_ABS_GRID) &&
(t->mode == TFM_TRANSLATION))
{
snap_mode &= ~SCE_SNAP_MODE_INCREMENT;
snap_mode |= SCE_SNAP_MODE_GRID;
}
return snap_mode;
return eSnapMode(ts->snap_uv_mode);
}
if (t->spacetype == SPACE_SEQ) {
@ -661,16 +726,7 @@ static eSnapMode snap_mode_from_spacetype(TransInfo *t)
if (t->options & (CTX_CAMERA | CTX_EDGE_DATA | CTX_PAINT_CURVE)) {
return SCE_SNAP_MODE_INCREMENT;
}
eSnapMode snap_mode = eSnapMode(ts->snap_mode);
if ((snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_flag & SCE_SNAP_ABS_GRID) &&
(t->mode == TFM_TRANSLATION))
{
/* Special case in which snap to increments is transformed to snap to grid. */
snap_mode &= ~SCE_SNAP_MODE_INCREMENT;
snap_mode |= SCE_SNAP_MODE_GRID;
}
return snap_mode;
return eSnapMode(ts->snap_mode);
}
if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) {
@ -733,6 +789,28 @@ static eSnapTargetOP snap_target_select_from_spacetype(TransInfo *t)
return ret;
}
static void snap_object_context_init(TransInfo *t)
{
if (t->data_type == &TransConvertType_Mesh) {
/* Ignore elements being transformed. */
ED_transform_snap_object_context_set_editmesh_callbacks(
t->tsnap.object_context,
(bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled,
bm_edge_is_snap_target,
bm_face_is_snap_target,
POINTER_FROM_UINT(BM_ELEM_SELECT | BM_ELEM_HIDDEN));
}
else {
/* Ignore hidden geometry in the general case. */
ED_transform_snap_object_context_set_editmesh_callbacks(
t->tsnap.object_context,
(bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled,
(bool (*)(BMEdge *, void *))BM_elem_cb_check_hflag_disabled,
(bool (*)(BMFace *, void *))BM_elem_cb_check_hflag_disabled,
POINTER_FROM_UINT(BM_ELEM_HIDDEN));
}
}
static void initSnappingMode(TransInfo *t)
{
if (!transformModeUseSnap(t)) {
@ -763,25 +841,7 @@ static void initSnappingMode(TransInfo *t)
if (t->tsnap.object_context == nullptr) {
SET_FLAG_FROM_TEST(t->tsnap.flag, snap_use_backface_culling(t), SCE_SNAP_BACKFACE_CULLING);
t->tsnap.object_context = ED_transform_snap_object_context_create(t->scene, 0);
if (t->data_type == &TransConvertType_Mesh) {
/* Ignore elements being transformed. */
ED_transform_snap_object_context_set_editmesh_callbacks(
t->tsnap.object_context,
(bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled,
bm_edge_is_snap_target,
bm_face_is_snap_target,
POINTER_FROM_UINT(BM_ELEM_SELECT | BM_ELEM_HIDDEN));
}
else {
/* Ignore hidden geometry in the general case. */
ED_transform_snap_object_context_set_editmesh_callbacks(
t->tsnap.object_context,
(bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled,
(bool (*)(BMEdge *, void *))BM_elem_cb_check_hflag_disabled,
(bool (*)(BMFace *, void *))BM_elem_cb_check_hflag_disabled,
POINTER_FROM_UINT(BM_ELEM_HIDDEN));
}
snap_object_context_init(t);
}
}
else if (t->spacetype == SPACE_SEQ) {
@ -1075,6 +1135,129 @@ void getSnapPoint(const TransInfo *t, float vec[3])
}
}
static void snap_multipoints_free(TransInfo *t)
{
if (t->tsnap.status & SNAP_MULTI_POINTS) {
BLI_freelistN(&t->tsnap.points);
t->tsnap.status &= ~SNAP_MULTI_POINTS;
t->tsnap.selectedPoint = NULL;
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Calc Snap
* \{ */
void transform_snap_grid_init(TransInfo *t)
{
/* Default values. */
float grid_dist[3] = {1.0f, 1.0f, 0.0f};
float grid_dist_precision = 0.1f;
if (t->spacetype == SPACE_VIEW3D) {
if (t->region->regiondata) {
View3D *v3d = static_cast<View3D *>(t->area->spacedata.first);
grid_dist[0] = grid_dist[1] = grid_dist[2] = ED_view3d_grid_view_scale(
t->scene, v3d, t->region, NULL);
}
}
else if (t->spacetype == SPACE_IMAGE) {
SpaceImage *sima = static_cast<SpaceImage *>(t->area->spacedata.first);
View2D *v2d = &t->region->v2d;
int grid_size = SI_GRID_STEPS_LEN;
float zoom_factor = ED_space_image_zoom_level(v2d, grid_size);
float grid_steps_x[SI_GRID_STEPS_LEN];
float grid_steps_y[SI_GRID_STEPS_LEN];
ED_space_image_grid_steps(sima, grid_steps_x, grid_steps_y, grid_size);
/* Snapping value based on what type of grid is used (adaptive-subdividing or custom-grid). */
grid_dist[0] = ED_space_image_increment_snap_value(grid_size, grid_steps_x, zoom_factor);
grid_dist[1] = ED_space_image_increment_snap_value(grid_size, grid_steps_y, zoom_factor);
grid_dist_precision = 0.5f;
}
else if (t->spacetype == SPACE_CLIP) {
grid_dist[0] = grid_dist[1] = 0.125f;
grid_dist_precision = 0.5f;
}
else if (t->spacetype == SPACE_NODE) {
grid_dist[0] = grid_dist[1] = ED_node_grid_size();
}
copy_v3_v3(t->snap_spatial, grid_dist);
t->snap_spatial_precision = grid_dist_precision;
if (t->mode == TFM_TRANSLATION) {
/* WORKAROUND: Reset incremental snap values. */
t->snap[0] = t->snap_spatial[0];
t->snap[1] = t->snap_spatial[0] * t->snap_spatial_precision;
}
}
static bool snap_grid(TransInfo *t, const float mval[2], const int val_size, float *r_val)
{
float grid_dist[3];
copy_v3_v3(grid_dist, t->snap_spatial);
if (t->modifiers & MOD_PRECISION) {
mul_v3_fl(grid_dist, t->snap_spatial_precision);
}
/* Early bailing out if no need to snap */
if (is_zero_v3(grid_dist)) {
return false;
}
if (t->spacetype == SPACE_VIEW3D) {
float ray_dir[3];
ED_view3d_win_to_ray_clipped(
t->depsgraph, t->region, (View3D *)t->view, mval, r_val, ray_dir, true);
if ((t->mode != TFM_ROTATION) && (t->con.mode & CON_APPLY)) {
if (!transform_constraint_isect_ray(t, r_val, ray_dir, r_val)) {
return false;
}
}
else {
float lambda;
float plane[4];
if (t->persp != RV3D_ORTHO) {
/* Intersect Plane Z. */
copy_v4_fl4(plane, 0.0f, 0.0f, 1.0f, 0.0f);
}
else {
plane_from_point_normal_v3(plane, t->center_global, ray_dir);
}
if (isect_ray_plane_v3(r_val, ray_dir, plane, &lambda, true)) {
madd_v3_v3fl(r_val, ray_dir, lambda);
}
else {
return false;
}
}
}
else {
const View2D *v2d = &t->region->v2d;
float scale[2], offset[2];
UI_view2d_scale_get(v2d, &scale[0], &scale[1]);
UI_view2d_view_to_region_fl(v2d, 0.0f, 0.0f, &offset[0], &offset[1]);
sub_v2_v2v2(r_val, mval, offset);
r_val[0] /= scale[0];
r_val[1] /= scale[1];
}
/* Apply. */
for (int i = 0; i < val_size; i++) {
const float iter_fac = grid_dist[i] * t->aspect[i];
r_val[i] = iter_fac * roundf(r_val[i] / iter_fac);
}
t->tsnap.snapElem = SCE_SNAP_MODE_GRID;
return true;
}
/** \} */
/* -------------------------------------------------------------------- */
@ -1087,28 +1270,31 @@ static void snap_target_view3d_fn(TransInfo *t, float * /*vec*/)
float loc[3];
float no[3];
float mval[2];
bool found = false;
eSnapMode snap_elem = SCE_SNAP_MODE_NONE;
float dist_px = SNAP_MIN_DISTANCE; /* Use a user defined value here. */
zero_v3(no); /* objects won't set this */
mval[0] = t->mval[0];
mval[1] = t->mval[1];
if (t->tsnap.mode & SCE_SNAP_MODE_GEOM) {
zero_v3(no); /* objects won't set this */
snap_elem = snapObjectsTransform(t, mval, &dist_px, loc, no);
found = (snap_elem != SCE_SNAP_MODE_NONE);
}
if ((found == false) && (t->tsnap.mode & SCE_SNAP_MODE_VOLUME)) {
bool use_peel = (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0;
found = peelObjectsTransform(t, mval, use_peel, loc, no, nullptr);
if (found) {
if ((snap_elem == SCE_SNAP_MODE_NONE) && (t->tsnap.mode & SCE_SNAP_MODE_VOLUME)) {
bool use_peel = (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0;
if (peelObjectsTransform(t, mval, use_peel, loc, no, nullptr)) {
snap_elem = SCE_SNAP_MODE_VOLUME;
}
}
if (found == true) {
if ((snap_elem == SCE_SNAP_MODE_NONE) && (t->tsnap.mode & SCE_SNAP_MODE_GRID)) {
if (snap_grid(t, mval, 3, loc)) {
snap_elem = SCE_SNAP_MODE_GRID;
}
}
if (snap_elem != SCE_SNAP_MODE_NONE) {
copy_v3_v3(t->tsnap.snap_target, loc);
copy_v3_v3(t->tsnap.snapNormal, no);
@ -1124,6 +1310,8 @@ static void snap_target_view3d_fn(TransInfo *t, float * /*vec*/)
static void snap_target_uv_fn(TransInfo *t, float * /*vec*/)
{
BLI_assert(t->spacetype == SPACE_IMAGE);
eSnapMode snap_elem = SCE_SNAP_MODE_NONE;
if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) {
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
@ -1142,13 +1330,22 @@ static void snap_target_uv_fn(TransInfo *t, float * /*vec*/)
t->tsnap.snap_target[0] *= t->aspect[0];
t->tsnap.snap_target[1] *= t->aspect[1];
t->tsnap.status |= SNAP_TARGET_FOUND;
}
else {
t->tsnap.status &= ~SNAP_TARGET_FOUND;
snap_elem = SCE_SNAP_MODE_VERTEX;
}
MEM_freeN(objects);
}
if ((snap_elem == SCE_SNAP_MODE_NONE) && (t->tsnap.mode & SCE_SNAP_MODE_GRID)) {
float mval[2];
mval[0] = t->mval[0];
mval[1] = t->mval[1];
if (snap_grid(t, mval, 2, t->tsnap.snap_target)) {
snap_elem = SCE_SNAP_MODE_GRID;
}
}
SET_FLAG_FROM_TEST(t->tsnap.status, snap_elem != SCE_SNAP_MODE_NONE, SNAP_TARGET_FOUND);
t->tsnap.snapElem = snap_elem;
}
static void snap_target_node_fn(TransInfo *t, float * /*vec*/)
@ -1616,7 +1813,7 @@ bool snapNodesTransform(
/** \} */
/* -------------------------------------------------------------------- */
/** \name snap Grid
/** \name snap Increment
* \{ */
static void snap_increment_apply_ex(const TransInfo * /*t*/,
@ -1713,6 +1910,12 @@ float transform_snap_increment_get(const TransInfo *t)
return 0.0f;
}
void tranform_snap_source_restore_context(TransInfo *t)
{
snap_object_context_init(t);
snap_multipoints_free(t);
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -38,11 +38,15 @@ bool snapNodesTransform(struct TransInfo *t,
bool transformModeUseSnap(const TransInfo *t);
void transform_snap_grid_init(TransInfo *t);
void tranform_snap_target_median_calc(const TransInfo *t, float r_median[3]);
bool transform_snap_increment_ex(const TransInfo *t, bool use_local_space, float *r_val);
bool transform_snap_increment(const TransInfo *t, float *val);
float transform_snap_increment_get(const TransInfo *t);
void tranform_snap_source_restore_context(TransInfo *t);
void transform_snap_flag_from_modifiers_set(TransInfo *t);
bool transform_snap_is_active(const TransInfo *t);

View File

@ -298,7 +298,7 @@ static SnapData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx,
else if (sod->mesh_runtime) {
if (sod->mesh_runtime != snap_object_data_editmesh_runtime_get(ob_eval)) {
if (G.moving) {
/* Hack to avoid updating while transforming. */
/* WORKAROUND: avoid updating while transforming. */
BLI_assert(!sod->treedata_editmesh.cached && !sod->cached[0] && !sod->cached[1]);
sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob_eval);
}
@ -381,11 +381,12 @@ static BVHTreeFromEditMesh *snap_object_data_editmesh_treedata_get(SnapObjectCon
em,
4,
BVHTREE_FROM_EM_LOOPTRI,
&sod->mesh_runtime->bvh_cache,
/* WORKAROUND: avoid updating while transforming. */
G.moving ? nullptr : &sod->mesh_runtime->bvh_cache,
&sod->mesh_runtime->eval_mutex);
}
}
if (treedata == nullptr || treedata->tree == nullptr) {
if (treedata->tree == nullptr) {
return nullptr;
}
@ -1263,7 +1264,7 @@ static bool nearest_world_editmesh(SnapObjectContext *sctx,
int *r_index)
{
BVHTreeFromEditMesh *treedata = snap_object_data_editmesh_treedata_get(sctx, ob_eval, em);
if (treedata == nullptr || treedata->tree == nullptr) {
if (treedata == nullptr) {
return false;
}
@ -2765,7 +2766,8 @@ static eSnapMode snapEditMesh(SnapObjectContext *sctx,
em,
2,
BVHTREE_FROM_EM_VERTS,
&sod->mesh_runtime->bvh_cache,
/* WORKAROUND: avoid updating while transforming. */
G.moving ? nullptr : &sod->mesh_runtime->bvh_cache,
&sod->mesh_runtime->eval_mutex);
}
sod->bvhtree[0] = treedata.tree;
@ -2794,7 +2796,8 @@ static eSnapMode snapEditMesh(SnapObjectContext *sctx,
em,
2,
BVHTREE_FROM_EM_EDGES,
&sod->mesh_runtime->bvh_cache,
/* WORKAROUND: avoid updating while transforming. */
G.moving ? nullptr : &sod->mesh_runtime->bvh_cache,
&sod->mesh_runtime->eval_mutex);
}
sod->bvhtree[1] = treedata.tree;
@ -3063,11 +3066,27 @@ void ED_transform_snap_object_context_set_editmesh_callbacks(
bool (*test_face_fn)(BMFace *, void *user_data),
void *user_data)
{
sctx->callbacks.edit_mesh.test_vert_fn = test_vert_fn;
sctx->callbacks.edit_mesh.test_edge_fn = test_edge_fn;
sctx->callbacks.edit_mesh.test_face_fn = test_face_fn;
bool is_cache_dirty = false;
if (sctx->callbacks.edit_mesh.test_vert_fn != test_vert_fn) {
sctx->callbacks.edit_mesh.test_vert_fn = test_vert_fn;
is_cache_dirty = true;
}
if (sctx->callbacks.edit_mesh.test_edge_fn != test_edge_fn) {
sctx->callbacks.edit_mesh.test_edge_fn = test_edge_fn;
is_cache_dirty = true;
}
if (sctx->callbacks.edit_mesh.test_face_fn != test_face_fn) {
sctx->callbacks.edit_mesh.test_face_fn = test_face_fn;
is_cache_dirty = true;
}
if (sctx->callbacks.edit_mesh.user_data != user_data) {
sctx->callbacks.edit_mesh.user_data = user_data;
is_cache_dirty = true;
}
sctx->callbacks.edit_mesh.user_data = user_data;
if (is_cache_dirty) {
sctx->editmesh_caches.clear();
}
}
bool ED_transform_snap_object_project_ray_ex(SnapObjectContext *sctx,

View File

@ -2257,7 +2257,7 @@ typedef enum eSnapFlag {
SCE_SNAP_PROJECT = (1 << 3),
/** Was `SCE_SNAP_NO_SELF`, but self should be active. */
SCE_SNAP_NOT_TO_ACTIVE = (1 << 4),
SCE_SNAP_ABS_GRID = (1 << 5),
/* SCE_SNAP_ABS_GRID = (1 << 5), */ /* UNUSED */
SCE_SNAP_BACKFACE_CULLING = (1 << 6),
SCE_SNAP_KEEP_ON_SAME_OBJECT = (1 << 7),
/** see #eSnapTargetOP */

View File

@ -150,11 +150,8 @@ const EnumPropertyItem rna_enum_mesh_select_mode_uv_items[] = {
};
const EnumPropertyItem rna_enum_snap_element_items[] = {
{SCE_SNAP_MODE_INCREMENT,
"INCREMENT",
ICON_SNAP_INCREMENT,
"Increment",
"Snap to increments of grid"},
{SCE_SNAP_MODE_INCREMENT, "INCREMENT", ICON_SNAP_INCREMENT, "Increment", "Snap to increments"},
{SCE_SNAP_MODE_GRID, "GRID", ICON_SNAP_GRID, "Grid", "Snap to grid"},
{SCE_SNAP_MODE_VERTEX, "VERTEX", ICON_SNAP_VERTEX, "Vertex", "Snap to vertices"},
{SCE_SNAP_MODE_EDGE, "EDGE", ICON_SNAP_EDGE, "Edge", "Snap to edges"},
{SCE_SNAP_MODE_FACE_RAYCAST,
@ -195,11 +192,8 @@ const EnumPropertyItem rna_enum_snap_node_element_items[] = {
#ifndef RNA_RUNTIME
static const EnumPropertyItem snap_uv_element_items[] = {
{SCE_SNAP_MODE_INCREMENT,
"INCREMENT",
ICON_SNAP_INCREMENT,
"Increment",
"Snap to increments of grid"},
{SCE_SNAP_MODE_INCREMENT, "INCREMENT", ICON_SNAP_INCREMENT, "Increment", "Snap to increments"},
{SCE_SNAP_MODE_GRID, "GRID", ICON_SNAP_GRID, "Grid", "Snap to grid"},
{SCE_SNAP_MODE_VERTEX, "VERTEX", ICON_SNAP_VERTEX, "Vertex", "Snap to vertices"},
{0, NULL, 0, NULL, NULL},
};
@ -3383,14 +3377,6 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop, "Align Rotation to Target", "Align rotation with the snapping target");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
prop = RNA_def_property(srna, "use_snap_grid_absolute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_ABS_GRID);
RNA_def_property_ui_text(
prop,
"Absolute Grid Snap",
"Absolute grid alignment while translating (based on the pivot center)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
prop = RNA_def_property(srna, "snap_elements", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "snap_mode");
RNA_def_property_enum_items(prop, rna_enum_snap_element_items);
@ -3428,14 +3414,6 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Snap UV Element", "Type of element to snap to");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
prop = RNA_def_property(srna, "use_snap_uv_grid_absolute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "snap_uv_flag", SCE_SNAP_ABS_GRID);
RNA_def_property_ui_text(
prop,
"Absolute Grid Snap",
"Absolute grid alignment while translating (based on the pivot center)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
/* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid previous ambiguity of "target"
* (now, "source" is geometry to be moved and "target" is geometry to which moved geometry is
* snapped). */