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

Merged
Germano Cavalcante merged 1 commits from mano-wii/blender:snap_base into main 2023-06-03 04:18:55 +02:00
16 changed files with 562 additions and 50 deletions
Showing only changes of commit 8bf06f6419 - Show all commits

View File

@ -80,4 +80,16 @@ def keyconfig_update(keyconfig_data, keyconfig_version):
km_items.append(('ROTATE_NORMALS', {"type": 'N', "value": 'PRESS'}, None))
break
if keyconfig_version <= (3, 6, 3):
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"].extend(("EDIT_SNAP_SOURCE_ON", {"type": 'B', "value": 'PRESS'}, None))
km_items_data["items"].append(("EDIT_SNAP_SOURCE_OFF", {"type": 'B', "value": 'PRESS'}, None))
break
return keyconfig_data

View File

@ -5915,6 +5915,8 @@ 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_ON", {"type": 'B', "value": 'PRESS'}, None),
("EDIT_SNAP_SOURCE_OFF", {"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

@ -4037,6 +4037,8 @@ 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_ON", {"type": 'B', "value": 'PRESS'}, None),
("EDIT_SNAP_SOURCE_OFF", {"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

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

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

@ -543,6 +543,20 @@ 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_OFF) {
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
@ -670,6 +684,20 @@ static bool transform_modal_item_poll(const wmOperator *op, int value)
}
break;
}
case TFM_MODAL_EDIT_SNAP_SOURCE_OFF:
return false;
case TFM_MODAL_EDIT_SNAP_SOURCE_ON: {
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;
}
@ -686,6 +714,8 @@ 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_ON, "EDIT_SNAP_SOURCE_ON", 0, "Set Snap Base", ""},
{TFM_MODAL_EDIT_SNAP_SOURCE_OFF, "EDIT_SNAP_SOURCE_OFF", 0, "Set Snap Base (Off)", ""},
{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", ""},
@ -956,12 +986,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:
@ -1246,6 +1280,10 @@ int transformEvent(TransInfo *t, const wmEvent *event)
t->redraw |= TREDRAW_HARD;
}
break;
mano-wii marked this conversation as resolved Outdated

Note what the prev_val means in this context (while it works it's relying on some internals and isn't common usage). Arguably there should be TFM_MODAL_EDIT_SNAP_SOURCE_ENABLE / TFM_MODAL_EDIT_SNAP_SOURCE_DISABLE events to detect press release although I'm not sure this is really needed.

Note what the `prev_val` means in this context (while it works it's relying on some internals and isn't common usage). Arguably there should be `TFM_MODAL_EDIT_SNAP_SOURCE_ENABLE` / `TFM_MODAL_EDIT_SNAP_SOURCE_DISABLE` events to detect press release although I'm not sure this is really needed.
case TFM_MODAL_EDIT_SNAP_SOURCE_ON:
transform_mode_snap_source_init(t);
t->redraw |= TREDRAW_HARD;
break;
default:
break;
}

View File

@ -158,6 +158,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)
@ -271,6 +272,9 @@ enum {
TFM_MODAL_VERT_EDGE_SLIDE = 31,
TFM_MODAL_TRACKBALL = 32,
TFM_MODAL_ROTATE_NORMALS = 33,
TFM_MODAL_EDIT_SNAP_SOURCE_ON = 34,
TFM_MODAL_EDIT_SNAP_SOURCE_OFF = 35,
};
/** \} */
@ -753,6 +757,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

@ -510,4 +510,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

@ -184,6 +184,11 @@ extern TransModeInfo TransMode_shrinkfatten;
extern TransModeInfo TransMode_skinresize;
/* transform_mode_snapsource.c */
extern TransModeInfo TransMode_snapsource;
void transform_mode_snap_source_init(TransInfo *t);
/* transform_mode_tilt.c */
extern TransModeInfo TransMode_tilt;

View File

