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) {