Transform: add feature to edit the 'Snap Base' #104412

Closed
Germano Cavalcante wants to merge 1 commits from mano-wii:snap_base into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
16 changed files with 551 additions and 50 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, 4):
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

@ -5892,6 +5892,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

@ -25,7 +25,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 3
#define BLENDER_FILE_SUBVERSION 5
/* 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

@ -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", ""},
@ -955,12 +984,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:
@ -1245,6 +1278,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;
}

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)
@ -270,6 +271,8 @@ enum {
TFM_MODAL_VERT_EDGE_SLIDE = 31,
TFM_MODAL_TRACKBALL = 32,
TFM_MODAL_ROTATE_NORMALS = 33,
TFM_MODAL_EDIT_SNAP_SOURCE = 34,
};
/** \} */
@ -769,6 +772,7 @@ void applyMouseInput(struct TransInfo *t,
float output[3]);
void transform_input_update(TransInfo *t, const float fac);
void transform_input_virtual_mval_reset(TransInfo *t);
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

@ -508,4 +508,16 @@ void transform_input_virtual_mval_reset(TransInfo *t)
}
}
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->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;
customdata->customdata_mode_prev = t->custom.mode.data;
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 | SCE_SNAP_MODE_GRID)) == 0) {
/* Initialize snap modes for geometry. */
t->tsnap.mode &= ~(SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID);
t->tsnap.mode |= SCE_SNAP_MODE_GEOM & ~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

@ -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

@ -165,17 +165,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 +217,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 +230,67 @@ 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 +305,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;
}
@ -737,6 +806,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)) {
@ -767,25 +858,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) {
@ -1079,6 +1152,15 @@ 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;
}
}
/** \} */
/* -------------------------------------------------------------------- */
@ -1717,6 +1799,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

@ -43,6 +43,8 @@ bool transform_snap_increment_ex(const TransInfo *t, bool use_local_space, float
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,