@ -1480,6 +1480,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);
}
static void initEdgeSlide_ex(
TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp)
{
@ -1585,7 +1620,7 @@ TransModeInfo TransMode_edgeslide = {
/*flags*/ T_NO_CONSTRAINT | T_NO_PROJECT,
/*init_fn*/ initEdgeSlide,
/*transform_fn*/ applyEdgeSlide,
/*transform_matrix_fn*/ NULL,
/*transform_matrix_fn*/ edge_slide_transform_matrix_fn,
/*handle_event_fn*/ handleEventEdgeSlide,
/*snap_distance_fn*/ transform_snap_distance_len_squared_fn,
/*snap_apply_fn*/ edge_slide_snap_apply,

View File

@ -286,6 +286,14 @@ 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);
}
static void initResize(TransInfo *t, wmOperator *op)
{
float mouse_dir_constraint[3];
@ -368,7 +376,7 @@ TransModeInfo TransMode_resize = {
/*flags*/ T_NULL_ONE,
/*init_fn*/ initResize,
/*transform_fn*/ applyResize,
/*transform_matrix_fn*/ NULL,
/*transform_matrix_fn*/ resize_transform_matrix_fn,
/*handle_event_fn*/ NULL,
/*snap_distance_fn*/ ResizeBetween,
/*snap_apply_fn*/ ApplySnapResize,

View File

@ -0,0 +1,253 @@
/* 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 {
TransModeInfo *mode_info_prev;
void *customdata_mode_prev;
eSnapTargetOP target_operation_prev;
struct {
void (*apply)(struct TransInfo *t,
struct MouseInput *mi,
mano-wii marked this conversation as resolved Outdated

Prefer if callbacks use an _fn suffix, especially when mixing data & callbacks in a single struct.

Prefer if callbacks use an `_fn` suffix, especially when mixing data & callbacks in a single struct.
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->mode_info = customdata->mode_info_prev;
t->custom.mode.data = customdata->customdata_mode_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_ON:
case TFM_MODAL_EDIT_SNAP_SOURCE_OFF:
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, struct wmOperator *UNUSED(op))
{
if (t->mode_info == &TransMode_snapsource) {
/* 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->mode_info_prev = t->mode_info;
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;
if (!(t->modifiers & MOD_SNAP) || !transformModeUseSnap(t)) {
t->modifiers |= (MOD_SNAP | MOD_SNAP_FORCED);
}
t->mode_info = &TransMode_snapsource;
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;
}
/** \} */
TransModeInfo TransMode_snapsource = {
/*flags*/ 0,
/*init_fn*/ transform_mode_snap_source_init,
/*transform_fn*/ snapsource_transform_fn,
/*transform_matrix_fn*/ NULL,
/*handle_event_fn*/ snapsource_handle_event_fn,
/*snap_distance_fn*/ NULL,
/*snap_apply_fn*/ NULL,
/*draw_fn*/ NULL,
};

View File

@ -610,6 +610,35 @@ 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);
}
static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
{
@ -699,7 +728,7 @@ TransModeInfo TransMode_vertslide = {
/*flags*/ T_NO_CONSTRAINT | T_NO_PROJECT,
/*init_fn*/ initVertSlide,
/*transform_fn*/ applyVertSlide,
/*transform_matrix_fn*/ NULL,
/*transform_matrix_fn*/ vert_slide_transform_matrix_fn,
/*handle_event_fn*/ handleEventVertSlide,
/*snap_distance_fn*/ transform_snap_distance_len_squared_fn,
/*snap_apply_fn*/ vert_slide_snap_apply,

View File

@ -167,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->mode_info->transform_matrix_fn) {
t->mode_info->transform_matrix_fn(t, mat);
}
mul_v3_m4v3(r_vec, mat, t->tsnap.snap_source);
}
void drawSnapping(const 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;
}
@ -203,8 +219,8 @@ void drawSnapping(const 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);
@ -216,14 +232,68 @@ void drawSnapping(const 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();
@ -238,7 +308,7 @@ void drawSnapping(const 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;
}
@ -739,6 +809,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)) {
@ -769,25 +861,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) {
@ -1081,6 +1155,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;
}
}
/** \} */
/* -------------------------------------------------------------------- */
@ -1719,6 +1802,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

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

@ -300,7 +300,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);
}
@ -383,11 +383,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;
}
@ -1265,7 +1266,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;
}
@ -2767,7 +2768,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;
@ -2796,7 +2798,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;
@ -3065,11 +3068,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,