Transform: add feature to edit the 'Snap Base' #104443
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
case TFM_MODAL_EDIT_SNAP_SOURCE_ON:
|
||||
transform_mode_snap_source_init(t);
|
||||
t->redraw |= TREDRAW_HARD;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -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]);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
253
source/blender/editors/transform/transform_mode_snapsource.c
Normal file
253
source/blender/editors/transform/transform_mode_snapsource.c
Normal 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
Campbell Barton
commented
Prefer if callbacks use an 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,
|
||||
};
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user
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 beTFM_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.