diff options
author | Jacques Lucke <jacques@blender.org> | 2021-06-14 13:44:13 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2021-06-14 13:44:13 +0300 |
commit | dddcf1e9bbf4a6d1f4ff03eaf0cb7e9228b18ec5 (patch) | |
tree | c20defa7efd54c933d20a296abefe567909bb6c0 /source/blender/editors/transform | |
parent | 3b162b7c185d089e93d892169a458d552196b7b6 (diff) | |
parent | c9dc55301cd7903b7ef7c045d337ada29aa809a1 (diff) |
Merge branch 'master' into temp-compact-node-prototypetemp-compact-node-prototype
Diffstat (limited to 'source/blender/editors/transform')
44 files changed, 1762 insertions, 1539 deletions
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 2fbcbe22349..17bfc23aea7 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -74,7 +74,7 @@ static void drawTransformApply(const struct bContext *C, ARegion *region, void *arg); -static void initSnapSpatial(TransInfo *t, float r_snap[3]); +static void initSnapSpatial(TransInfo *t, float r_snap[2]); bool transdata_check_local_islands(TransInfo *t, short around) { @@ -724,81 +724,92 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf) static bool transform_event_modal_constraint(TransInfo *t, short modal_type) { - if (!(t->flag & T_NO_CONSTRAINT)) { - if (t->flag & T_2D_EDIT && ELEM(modal_type, TFM_MODAL_AXIS_Z, TFM_MODAL_PLANE_Z)) { + if (t->flag & T_NO_CONSTRAINT) { + return false; + } + + if (t->flag & T_2D_EDIT && ELEM(modal_type, TFM_MODAL_AXIS_Z, TFM_MODAL_PLANE_Z)) { + return false; + } + + int constraint_curr = -1; + + if (t->modifiers & (MOD_CONSTRAINT_SELECT_AXIS | MOD_CONSTRAINT_SELECT_PLANE)) { + t->modifiers &= ~(MOD_CONSTRAINT_SELECT_AXIS | MOD_CONSTRAINT_SELECT_PLANE); + + /* Avoid changing orientation in this case. */ + constraint_curr = -2; + } + else if (t->con.mode & CON_APPLY) { + constraint_curr = t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2); + } + + int constraint_new; + const char *msg_2d = "", *msg_3d = ""; + + /* Initialize */ + switch (modal_type) { + case TFM_MODAL_AXIS_X: + msg_2d = TIP_("along X"); + msg_3d = TIP_("along %s X"); + constraint_new = CON_AXIS0; + break; + case TFM_MODAL_AXIS_Y: + msg_2d = TIP_("along Y"); + msg_3d = TIP_("along %s Y"); + constraint_new = CON_AXIS1; + break; + case TFM_MODAL_AXIS_Z: + msg_2d = TIP_("along Z"); + msg_3d = TIP_("along %s Z"); + constraint_new = CON_AXIS2; + break; + case TFM_MODAL_PLANE_X: + msg_3d = TIP_("locking %s X"); + constraint_new = CON_AXIS1 | CON_AXIS2; + break; + case TFM_MODAL_PLANE_Y: + msg_3d = TIP_("locking %s Y"); + constraint_new = CON_AXIS0 | CON_AXIS2; + break; + case TFM_MODAL_PLANE_Z: + msg_3d = TIP_("locking %s Z"); + constraint_new = CON_AXIS0 | CON_AXIS1; + break; + default: + /* Invalid key */ return false; - } - int constraint_curr = (t->con.mode & CON_APPLY) ? - t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2) : - -1; - int constraint_new; - const char *msg_2d = "", *msg_3d = ""; + } - /* Initialize */ - switch (modal_type) { - case TFM_MODAL_AXIS_X: - msg_2d = TIP_("along X"); - msg_3d = TIP_("along %s X"); - constraint_new = CON_AXIS0; - break; - case TFM_MODAL_AXIS_Y: - msg_2d = TIP_("along Y"); - msg_3d = TIP_("along %s Y"); - constraint_new = CON_AXIS1; - break; - case TFM_MODAL_AXIS_Z: - msg_2d = TIP_("along Z"); - msg_3d = TIP_("along %s Z"); - constraint_new = CON_AXIS2; - break; - case TFM_MODAL_PLANE_X: - msg_3d = TIP_("locking %s X"); - constraint_new = CON_AXIS1 | CON_AXIS2; - break; - case TFM_MODAL_PLANE_Y: - msg_3d = TIP_("locking %s Y"); - constraint_new = CON_AXIS0 | CON_AXIS2; - break; - case TFM_MODAL_PLANE_Z: - msg_3d = TIP_("locking %s Z"); - constraint_new = CON_AXIS0 | CON_AXIS1; - break; - default: - /* Invalid key */ - return false; + if (t->flag & T_2D_EDIT) { + BLI_assert(modal_type < TFM_MODAL_PLANE_X); + if (constraint_new == CON_AXIS2) { + return false; } - - if (t->flag & T_2D_EDIT) { - BLI_assert(modal_type < TFM_MODAL_PLANE_X); - if (constraint_new == CON_AXIS2) { - return false; - } - if (constraint_curr == constraint_new) { - stopConstraint(t); - } - else { - setUserConstraint(t, constraint_new, msg_2d); - } + if (constraint_curr == constraint_new) { + stopConstraint(t); } else { - short orient_index = 1; - if (t->orient_curr == 0 || ELEM(constraint_curr, -1, constraint_new)) { - /* Successive presses on existing axis, cycle orientation modes. */ - orient_index = (short)((t->orient_curr + 1) % (int)ARRAY_SIZE(t->orient)); - } + setUserConstraint(t, constraint_new, msg_2d); + } + } + else { + short orient_index = 1; + if (t->orient_curr == O_DEFAULT || ELEM(constraint_curr, -1, constraint_new)) { + /* Successive presses on existing axis, cycle orientation modes. */ + orient_index = (short)((t->orient_curr + 1) % (int)ARRAY_SIZE(t->orient)); + } - transform_orientations_current_set(t, orient_index); - if (orient_index == 0) { - stopConstraint(t); - } - else { - setUserConstraint(t, constraint_new, msg_3d); - } + transform_orientations_current_set(t, orient_index); + if (orient_index == 0) { + stopConstraint(t); + } + else { + setUserConstraint(t, constraint_new, msg_3d); } - t->redraw |= TREDRAW_HARD; - return true; } - return false; + t->redraw |= TREDRAW_HARD; + return true; } int transformEvent(TransInfo *t, const wmEvent *event) @@ -814,7 +825,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) handled = true; } else if (event->type == MOUSEMOVE) { - if (t->modifiers & (MOD_CONSTRAINT_SELECT | MOD_CONSTRAINT_PLANE)) { + if (t->modifiers & (MOD_CONSTRAINT_SELECT_AXIS | MOD_CONSTRAINT_SELECT_PLANE)) { t->con.mode |= CON_SELECT; } @@ -1062,10 +1073,10 @@ int transformEvent(TransInfo *t, const wmEvent *event) t->state = TRANS_CONFIRM; } else if ((t->flag & T_NO_CONSTRAINT) == 0) { - if (t->modifiers & (MOD_CONSTRAINT_SELECT | MOD_CONSTRAINT_PLANE)) { + if (t->modifiers & (MOD_CONSTRAINT_SELECT_AXIS | MOD_CONSTRAINT_SELECT_PLANE)) { /* Confirm. */ postSelectConstraint(t); - t->modifiers &= ~(MOD_CONSTRAINT_SELECT | MOD_CONSTRAINT_PLANE); + t->modifiers &= ~(MOD_CONSTRAINT_SELECT_AXIS | MOD_CONSTRAINT_SELECT_PLANE); } else { if (t->options & CTX_CAMERA) { @@ -1079,8 +1090,9 @@ int transformEvent(TransInfo *t, const wmEvent *event) } } else { - t->modifiers |= (event->val == TFM_MODAL_AUTOCONSTRAINT) ? MOD_CONSTRAINT_SELECT : - MOD_CONSTRAINT_PLANE; + t->modifiers |= (event->val == TFM_MODAL_AUTOCONSTRAINT) ? + MOD_CONSTRAINT_SELECT_AXIS : + MOD_CONSTRAINT_SELECT_PLANE; if (t->con.mode & CON_APPLY) { stopConstraint(t); } @@ -1412,25 +1424,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) ToolSettings *ts = CTX_data_tool_settings(C); PropertyRNA *prop; - if (!(t->con.mode & CON_APPLY) && (t->flag & T_MODAL) && - ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE)) { - /* When redoing these modes the first time, it's more convenient to save - * in the Global orientation. */ - if (t->mode == TFM_TRANSLATION) { - mul_m3_v3(t->spacemtx, t->values_final); - } - else { - float tmat[3][3], sizemat[3][3]; - size_to_mat3(sizemat, t->values_final); - mul_m3_m3m3(tmat, t->spacemtx, sizemat); - mat3_to_size(t->values_final, tmat); - } - - BLI_assert(t->orient_curr == 0); - unit_m3(t->spacemtx); - t->orient[0].type = V3D_ORIENT_GLOBAL; - } - /* Save back mode in case we're in the generic operator */ if ((prop = RNA_struct_find_property(op->ptr, "mode"))) { RNA_property_enum_set(op->ptr, prop, t->mode); @@ -1638,7 +1631,7 @@ static void initSnapSpatial(TransInfo *t, float r_snap[2]) /** * \note caller needs to free 't' on a 0 return - * \warning \a event might be NULL (when tweaking from redo panel) + * \warning \a event might be NULL (when tweaking from redo panel) * \see #saveTransform which writes these values back. */ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode) diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index f2d5800abb7..f0ced665679 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -46,6 +46,7 @@ * \{ */ struct ARegion; +struct BMPartialUpdate; struct Depsgraph; struct NumInput; struct Object; @@ -88,12 +89,11 @@ typedef enum { CTX_TEXTURE_SPACE = (1 << 9), CTX_NO_PET = (1 << 10), - CTX_NO_MIRROR = (1 << 11), - CTX_AUTOCONFIRM = (1 << 12), + CTX_AUTOCONFIRM = (1 << 11), /** When transforming object's, adjust the object data so it stays in the same place. */ - CTX_OBMODE_XFORM_OBDATA = (1 << 13), + CTX_OBMODE_XFORM_OBDATA = (1 << 12), /** Transform object parents without moving their children. */ - CTX_OBMODE_XFORM_SKIP_CHILDREN = (1 << 14), + CTX_OBMODE_XFORM_SKIP_CHILDREN = (1 << 13), } eTContext; /** #TransInfo.flag */ @@ -105,60 +105,59 @@ typedef enum { /** restrictions flags */ T_NO_CONSTRAINT = 1 << 2, T_NULL_ONE = 1 << 3, - T_NO_ZERO = 1 << 4, - T_ALL_RESTRICTIONS = T_NO_CONSTRAINT | T_NULL_ONE | T_NO_ZERO, + T_ALL_RESTRICTIONS = T_NO_CONSTRAINT | T_NULL_ONE, - T_PROP_EDIT = 1 << 5, - T_PROP_CONNECTED = 1 << 6, - T_PROP_PROJECTED = 1 << 7, + T_PROP_EDIT = 1 << 4, + T_PROP_CONNECTED = 1 << 5, + T_PROP_PROJECTED = 1 << 6, T_PROP_EDIT_ALL = T_PROP_EDIT | T_PROP_CONNECTED | T_PROP_PROJECTED, - T_V3D_ALIGN = 1 << 8, + T_V3D_ALIGN = 1 << 7, /** For 2D views such as UV or f-curve. */ - T_2D_EDIT = 1 << 9, - T_CLIP_UV = 1 << 10, + T_2D_EDIT = 1 << 8, + T_CLIP_UV = 1 << 9, /** Auto-IK is on. */ - T_AUTOIK = 1 << 11, + T_AUTOIK = 1 << 10, /** Don't use mirror even if the data-block option is set. */ - T_NO_MIRROR = 1 << 12, + T_NO_MIRROR = 1 << 11, /** To indicate that the value set in the `value` parameter is the final * value of the transformation, modified only by the constrain. */ - T_INPUT_IS_VALUES_FINAL = 1 << 13, + T_INPUT_IS_VALUES_FINAL = 1 << 12, /** To specify if we save back settings at the end. */ - T_MODAL = 1 << 14, + T_MODAL = 1 << 13, /** No re-topology (projection). */ - T_NO_PROJECT = 1 << 15, + T_NO_PROJECT = 1 << 14, - T_RELEASE_CONFIRM = 1 << 16, + T_RELEASE_CONFIRM = 1 << 15, /** Alternative transformation. used to add offset to tracking markers. */ - T_ALT_TRANSFORM = 1 << 17, + T_ALT_TRANSFORM = 1 << 16, /** #TransInfo.center has been set, don't change it. */ - T_OVERRIDE_CENTER = 1 << 18, + T_OVERRIDE_CENTER = 1 << 17, - T_MODAL_CURSOR_SET = 1 << 19, + T_MODAL_CURSOR_SET = 1 << 18, - T_CLNOR_REBUILD = 1 << 20, + T_CLNOR_REBUILD = 1 << 19, /** Merges unselected into selected after transforming (runs after transforming). */ - T_AUTOMERGE = 1 << 21, + T_AUTOMERGE = 1 << 20, /** Runs auto-merge & splits. */ - T_AUTOSPLIT = 1 << 22, + T_AUTOSPLIT = 1 << 21, } eTFlag; /** #TransInfo.modifiers */ typedef enum { - MOD_CONSTRAINT_SELECT = 1 << 0, + MOD_CONSTRAINT_SELECT_AXIS = 1 << 0, MOD_PRECISION = 1 << 1, MOD_SNAP = 1 << 2, MOD_SNAP_INVERT = 1 << 3, - MOD_CONSTRAINT_PLANE = 1 << 4, + MOD_CONSTRAINT_SELECT_PLANE = 1 << 4, } eTModifier; /** #TransSnap.status */ @@ -432,14 +431,14 @@ typedef struct TransCustomDataContainer { /** * Container for Transform Data * - * Used to implement multi-object modes, so each object can have it's + * Used to implement multi-object modes, so each object can have its * own data array as well as object matrix, local center etc. * * Anything that can't be shared between all objects * and doesn't make sense to store for every vertex (in the #TransDataContainer.data). * * \note at some point this could be used to store non object containers - * although this only makes sense if each container has it's own matrices, + * although this only makes sense if each container has its own matrices, * otherwise all elements may as well be stored in one array (#TransDataContainer.data), * as is already done for curve-objects, f-curves. etc. */ @@ -598,11 +597,18 @@ typedef struct TransInfo { * mouse button then.) */ bool is_launch_event_tweak; + bool is_orient_set; + struct { short type; float matrix[3][3]; } orient[3]; - short orient_curr; + + enum { + O_DEFAULT = 0, + O_SCENE, + O_SET, + } orient_curr; /** backup from view3d, to restore on end. */ short gizmo_flag; diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 2037981e655..8c74d5349ba 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -953,9 +953,8 @@ void startConstraint(TransInfo *t) void stopConstraint(TransInfo *t) { - if (t->orient_curr != 0) { - t->orient_curr = 0; - transform_orientations_current_set(t, t->orient_curr); + if (t->orient_curr != O_DEFAULT) { + transform_orientations_current_set(t, O_DEFAULT); } t->con.mode &= ~(CON_APPLY | CON_SELECT); @@ -971,12 +970,11 @@ void stopConstraint(TransInfo *t) void initSelectConstraint(TransInfo *t) { - if (t->orient_curr == 0) { - transform_orientations_current_set(t, 1); + if (t->orient_curr == O_DEFAULT) { + transform_orientations_current_set(t, O_SCENE); } setUserConstraint(t, CON_APPLY | CON_SELECT, "%s"); - setNearestAxis(t); } void selectConstraint(TransInfo *t) @@ -1063,7 +1061,7 @@ static void setNearestAxis3d(TransInfo *t) } if (len[0] <= len[1] && len[0] <= len[2]) { - if (t->modifiers & MOD_CONSTRAINT_PLANE) { + if (t->modifiers & MOD_CONSTRAINT_SELECT_PLANE) { t->con.mode |= (CON_AXIS1 | CON_AXIS2); BLI_snprintf(t->con.text, sizeof(t->con.text), TIP_(" locking %s X axis"), t->spacename); } @@ -1073,7 +1071,7 @@ static void setNearestAxis3d(TransInfo *t) } } else if (len[1] <= len[0] && len[1] <= len[2]) { - if (t->modifiers & MOD_CONSTRAINT_PLANE) { + if (t->modifiers & MOD_CONSTRAINT_SELECT_PLANE) { t->con.mode |= (CON_AXIS0 | CON_AXIS2); BLI_snprintf(t->con.text, sizeof(t->con.text), TIP_(" locking %s Y axis"), t->spacename); } @@ -1083,7 +1081,7 @@ static void setNearestAxis3d(TransInfo *t) } } else if (len[2] <= len[1] && len[2] <= len[0]) { - if (t->modifiers & MOD_CONSTRAINT_PLANE) { + if (t->modifiers & MOD_CONSTRAINT_SELECT_PLANE) { t->con.mode |= (CON_AXIS0 | CON_AXIS1); BLI_snprintf(t->con.text, sizeof(t->con.text), TIP_(" locking %s Z axis"), t->spacename); } diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index c021c084a23..9e285dd2d26 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -37,6 +37,7 @@ #include "BKE_context.h" #include "BKE_fcurve.h" #include "BKE_global.h" +#include "BKE_image.h" #include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_main.h" @@ -505,9 +506,27 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize) bool clipx = true, clipy = true; float min[2], max[2]; - min[0] = min[1] = 0.0f; - max[0] = t->aspect[0]; - max[1] = t->aspect[1]; + /* Check if the current image in UV editor is a tiled image or not. */ + const SpaceImage *sima = t->area->spacedata.first; + const Image *image = sima->image; + const bool is_tiled_image = image && (image->source == IMA_SRC_TILED); + /* Stores the coordinates of the closest UDIM tile. + * Also acts as an offset to the tile from the origin of UV space. */ + float base_offset[2] = {0.0f, 0.0f}; + + /* If tiled image then constrain to correct/closest UDIM tile, else 0-1 UV space. */ + if (is_tiled_image) { + int nearest_tile_index = BKE_image_find_nearest_tile(image, t->center_global); + if (nearest_tile_index != -1) { + nearest_tile_index -= 1001; + /* Getting coordinates of nearest tile from the tile index. */ + base_offset[0] = nearest_tile_index % 10; + base_offset[1] = nearest_tile_index / 10; + } + } + + min[0] = min[1] = FLT_MAX; + max[0] = max[1] = FLT_MIN; FOREACH_TRANS_DATA_CONTAINER (t, tc) { @@ -520,42 +539,48 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize) } if (resize) { - if (min[0] < 0.0f && t->center_global[0] > 0.0f && t->center_global[0] < t->aspect[0] * 0.5f) { - vec[0] *= t->center_global[0] / (t->center_global[0] - min[0]); + if (min[0] < base_offset[0] && t->center_global[0] > base_offset[0] && + t->center_global[0] < base_offset[0] + (t->aspect[0] * 0.5f)) { + vec[0] *= (t->center_global[0] - base_offset[0]) / (t->center_global[0] - min[0]); } - else if (max[0] > t->aspect[0] && t->center_global[0] < t->aspect[0]) { - vec[0] *= (t->center_global[0] - t->aspect[0]) / (t->center_global[0] - max[0]); + else if (max[0] > (base_offset[0] + t->aspect[0]) && + t->center_global[0] < (base_offset[0] + t->aspect[0])) { + vec[0] *= (t->center_global[0] - (base_offset[0] + t->aspect[0])) / + (t->center_global[0] - max[0]); } else { clipx = 0; } - if (min[1] < 0.0f && t->center_global[1] > 0.0f && t->center_global[1] < t->aspect[1] * 0.5f) { - vec[1] *= t->center_global[1] / (t->center_global[1] - min[1]); + if (min[1] < base_offset[1] && t->center_global[1] > base_offset[1] && + t->center_global[1] < base_offset[1] + (t->aspect[1] * 0.5f)) { + vec[1] *= (t->center_global[1] - base_offset[1]) / (t->center_global[1] - min[1]); } - else if (max[1] > t->aspect[1] && t->center_global[1] < t->aspect[1]) { - vec[1] *= (t->center_global[1] - t->aspect[1]) / (t->center_global[1] - max[1]); + else if (max[1] > (base_offset[1] + t->aspect[1]) && + t->center_global[1] < (base_offset[1] + t->aspect[1])) { + vec[1] *= (t->center_global[1] - (base_offset[1] + t->aspect[1])) / + (t->center_global[1] - max[1]); } else { clipy = 0; } } else { - if (min[0] < 0.0f) { - vec[0] -= min[0]; + if (min[0] < base_offset[0]) { + vec[0] += base_offset[0] - min[0]; } - else if (max[0] > t->aspect[0]) { - vec[0] -= max[0] - t->aspect[0]; + else if (max[0] > base_offset[0] + t->aspect[0]) { + vec[0] -= max[0] - base_offset[0] - t->aspect[0]; } else { clipx = 0; } - if (min[1] < 0.0f) { - vec[1] -= min[1]; + if (min[1] < base_offset[1]) { + vec[1] += base_offset[1] - min[1]; } - else if (max[1] > t->aspect[1]) { - vec[1] -= max[1] - t->aspect[1]; + else if (max[1] > base_offset[1] + t->aspect[1]) { + vec[1] -= max[1] - base_offset[1] - t->aspect[1]; } else { clipy = 0; @@ -1122,8 +1147,7 @@ static void init_TransDataContainers(TransInfo *t, for (int i = 0; i < objects_len; i++) { TransDataContainer *tc = &t->data_container[i]; - if (((t->flag & T_NO_MIRROR) == 0) && ((t->options & CTX_NO_MIRROR) == 0) && - (objects[i]->type == OB_MESH)) { + if (!(t->flag & T_NO_MIRROR) && (objects[i]->type == OB_MESH)) { tc->use_mirror_axis_x = (((Mesh *)objects[i]->data)->symmetry & ME_SYMMETRY_X) != 0; tc->use_mirror_axis_y = (((Mesh *)objects[i]->data)->symmetry & ME_SYMMETRY_Y) != 0; tc->use_mirror_axis_z = (((Mesh *)objects[i]->data)->symmetry & ME_SYMMETRY_Z) != 0; @@ -1472,91 +1496,89 @@ void createTransData(bContext *C, TransInfo *t) /** \name Transform Data Recalc/Flush * \{ */ -void clipMirrorModifier(TransInfo *t) +void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc) { - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - Object *ob = tc->obedit; - ModifierData *md = ob->modifiers.first; - float tolerance[3] = {0.0f, 0.0f, 0.0f}; - int axis = 0; - - for (; md; md = md->next) { - if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) { - MirrorModifierData *mmd = (MirrorModifierData *)md; - - if (mmd->flag & MOD_MIR_CLIPPING) { - axis = 0; - if (mmd->flag & MOD_MIR_AXIS_X) { - axis |= 1; - tolerance[0] = mmd->tolerance; - } - if (mmd->flag & MOD_MIR_AXIS_Y) { - axis |= 2; - tolerance[1] = mmd->tolerance; - } - if (mmd->flag & MOD_MIR_AXIS_Z) { - axis |= 4; - tolerance[2] = mmd->tolerance; - } - if (axis) { - float mtx[4][4], imtx[4][4]; - int i; + Object *ob = tc->obedit; + ModifierData *md = ob->modifiers.first; + float tolerance[3] = {0.0f, 0.0f, 0.0f}; + int axis = 0; + + for (; md; md = md->next) { + if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) { + MirrorModifierData *mmd = (MirrorModifierData *)md; + + if (mmd->flag & MOD_MIR_CLIPPING) { + axis = 0; + if (mmd->flag & MOD_MIR_AXIS_X) { + axis |= 1; + tolerance[0] = mmd->tolerance; + } + if (mmd->flag & MOD_MIR_AXIS_Y) { + axis |= 2; + tolerance[1] = mmd->tolerance; + } + if (mmd->flag & MOD_MIR_AXIS_Z) { + axis |= 4; + tolerance[2] = mmd->tolerance; + } + if (axis) { + float mtx[4][4], imtx[4][4]; + int i; - if (mmd->mirror_ob) { - float obinv[4][4]; + if (mmd->mirror_ob) { + float obinv[4][4]; - invert_m4_m4(obinv, mmd->mirror_ob->obmat); - mul_m4_m4m4(mtx, obinv, ob->obmat); - invert_m4_m4(imtx, mtx); - } + invert_m4_m4(obinv, mmd->mirror_ob->obmat); + mul_m4_m4m4(mtx, obinv, ob->obmat); + invert_m4_m4(imtx, mtx); + } - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - int clip; - float loc[3], iloc[3]; + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + int clip; + float loc[3], iloc[3]; - if (td->loc == NULL) { - break; - } + if (td->loc == NULL) { + break; + } - if (td->flag & TD_SKIP) { - continue; - } + if (td->flag & TD_SKIP) { + continue; + } - copy_v3_v3(loc, td->loc); - copy_v3_v3(iloc, td->iloc); + copy_v3_v3(loc, td->loc); + copy_v3_v3(iloc, td->iloc); - if (mmd->mirror_ob) { - mul_m4_v3(mtx, loc); - mul_m4_v3(mtx, iloc); - } + if (mmd->mirror_ob) { + mul_m4_v3(mtx, loc); + mul_m4_v3(mtx, iloc); + } - clip = 0; - if (axis & 1) { - if (fabsf(iloc[0]) <= tolerance[0] || loc[0] * iloc[0] < 0.0f) { - loc[0] = 0.0f; - clip = 1; - } + clip = 0; + if (axis & 1) { + if (fabsf(iloc[0]) <= tolerance[0] || loc[0] * iloc[0] < 0.0f) { + loc[0] = 0.0f; + clip = 1; } + } - if (axis & 2) { - if (fabsf(iloc[1]) <= tolerance[1] || loc[1] * iloc[1] < 0.0f) { - loc[1] = 0.0f; - clip = 1; - } + if (axis & 2) { + if (fabsf(iloc[1]) <= tolerance[1] || loc[1] * iloc[1] < 0.0f) { + loc[1] = 0.0f; + clip = 1; } - if (axis & 4) { - if (fabsf(iloc[2]) <= tolerance[2] || loc[2] * iloc[2] < 0.0f) { - loc[2] = 0.0f; - clip = 1; - } + } + if (axis & 4) { + if (fabsf(iloc[2]) <= tolerance[2] || loc[2] * iloc[2] < 0.0f) { + loc[2] = 0.0f; + clip = 1; } - if (clip) { - if (mmd->mirror_ob) { - mul_m4_v3(imtx, loc); - } - copy_v3_v3(td->loc, loc); + } + if (clip) { + if (mmd->mirror_ob) { + mul_m4_v3(imtx, loc); } + copy_v3_v3(td->loc, loc); } } } @@ -1644,38 +1666,6 @@ void animrecord_check_state(TransInfo *t, struct Object *ob) } } -static void recalcData_cursor_image(TransInfo *t) -{ - TransDataContainer *tc = t->data_container; - TransData *td = tc->data; - float aspect_inv[2]; - - aspect_inv[0] = 1.0f / t->aspect[0]; - aspect_inv[1] = 1.0f / t->aspect[1]; - - td->loc[0] = td->loc[0] * aspect_inv[0]; - td->loc[1] = td->loc[1] * aspect_inv[1]; - - DEG_id_tag_update(&t->scene->id, ID_RECALC_COPY_ON_WRITE); -} - -static void recalcData_cursor(TransInfo *t) -{ - DEG_id_tag_update(&t->scene->id, ID_RECALC_COPY_ON_WRITE); -} - -static void recalcData_obedit(TransInfo *t) -{ - if (t->state != TRANS_CANCEL) { - applyProject(t); - } - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - if (tc->data_len) { - DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */ - } - } -} - /* called for updating while transform acts, once per redraw */ void recalcData(TransInfo *t) { @@ -1708,9 +1698,11 @@ void recalcData(TransInfo *t) recalcData_mask_common(t); break; case TC_MESH_VERTS: - case TC_MESH_EDGES: recalcData_mesh(t); break; + case TC_MESH_EDGES: + recalcData_mesh_edge(t); + break; case TC_MESH_SKIN: recalcData_mesh_skin(t); break; @@ -1742,7 +1734,7 @@ void recalcData(TransInfo *t) recalcData_tracking(t); break; case TC_MBALL_VERTS: - recalcData_obedit(t); + recalcData_mball(t); break; case TC_LATTICE_VERTS: recalcData_lattice(t); diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index 36a51d57f64..918ce0739ed 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -45,7 +45,7 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize); void clipUVData(TransInfo *t); /* transform_convert_mesh.c */ -void mesh_customdatacorrect_init(TransInfo *t); +void transform_convert_mesh_customdatacorrect_init(TransInfo *t); /* transform_convert_sequencer.c */ int transform_convert_sequencer_get_snap_bound(TransInfo *t); @@ -62,7 +62,7 @@ void calc_distanceCurveVerts(TransData *head, TransData *tail, bool cyclic); struct TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt); char transform_convert_frame_side_dir_get(TransInfo *t, float cframe); bool FrameOnMouseSide(char side, float frame, float cframe); -void clipMirrorModifier(TransInfo *t); +void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc); void animrecord_check_state(TransInfo *t, struct Object *ob); /* transform_convert_action.c */ @@ -84,6 +84,8 @@ void special_aftertrans_update__pose(bContext *C, TransInfo *t); /* transform_convert_cursor.c */ void createTransCursor_image(TransInfo *t); void createTransCursor_view3d(TransInfo *t); +void recalcData_cursor_image(TransInfo *t); +void recalcData_cursor(TransInfo *t); /* transform_convert_curve.c */ void createTransCurveVerts(TransInfo *t); @@ -109,6 +111,7 @@ void special_aftertrans_update__mask(bContext *C, TransInfo *t); /* transform_convert_mball.c */ void createTransMBallVerts(TransInfo *t); +void recalcData_mball(TransInfo *t); /* transform_convert_mesh.c */ struct TransIslandData { @@ -166,6 +169,7 @@ void special_aftertrans_update__mesh(bContext *C, TransInfo *t); /* transform_convert_mesh_edge.c */ void createTransEdge(TransInfo *t); +void recalcData_mesh_edge(TransInfo *t); /* transform_convert_mesh_skin.c */ void createTransMeshSkin(TransInfo *t); diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index a4edf51ffee..aaea9d05f84 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -99,15 +99,7 @@ static void autokeyframe_pose( bPoseChannel *pchan; FCurve *fcu; - /* TODO: this should probably be done per channel instead. */ if (!autokeyframe_cfra_can_key(scene, id)) { - /* tag channels that should have unkeyed data */ - for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - if (pchan->bone->flag & BONE_TRANSFORM) { - /* tag this channel */ - pchan->bone->flag |= BONE_UNKEYED; - } - } return; } @@ -139,9 +131,6 @@ static void autokeyframe_pose( ListBase dsources = {NULL, NULL}; - /* clear any 'unkeyed' flag it may have */ - pchan->bone->flag &= ~BONE_UNKEYED; - /* add datasource override for the camera object */ ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan); @@ -1279,9 +1268,6 @@ void recalcData_edit_armature(TransInfo *t) restoreBones(tc); } } - - /* Tag for redraw/invalidate overlay cache. */ - DEG_id_tag_update(&arm->id, ID_RECALC_SELECT); } } diff --git a/source/blender/editors/transform/transform_convert_cursor.c b/source/blender/editors/transform/transform_convert_cursor.c index 67d85f9610b..1f3eff31205 100644 --- a/source/blender/editors/transform/transform_convert_cursor.c +++ b/source/blender/editors/transform/transform_convert_cursor.c @@ -134,3 +134,29 @@ void createTransCursor_view3d(TransInfo *t) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Recalc Cursor + * \{ */ + +void recalcData_cursor_image(TransInfo *t) +{ + TransDataContainer *tc = t->data_container; + TransData *td = tc->data; + float aspect_inv[2]; + + aspect_inv[0] = 1.0f / t->aspect[0]; + aspect_inv[1] = 1.0f / t->aspect[1]; + + td->loc[0] = td->loc[0] * aspect_inv[0]; + td->loc[1] = td->loc[1] * aspect_inv[1]; + + DEG_id_tag_update(&t->scene->id, ID_RECALC_COPY_ON_WRITE); +} + +void recalcData_cursor(TransInfo *t) +{ + DEG_id_tag_update(&t->scene->id, ID_RECALC_COPY_ON_WRITE); +} + +/** \} */ diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c index bef3eca0d9d..e57fd85470f 100644 --- a/source/blender/editors/transform/transform_convert_curve.c +++ b/source/blender/editors/transform/transform_convert_curve.c @@ -441,7 +441,6 @@ void createTransCurveVerts(TransInfo *t) void recalcData_curve(TransInfo *t) { if (t->state != TRANS_CANCEL) { - clipMirrorModifier(t); applyProject(t); } @@ -450,7 +449,7 @@ void recalcData_curve(TransInfo *t) ListBase *nurbs = BKE_curve_editNurbs_get(cu); Nurb *nu = nurbs->first; - DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */ + DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY); if (t->state == TRANS_CANCEL) { while (nu) { @@ -460,12 +459,11 @@ void recalcData_curve(TransInfo *t) } } else { - /* Normal updating */ - while (nu) { - BKE_nurb_test_2d(nu); - BKE_nurb_handles_calc(nu); - nu = nu->next; - } + /* Apply clipping after so we never project past the clip plane T25423. */ + transform_convert_clip_mirror_modifier_apply(tc); + + /* Normal updating. */ + BKE_curve_dimension_update(cu); } } } diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c index 45df0e66691..4932a5f8d23 100644 --- a/source/blender/editors/transform/transform_convert_gpencil.c +++ b/source/blender/editors/transform/transform_convert_gpencil.c @@ -78,14 +78,12 @@ static short get_bezt_sel_triple_flag(BezTriple *bezt, const bool handles_visibl flag = ((bezt->f1 & SELECT) ? SEL_F1 : 0) | ((bezt->f2 & SELECT) ? SEL_F2 : 0) | ((bezt->f3 & SELECT) ? SEL_F3 : 0); } - else { - if (bezt->f2 & SELECT) { - flag = SEL_ALL; - } + else if (bezt->f2 & SELECT) { + flag = SEL_ALL; } /* Special case for auto & aligned handles */ - if (flag != SEL_ALL && flag & SEL_F2) { + if ((flag != SEL_ALL) && (flag & SEL_F2)) { if (ELEM(bezt->h1, HD_AUTO, HD_ALIGN) && ELEM(bezt->h2, HD_AUTO, HD_ALIGN)) { flag = SEL_ALL; } @@ -316,7 +314,7 @@ static void createTransGPencil_curves(bContext *C, } } else if (handles_visible) { - if (BEZT_ISSEL_IDX(bezt, j)) { + if (sel) { td->flag = TD_SELECTED; } else { diff --git a/source/blender/editors/transform/transform_convert_lattice.c b/source/blender/editors/transform/transform_convert_lattice.c index 20ac7dcb998..fbfce41d555 100644 --- a/source/blender/editors/transform/transform_convert_lattice.c +++ b/source/blender/editors/transform/transform_convert_lattice.c @@ -122,7 +122,7 @@ void recalcData_lattice(TransInfo *t) FOREACH_TRANS_DATA_CONTAINER (t, tc) { Lattice *la = tc->obedit->data; - DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */ + DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY); if (la->editlatt->latt->flag & LT_OUTSIDE) { outside_lattice(la->editlatt->latt); } diff --git a/source/blender/editors/transform/transform_convert_mball.c b/source/blender/editors/transform/transform_convert_mball.c index 6f5c0318054..f38f3ccf421 100644 --- a/source/blender/editors/transform/transform_convert_mball.c +++ b/source/blender/editors/transform/transform_convert_mball.c @@ -30,6 +30,8 @@ #include "BKE_context.h" #include "transform.h" +#include "transform_snap.h" + #include "transform_convert.h" /* -------------------------------------------------------------------- */ @@ -128,3 +130,21 @@ void createTransMBallVerts(TransInfo *t) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Recalc Meta Ball + * \{ */ + +void recalcData_mball(TransInfo *t) +{ + if (t->state != TRANS_CANCEL) { + applyProject(t); + } + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + if (tc->data_len) { + DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY); + } + } +} + +/** \} */ diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index 93c36645873..422370cb13b 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -48,7 +48,637 @@ #include "transform_convert.h" +/* -------------------------------------------------------------------- */ +/** \name Container TransCustomData Creation + * \{ */ + +static void tc_mesh_customdata_free_fn(struct TransInfo *t, + struct TransDataContainer *tc, + struct TransCustomData *custom_data); + +struct TransCustomDataLayer; +static void tc_mesh_customdatacorrect_free(struct TransCustomDataLayer *tcld); + +struct TransCustomDataMesh { + struct TransCustomDataLayer *cd_layer_correct; + struct { + struct BMPartialUpdate *cache; + + /** The size of proportional editing used for `partial_update_cache`. */ + float prop_size; + /** The size of proportional editing for the last update. */ + float prop_size_prev; + } partial_update; +}; + +static struct TransCustomDataMesh *tc_mesh_customdata_ensure(TransDataContainer *tc) +{ + struct TransCustomDataMesh *tcmd = tc->custom.type.data; + BLI_assert(tc->custom.type.data == NULL || + tc->custom.type.free_cb == tc_mesh_customdata_free_fn); + if (tc->custom.type.data == NULL) { + tc->custom.type.data = MEM_callocN(sizeof(struct TransCustomDataMesh), __func__); + tc->custom.type.free_cb = tc_mesh_customdata_free_fn; + tcmd = tc->custom.type.data; + } + return tcmd; +} + +static void tc_mesh_customdata_free(struct TransCustomDataMesh *tcmd) +{ + if (tcmd->cd_layer_correct != NULL) { + tc_mesh_customdatacorrect_free(tcmd->cd_layer_correct); + } + + if (tcmd->partial_update.cache != NULL) { + BM_mesh_partial_destroy(tcmd->partial_update.cache); + } + + MEM_freeN(tcmd); +} + +static void tc_mesh_customdata_free_fn(struct TransInfo *UNUSED(t), + struct TransDataContainer *UNUSED(tc), + struct TransCustomData *custom_data) +{ + struct TransCustomDataMesh *tcmd = custom_data->data; + tc_mesh_customdata_free(tcmd); + custom_data->data = NULL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name CustomData TransCustomDataLayer Creation + * \{ */ + +struct TransCustomDataMergeGroup { + /** map {BMVert: TransCustomDataLayerVert} */ + struct LinkNode **cd_loop_groups; +}; + +struct TransCustomDataLayer { + BMesh *bm; + struct MemArena *arena; + + struct GHash *origfaces; + struct BMesh *bm_origfaces; + + /* Special handle for multi-resolution. */ + int cd_loop_mdisp_offset; + + /* Optionally merge custom-data groups (this keeps UVs connected for example). */ + struct { + /** map {BMVert: TransDataBasic} */ + struct GHash *origverts; + struct TransCustomDataMergeGroup *data; + int data_len; + /** Array size of 'layer_math_map_len' + * maps #TransCustomDataLayerVert.cd_group index to absolute #CustomData layer index */ + int *customdatalayer_map; + /** Number of math BMLoop layers. */ + int customdatalayer_map_len; + } merge_group; + + bool use_merge_group; +}; + #define USE_FACE_SUBSTITUTE +#ifdef USE_FACE_SUBSTITUTE +# define FACE_SUBSTITUTE_INDEX INT_MIN + +/** + * Search for a neighboring face with area and preferably without selected vertex. + * Used to replace area-less faces in custom-data correction. + */ +static BMFace *tc_mesh_customdatacorrect_find_best_face_substitute(BMFace *f) +{ + BMFace *best_face = NULL; + BMLoop *l; + BMIter liter; + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + BMLoop *l_radial_next = l->radial_next; + BMFace *f_test = l_radial_next->f; + if (f_test == f) { + continue; + } + if (is_zero_v3(f_test->no)) { + continue; + } + + /* Check the loops edge isn't selected. */ + if (!BM_elem_flag_test(l_radial_next->v, BM_ELEM_SELECT) && + !BM_elem_flag_test(l_radial_next->next->v, BM_ELEM_SELECT)) { + /* Prefer edges with unselected vertices. + * Useful for extrude. */ + best_face = f_test; + break; + } + if (best_face == NULL) { + best_face = f_test; + } + } + return best_face; +} + +static void tc_mesh_customdatacorrect_face_substitute_set(struct TransCustomDataLayer *tcld, + BMFace *f, + BMFace *f_copy) +{ + BLI_assert(is_zero_v3(f->no)); + BMesh *bm = tcld->bm; + /* It is impossible to calculate the loops weights of a face without area. + * Find a substitute. */ + BMFace *f_substitute = tc_mesh_customdatacorrect_find_best_face_substitute(f); + if (f_substitute) { + /* Copy the custom-data from the substitute face. */ + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BM_loop_interp_from_face(bm, l_iter, f_substitute, false, false); + } while ((l_iter = l_iter->next) != l_first); + + /* Use the substitute face as the reference during the transformation. */ + BMFace *f_substitute_copy = BM_face_copy(tcld->bm_origfaces, bm, f_substitute, true, true); + + /* Hack: reference substitute face in `f_copy->no`. + * `tcld->origfaces` is already used to restore the initial value. */ + BM_elem_index_set(f_copy, FACE_SUBSTITUTE_INDEX); + *((BMFace **)&f_copy->no[0]) = f_substitute_copy; + } +} + +static BMFace *tc_mesh_customdatacorrect_face_substitute_get(BMFace *f_copy) +{ + BLI_assert(BM_elem_index_get(f_copy) == FACE_SUBSTITUTE_INDEX); + return *((BMFace **)&f_copy->no[0]); +} + +#endif /* USE_FACE_SUBSTITUTE */ + +static void tc_mesh_customdatacorrect_init_vert(struct TransCustomDataLayer *tcld, + struct TransDataBasic *td, + const int index) +{ + BMesh *bm = tcld->bm; + BMVert *v = td->extra; + BMIter liter; + int j, l_num; + float *loop_weights; + + // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) { + BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, v); + l_num = liter.count; + loop_weights = tcld->use_merge_group ? BLI_array_alloca(loop_weights, l_num) : NULL; + for (j = 0; j < l_num; j++) { + BMLoop *l = BM_iter_step(&liter); + BMLoop *l_prev, *l_next; + + /* Generic custom-data correction. Copy face data. */ + void **val_p; + if (!BLI_ghash_ensure_p(tcld->origfaces, l->f, &val_p)) { + BMFace *f_copy = BM_face_copy(tcld->bm_origfaces, bm, l->f, true, true); + *val_p = f_copy; +#ifdef USE_FACE_SUBSTITUTE + if (is_zero_v3(l->f->no)) { + tc_mesh_customdatacorrect_face_substitute_set(tcld, l->f, f_copy); + } +#endif + } + + if (tcld->use_merge_group) { + if ((l_prev = BM_loop_find_prev_nodouble(l, l->next, FLT_EPSILON)) && + (l_next = BM_loop_find_next_nodouble(l, l_prev, FLT_EPSILON))) { + loop_weights[j] = angle_v3v3v3(l_prev->v->co, l->v->co, l_next->v->co); + } + else { + loop_weights[j] = 0.0f; + } + } + } + + if (tcld->use_merge_group) { + /* Store cd_loop_groups. */ + struct TransCustomDataMergeGroup *merge_data = &tcld->merge_group.data[index]; + if (l_num != 0) { + merge_data->cd_loop_groups = BLI_memarena_alloc( + tcld->arena, tcld->merge_group.customdatalayer_map_len * sizeof(void *)); + for (j = 0; j < tcld->merge_group.customdatalayer_map_len; j++) { + const int layer_nr = tcld->merge_group.customdatalayer_map[j]; + merge_data->cd_loop_groups[j] = BM_vert_loop_groups_data_layer_create( + bm, v, layer_nr, loop_weights, tcld->arena); + } + } + else { + merge_data->cd_loop_groups = NULL; + } + + BLI_ghash_insert(tcld->merge_group.origverts, v, td); + } +} + +static void tc_mesh_customdatacorrect_init_container_generic(TransDataContainer *UNUSED(tc), + struct TransCustomDataLayer *tcld) +{ + BMesh *bm = tcld->bm; + + struct GHash *origfaces = BLI_ghash_ptr_new(__func__); + struct BMesh *bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default, + &((struct BMeshCreateParams){ + .use_toolflags = false, + })); + + /* We need to have matching loop custom-data. */ + BM_mesh_copy_init_customdata_all_layers(bm_origfaces, bm, BM_LOOP, NULL); + + tcld->origfaces = origfaces; + tcld->bm_origfaces = bm_origfaces; + + bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES); + tcld->cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); +} + +static void tc_mesh_customdatacorrect_init_container_merge_group(TransDataContainer *tc, + struct TransCustomDataLayer *tcld) +{ + BMesh *bm = tcld->bm; + BLI_assert(CustomData_has_math(&bm->ldata)); + + /* TODO: We don't need `layer_math_map` when there are no loops linked + * to one of the sliding vertices. */ + + /* Over allocate, only 'math' layers are indexed. */ + int *customdatalayer_map = MEM_mallocN(sizeof(int) * bm->ldata.totlayer, __func__); + int layer_math_map_len = 0; + for (int i = 0; i < bm->ldata.totlayer; i++) { + if (CustomData_layer_has_math(&bm->ldata, i)) { + customdatalayer_map[layer_math_map_len++] = i; + } + } + BLI_assert(layer_math_map_len != 0); + + tcld->merge_group.data_len = tc->data_len + tc->data_mirror_len; + tcld->merge_group.customdatalayer_map = customdatalayer_map; + tcld->merge_group.customdatalayer_map_len = layer_math_map_len; + tcld->merge_group.origverts = BLI_ghash_ptr_new_ex(__func__, tcld->merge_group.data_len); + tcld->merge_group.data = BLI_memarena_alloc( + tcld->arena, tcld->merge_group.data_len * sizeof(*tcld->merge_group.data)); +} + +static struct TransCustomDataLayer *tc_mesh_customdatacorrect_create_impl( + TransDataContainer *tc, const bool use_merge_group) +{ + BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); + BMesh *bm = em->bm; + + if (bm->shapenr > 1) { + /* Don't do this at all for non-basis shape keys, too easy to + * accidentally break uv maps or vertex colors then */ + /* create copies of faces for custom-data projection. */ + return NULL; + } + if (!CustomData_has_math(&bm->ldata) && !CustomData_has_layer(&bm->ldata, CD_MDISPS)) { + /* There is no custom-data to correct. */ + return NULL; + } + + struct TransCustomDataLayer *tcld = MEM_callocN(sizeof(*tcld), __func__); + tcld->bm = bm; + tcld->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + + /* Init `cd_loop_mdisp_offset` to -1 to avoid problems with a valid index. */ + tcld->cd_loop_mdisp_offset = -1; + tcld->use_merge_group = use_merge_group; + + tc_mesh_customdatacorrect_init_container_generic(tc, tcld); + + if (tcld->use_merge_group) { + tc_mesh_customdatacorrect_init_container_merge_group(tc, tcld); + } + + { + /* Setup Verts. */ + int i = 0; + + TransData *tob = tc->data; + for (int j = tc->data_len; j--; tob++, i++) { + tc_mesh_customdatacorrect_init_vert(tcld, (TransDataBasic *)tob, i); + } + + TransDataMirror *td_mirror = tc->data_mirror; + for (int j = tc->data_mirror_len; j--; td_mirror++, i++) { + tc_mesh_customdatacorrect_init_vert(tcld, (TransDataBasic *)td_mirror, i); + } + } + + return tcld; +} + +static void tc_mesh_customdatacorrect_create(TransDataContainer *tc, const bool use_merge_group) +{ + struct TransCustomDataLayer *customdatacorrect; + customdatacorrect = tc_mesh_customdatacorrect_create_impl(tc, use_merge_group); + + if (!customdatacorrect) { + return; + } + + struct TransCustomDataMesh *tcmd = tc_mesh_customdata_ensure(tc); + BLI_assert(tcmd->cd_layer_correct == NULL); + tcmd->cd_layer_correct = customdatacorrect; +} + +static void tc_mesh_customdatacorrect_free(struct TransCustomDataLayer *tcld) +{ + bmesh_edit_end(tcld->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES); + + if (tcld->bm_origfaces) { + BM_mesh_free(tcld->bm_origfaces); + } + if (tcld->origfaces) { + BLI_ghash_free(tcld->origfaces, NULL, NULL); + } + if (tcld->merge_group.origverts) { + BLI_ghash_free(tcld->merge_group.origverts, NULL, NULL); + } + if (tcld->arena) { + BLI_memarena_free(tcld->arena); + } + if (tcld->merge_group.customdatalayer_map) { + MEM_freeN(tcld->merge_group.customdatalayer_map); + } + + MEM_freeN(tcld); +} + +void transform_convert_mesh_customdatacorrect_init(TransInfo *t) +{ + bool use_merge_group = false; + if (ELEM(t->mode, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { + if (!(t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT_SLIDE)) { + /* No custom-data correction. */ + return; + } + use_merge_group = true; + } + else if (ELEM(t->mode, + TFM_TRANSLATION, + TFM_ROTATION, + TFM_RESIZE, + TFM_TOSPHERE, + TFM_SHEAR, + TFM_BEND, + TFM_SHRINKFATTEN, + TFM_TRACKBALL, + TFM_PUSHPULL, + TFM_ALIGN)) { + { + if (!(t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) { + /* No custom-data correction. */ + return; + } + use_merge_group = (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT_KEEP_CONNECTED) != 0; + } + } + else { + return; + } + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + if (tc->custom.type.data != NULL) { + struct TransCustomDataMesh *tcmd = tc->custom.type.data; + if (tcmd && tcmd->cd_layer_correct) { + tc_mesh_customdatacorrect_free(tcmd->cd_layer_correct); + tcmd->cd_layer_correct = NULL; + } + } + + tc_mesh_customdatacorrect_create(tc, use_merge_group); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name CustomData Layer Correction Apply + * \{ */ + +/** + * If we're sliding the vert, return its original location, if not, the current location is good. + */ +static const float *tc_mesh_vert_orig_co_get(struct TransCustomDataLayer *tcld, BMVert *v) +{ + TransDataBasic *td = BLI_ghash_lookup(tcld->merge_group.origverts, v); + return td ? td->iloc : v->co; +} + +static void tc_mesh_customdatacorrect_apply_vert(struct TransCustomDataLayer *tcld, + struct TransDataBasic *td, + struct TransCustomDataMergeGroup *merge_data, + bool do_loop_mdisps) +{ + BMesh *bm = tcld->bm; + BMVert *v = td->extra; + const float *co_orig_3d = td->iloc; + + BMIter liter; + int j, l_num; + float *loop_weights; + const bool is_moved = (len_squared_v3v3(v->co, co_orig_3d) > FLT_EPSILON); + const bool do_loop_weight = is_moved && tcld->merge_group.customdatalayer_map_len; + const float *v_proj_axis = v->no; + /* original (l->prev, l, l->next) projections for each loop ('l' remains unchanged) */ + float v_proj[3][3]; + + if (do_loop_weight) { + project_plane_normalized_v3_v3v3(v_proj[1], co_orig_3d, v_proj_axis); + } + + // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) + BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, v); + l_num = liter.count; + loop_weights = do_loop_weight ? BLI_array_alloca(loop_weights, l_num) : NULL; + for (j = 0; j < l_num; j++) { + BMFace *f_copy; /* the copy of 'f' */ + BMLoop *l = BM_iter_step(&liter); + + f_copy = BLI_ghash_lookup(tcld->origfaces, l->f); + +#ifdef USE_FACE_SUBSTITUTE + /* In some faces it is not possible to calculate interpolation, + * so we use a substitute. */ + if (BM_elem_index_get(f_copy) == FACE_SUBSTITUTE_INDEX) { + f_copy = tc_mesh_customdatacorrect_face_substitute_get(f_copy); + } +#endif + + /* only loop data, no vertex data since that contains shape keys, + * and we do not want to mess up other shape keys */ + BM_loop_interp_from_face(bm, l, f_copy, false, false); + + /* weight the loop */ + if (do_loop_weight) { + const float eps = 1.0e-8f; + const BMLoop *l_prev = l->prev; + const BMLoop *l_next = l->next; + const float *co_prev = tc_mesh_vert_orig_co_get(tcld, l_prev->v); + const float *co_next = tc_mesh_vert_orig_co_get(tcld, l_next->v); + bool co_prev_ok; + bool co_next_ok; + + /* In the unlikely case that we're next to a zero length edge - + * walk around the to the next. + * + * Since we only need to check if the vertex is in this corner, + * its not important _which_ loop - as long as its not overlapping + * 'sv->co_orig_3d', see: T45096. */ + project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis); + while (UNLIKELY(((co_prev_ok = (len_squared_v3v3(v_proj[1], v_proj[0]) > eps)) == false) && + ((l_prev = l_prev->prev) != l->next))) { + co_prev = tc_mesh_vert_orig_co_get(tcld, l_prev->v); + project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis); + } + project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis); + while (UNLIKELY(((co_next_ok = (len_squared_v3v3(v_proj[1], v_proj[2]) > eps)) == false) && + ((l_next = l_next->next) != l->prev))) { + co_next = tc_mesh_vert_orig_co_get(tcld, l_next->v); + project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis); + } + + if (co_prev_ok && co_next_ok) { + const float dist = dist_signed_squared_to_corner_v3v3v3( + v->co, UNPACK3(v_proj), v_proj_axis); + + loop_weights[j] = (dist >= 0.0f) ? 1.0f : ((dist <= -eps) ? 0.0f : (1.0f + (dist / eps))); + if (UNLIKELY(!isfinite(loop_weights[j]))) { + loop_weights[j] = 0.0f; + } + } + else { + loop_weights[j] = 0.0f; + } + } + } + + if (tcld->use_merge_group) { + struct LinkNode **cd_loop_groups = merge_data->cd_loop_groups; + if (tcld->merge_group.customdatalayer_map_len && cd_loop_groups) { + if (do_loop_weight) { + for (j = 0; j < tcld->merge_group.customdatalayer_map_len; j++) { + BM_vert_loop_groups_data_layer_merge_weights( + bm, cd_loop_groups[j], tcld->merge_group.customdatalayer_map[j], loop_weights); + } + } + else { + for (j = 0; j < tcld->merge_group.customdatalayer_map_len; j++) { + BM_vert_loop_groups_data_layer_merge( + bm, cd_loop_groups[j], tcld->merge_group.customdatalayer_map[j]); + } + } + } + } + + /* Special handling for multires + * + * Interpolate from every other loop (not ideal) + * However values will only be taken from loops which overlap other mdisps. + */ + const bool update_loop_mdisps = is_moved && do_loop_mdisps && (tcld->cd_loop_mdisp_offset != -1); + if (update_loop_mdisps) { + float(*faces_center)[3] = BLI_array_alloca(faces_center, l_num); + BMLoop *l; + + BM_ITER_ELEM_INDEX (l, &liter, v, BM_LOOPS_OF_VERT, j) { + BM_face_calc_center_median(l->f, faces_center[j]); + } + + BM_ITER_ELEM_INDEX (l, &liter, v, BM_LOOPS_OF_VERT, j) { + BMFace *f_copy = BLI_ghash_lookup(tcld->origfaces, l->f); + float f_copy_center[3]; + BMIter liter_other; + BMLoop *l_other; + int j_other; + + BM_face_calc_center_median(f_copy, f_copy_center); + + BM_ITER_ELEM_INDEX (l_other, &liter_other, v, BM_LOOPS_OF_VERT, j_other) { + BM_face_interp_multires_ex(bm, + l_other->f, + f_copy, + faces_center[j_other], + f_copy_center, + tcld->cd_loop_mdisp_offset); + } + } + } +} + +static void tc_mesh_customdatacorrect_apply(TransDataContainer *tc, bool is_final) +{ + struct TransCustomDataMesh *tcmd = tc->custom.type.data; + struct TransCustomDataLayer *tcld = tcmd ? tcmd->cd_layer_correct : NULL; + if (tcld == NULL) { + return; + } + const bool use_merge_group = tcld->use_merge_group; + + struct TransCustomDataMergeGroup *merge_data = tcld->merge_group.data; + TransData *tob = tc->data; + for (int i = tc->data_len; i--; tob++) { + tc_mesh_customdatacorrect_apply_vert(tcld, (TransDataBasic *)tob, merge_data, is_final); + + if (use_merge_group) { + merge_data++; + } + } + + TransDataMirror *td_mirror = tc->data_mirror; + for (int i = tc->data_mirror_len; i--; td_mirror++) { + tc_mesh_customdatacorrect_apply_vert(tcld, (TransDataBasic *)td_mirror, merge_data, is_final); + + if (use_merge_group) { + merge_data++; + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name CustomData Layer Correction Restore + * \{ */ + +static void tc_mesh_customdatacorrect_restore(struct TransInfo *t) +{ + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + struct TransCustomDataMesh *tcmd = tc->custom.type.data; + struct TransCustomDataLayer *tcld = tcmd ? tcmd->cd_layer_correct : NULL; + if (!tcld) { + continue; + } + + BMesh *bm = tcld->bm; + BMesh *bm_copy = tcld->bm_origfaces; + + GHashIterator gh_iter; + GHASH_ITER (gh_iter, tcld->origfaces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + BMFace *f_copy = BLI_ghashIterator_getValue(&gh_iter); + BLI_assert(f->len == f_copy->len); + + BMLoop *l_iter, *l_first, *l_copy; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + l_copy = BM_FACE_FIRST_LOOP(f_copy); + do { + /* TODO: Restore only the elements that transform. */ + BM_elem_attrs_copy(bm_copy, bm, l_copy, l_iter); + l_copy = l_copy->next; + } while ((l_iter = l_iter->next) != l_first); + } + } +} + +/** \} */ /* -------------------------------------------------------------------- */ /** \name Island Creation @@ -384,6 +1014,14 @@ void transform_convert_mesh_connectivity_distance(struct BMesh *bm, BMEdge *e; BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { + + /* Always clear to satisfy the assert, also predictable to leave in cleared state. */ + BM_elem_flag_disable(e, tag_queued); + + if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + continue; + } + BMVert *v1 = e->v1; BMVert *v2 = e->v2; int i1 = BM_elem_index_get(v1); @@ -392,7 +1030,6 @@ void transform_convert_mesh_connectivity_distance(struct BMesh *bm, if (dists[i1] != FLT_MAX || dists[i2] != FLT_MAX) { BLI_LINKSTACK_PUSH(queue, e); } - BM_elem_flag_disable(e, tag_queued); BM_elem_flag_set(e, tag_loose, bmesh_test_loose_edge(e)); } } @@ -420,6 +1057,7 @@ void transform_convert_mesh_connectivity_distance(struct BMesh *bm, BMIter eiter; BM_ITER_ELEM (e_other, &eiter, v2, BM_EDGES_OF_VERT) { if (e_other != e && BM_elem_flag_test(e_other, tag_queued) == 0 && + !BM_elem_flag_test(e_other, BM_ELEM_HIDDEN) && (BM_elem_flag_test(e, tag_loose) || BM_elem_flag_test(e_other, tag_loose))) { BM_elem_flag_enable(e_other, tag_queued); BLI_LINKSTACK_PUSH(queue_next, e_other); @@ -433,6 +1071,11 @@ void transform_convert_mesh_connectivity_distance(struct BMesh *bm, BMLoop *l; BMIter liter; BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) { + if (BM_elem_flag_test(l->f, BM_ELEM_HIDDEN)) { + continue; + } + /* Don't check hidden edges or vertices in this loop + * since any hidden edge causes the face to be hidden too. */ for (BMLoop *l_other = l->next->next; l_other != l; l_other = l_other->next) { BMVert *v_other = l_other->v; BLI_assert(!ELEM(v_other, v1, v2)); @@ -445,6 +1088,7 @@ void transform_convert_mesh_connectivity_distance(struct BMesh *bm, BMIter eiter; BM_ITER_ELEM (e_other, &eiter, v_other, BM_EDGES_OF_VERT) { if (e_other != e && BM_elem_flag_test(e_other, tag_queued) == 0 && + !BM_elem_flag_test(e_other, BM_ELEM_HIDDEN) && (BM_elem_flag_test(e_other, tag_loose) || dists[BM_elem_index_get(BM_edge_other_vert(e_other, v_other))] != FLT_MAX)) { BM_elem_flag_enable(e_other, tag_queued); @@ -727,10 +1371,10 @@ void transform_convert_mesh_crazyspace_free(struct TransMeshDataCrazySpace *r_cr /** \name Edit Mesh Verts Transform Creation * \{ */ -static void transdata_center_get(const struct TransIslandData *island_data, - const int island_index, - const float iloc[3], - float r_center[3]) +static void tc_mesh_transdata_center_copy(const struct TransIslandData *island_data, + const int island_index, + const float iloc[3], + float r_center[3]) { if (island_data->center && island_index != -1) { copy_v3_v3(r_center, island_data->center[island_index]); @@ -769,7 +1413,7 @@ static void VertsToTransData(TransInfo *t, no = eve->no; } - transdata_center_get(island_data, island_index, td->iloc, td->center); + tc_mesh_transdata_center_copy(island_data, island_index, td->iloc, td->center); if ((island_index != -1) && island_data->axismtx) { copy_m3_m3(td->axismtx, island_data->axismtx[island_index]); @@ -959,7 +1603,8 @@ void createTransEditVerts(TransInfo *t) copy_v3_v3(td_mirror->iloc, eve->co); td_mirror->flag = mirror_data.vert_map[a].flag; td_mirror->loc_src = v_src->co; - transdata_center_get(&island_data, island_index, td_mirror->iloc, td_mirror->center); + tc_mesh_transdata_center_copy( + &island_data, island_index, td_mirror->iloc, td_mirror->center); td_mirror++; } @@ -1031,590 +1676,133 @@ void createTransEditVerts(TransInfo *t) /** \} */ /* -------------------------------------------------------------------- */ -/** \name CustomData Layer Correction +/** \name Recalc Mesh Data * \{ */ -struct TransCustomDataMergeGroup { - /** map {BMVert: TransCustomDataLayerVert} */ - struct LinkNode **cd_loop_groups; -}; - -struct TransCustomDataLayer { - BMesh *bm; - struct MemArena *arena; - - struct GHash *origfaces; - struct BMesh *bm_origfaces; - - /* Special handle for multi-resolution. */ - int cd_loop_mdisp_offset; - - /* Optionally merge custom-data groups (this keeps UVs connected for example). */ - struct { - /** map {BMVert: TransDataBasic} */ - struct GHash *origverts; - struct TransCustomDataMergeGroup *data; - int data_len; - /** Array size of 'layer_math_map_len' - * maps #TransCustomDataLayerVert.cd_group index to absolute #CustomData layer index */ - int *customdatalayer_map; - /** Number of math BMLoop layers. */ - int customdatalayer_map_len; - } merge_group; - - bool use_merge_group; -}; - -static void mesh_customdatacorrect_free_cb(struct TransInfo *UNUSED(t), - struct TransDataContainer *UNUSED(tc), - struct TransCustomData *custom_data) +static bool bm_vert_tag_filter_fn(BMVert *v, void *UNUSED(user_data)) { - struct TransCustomDataLayer *tcld = custom_data->data; - bmesh_edit_end(tcld->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES); - - if (tcld->bm_origfaces) { - BM_mesh_free(tcld->bm_origfaces); - } - if (tcld->origfaces) { - BLI_ghash_free(tcld->origfaces, NULL, NULL); - } - if (tcld->merge_group.origverts) { - BLI_ghash_free(tcld->merge_group.origverts, NULL, NULL); - } - if (tcld->arena) { - BLI_memarena_free(tcld->arena); - } - if (tcld->merge_group.customdatalayer_map) { - MEM_freeN(tcld->merge_group.customdatalayer_map); - } - - MEM_freeN(tcld); - custom_data->data = NULL; -} - -#ifdef USE_FACE_SUBSTITUTE - -# define FACE_SUBSTITUTE_INDEX INT_MIN - -/** - * Search for a neighboring face with area and preferably without selected vertex. - * Used to replace area-less faces in custom-data correction. - */ -static BMFace *mesh_customdatacorrect_find_best_face_substitute(BMFace *f) -{ - BMFace *best_face = NULL; - BMLoop *l; - BMIter liter; - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - BMLoop *l_radial_next = l->radial_next; - BMFace *f_test = l_radial_next->f; - if (f_test == f) { - continue; - } - if (is_zero_v3(f_test->no)) { - continue; - } - - /* Check the loops edge isn't selected. */ - if (!BM_elem_flag_test(l_radial_next->v, BM_ELEM_SELECT) && - !BM_elem_flag_test(l_radial_next->next->v, BM_ELEM_SELECT)) { - /* Prefer edges with unselected vertices. - * Useful for extrude. */ - best_face = f_test; - break; - } - if (best_face == NULL) { - best_face = f_test; - } - } - return best_face; -} - -static void mesh_customdatacorrect_face_substitute_set(struct TransCustomDataLayer *tcld, - BMFace *f, - BMFace *f_copy) -{ - BLI_assert(is_zero_v3(f->no)); - BMesh *bm = tcld->bm; - /* It is impossible to calculate the loops weights of a face without area. - * Find a substitute. */ - BMFace *f_substitute = mesh_customdatacorrect_find_best_face_substitute(f); - if (f_substitute) { - /* Copy the custom-data from the substitute face. */ - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - BM_loop_interp_from_face(bm, l_iter, f_substitute, false, false); - } while ((l_iter = l_iter->next) != l_first); - - /* Use the substitute face as the reference during the transformation. */ - BMFace *f_substitute_copy = BM_face_copy(tcld->bm_origfaces, bm, f_substitute, true, true); - - /* Hack: reference substitute face in `f_copy->no`. - * `tcld->origfaces` is already used to restore the initial value. */ - BM_elem_index_set(f_copy, FACE_SUBSTITUTE_INDEX); - *((BMFace **)&f_copy->no[0]) = f_substitute_copy; - } + return BM_elem_flag_test(v, BM_ELEM_TAG); } -static BMFace *mesh_customdatacorrect_face_substitute_get(BMFace *f_copy) +static BMPartialUpdate *tc_mesh_ensure_partial_update(TransInfo *t, TransDataContainer *tc) { - BLI_assert(BM_elem_index_get(f_copy) == FACE_SUBSTITUTE_INDEX); - return *((BMFace **)&f_copy->no[0]); -} - -#endif /* USE_FACE_SUBSTITUTE */ + struct TransCustomDataMesh *tcmd = tc_mesh_customdata_ensure(tc); -static void mesh_customdatacorrect_init_vert(struct TransCustomDataLayer *tcld, - struct TransDataBasic *td, - const int index) -{ - BMesh *bm = tcld->bm; - BMVert *v = td->extra; - BMIter liter; - int j, l_num; - float *loop_weights; + if (tcmd->partial_update.cache) { - // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) { - BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, v); - l_num = liter.count; - loop_weights = tcld->use_merge_group ? BLI_array_alloca(loop_weights, l_num) : NULL; - for (j = 0; j < l_num; j++) { - BMLoop *l = BM_iter_step(&liter); - BMLoop *l_prev, *l_next; + /* Recalculate partial update data when the proportional editing size changes. + * + * Note that decreasing the proportional editing size requires the existing + * partial data is used before recreating this partial data at the smaller size. + * Since excluding geometry from being transformed requires an update. + * + * Extra logic is needed to account for this situation. */ - /* Generic custom-data correction. Copy face data. */ - void **val_p; - if (!BLI_ghash_ensure_p(tcld->origfaces, l->f, &val_p)) { - BMFace *f_copy = BM_face_copy(tcld->bm_origfaces, bm, l->f, true, true); - *val_p = f_copy; -#ifdef USE_FACE_SUBSTITUTE - if (is_zero_v3(l->f->no)) { - mesh_customdatacorrect_face_substitute_set(tcld, l->f, f_copy); - } -#endif + bool recalc; + if (tcmd->partial_update.prop_size_prev < t->prop_size) { + /* Size increase, simply recalculate. */ + recalc = true; } - - if (tcld->use_merge_group) { - if ((l_prev = BM_loop_find_prev_nodouble(l, l->next, FLT_EPSILON)) && - (l_next = BM_loop_find_next_nodouble(l, l_prev, FLT_EPSILON))) { - loop_weights[j] = angle_v3v3v3(l_prev->v->co, l->v->co, l_next->v->co); - } - else { - loop_weights[j] = 0.0f; - } + else if (tcmd->partial_update.prop_size_prev > t->prop_size) { + /* Size decreased, first use this partial data since reducing the size will transform + * geometry which needs recalculating. */ + tcmd->partial_update.prop_size_prev = t->prop_size; + recalc = false; } - } - - if (tcld->use_merge_group) { - /* Store cd_loop_groups. */ - struct TransCustomDataMergeGroup *merge_data = &tcld->merge_group.data[index]; - if (l_num != 0) { - merge_data->cd_loop_groups = BLI_memarena_alloc( - tcld->arena, tcld->merge_group.customdatalayer_map_len * sizeof(void *)); - for (j = 0; j < tcld->merge_group.customdatalayer_map_len; j++) { - const int layer_nr = tcld->merge_group.customdatalayer_map[j]; - merge_data->cd_loop_groups[j] = BM_vert_loop_groups_data_layer_create( - bm, v, layer_nr, loop_weights, tcld->arena); - } + else if (tcmd->partial_update.prop_size != t->prop_size) { + BLI_assert(tcmd->partial_update.prop_size > tcmd->partial_update.prop_size_prev); + recalc = true; } else { - merge_data->cd_loop_groups = NULL; + BLI_assert(t->prop_size == tcmd->partial_update.prop_size_prev); + recalc = false; } - BLI_ghash_insert(tcld->merge_group.origverts, v, td); - } -} - -static void mesh_customdatacorrect_init_container_generic(TransDataContainer *UNUSED(tc), - struct TransCustomDataLayer *tcld) -{ - BMesh *bm = tcld->bm; - - struct GHash *origfaces = BLI_ghash_ptr_new(__func__); - struct BMesh *bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default, - &((struct BMeshCreateParams){ - .use_toolflags = false, - })); - - /* We need to have matching loop custom-data. */ - BM_mesh_copy_init_customdata_all_layers(bm_origfaces, bm, BM_LOOP, NULL); - - tcld->origfaces = origfaces; - tcld->bm_origfaces = bm_origfaces; - - bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES); - tcld->cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); -} - -static void mesh_customdatacorrect_init_container_merge_group(TransDataContainer *tc, - struct TransCustomDataLayer *tcld) -{ - BMesh *bm = tcld->bm; - BLI_assert(CustomData_has_math(&bm->ldata)); - - /* TODO: We don't need `layer_math_map` when there are no loops linked - * to one of the sliding vertices. */ - - /* Over allocate, only 'math' layers are indexed. */ - int *customdatalayer_map = MEM_mallocN(sizeof(int) * bm->ldata.totlayer, __func__); - int layer_math_map_len = 0; - for (int i = 0; i < bm->ldata.totlayer; i++) { - if (CustomData_layer_has_math(&bm->ldata, i)) { - customdatalayer_map[layer_math_map_len++] = i; + if (!recalc) { + return tcmd->partial_update.cache; } - } - BLI_assert(layer_math_map_len != 0); - - tcld->merge_group.data_len = tc->data_len + tc->data_mirror_len; - tcld->merge_group.customdatalayer_map = customdatalayer_map; - tcld->merge_group.customdatalayer_map_len = layer_math_map_len; - tcld->merge_group.origverts = BLI_ghash_ptr_new_ex(__func__, tcld->merge_group.data_len); - tcld->merge_group.data = BLI_memarena_alloc( - tcld->arena, tcld->merge_group.data_len * sizeof(*tcld->merge_group.data)); -} -static void mesh_customdatacorrect_init_container(TransDataContainer *tc, - const bool use_merge_group) -{ - if (tc->custom.type.data) { - /* The custom-data correction has been initiated before. - * Free since some modes have different settings. */ - mesh_customdatacorrect_free_cb(NULL, tc, &tc->custom.type); + BM_mesh_partial_destroy(tcmd->partial_update.cache); + tcmd->partial_update.cache = NULL; } BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); - BMesh *bm = em->bm; - if (bm->shapenr > 1) { - /* Don't do this at all for non-basis shape keys, too easy to - * accidentally break uv maps or vertex colors then */ - /* create copies of faces for custom-data projection. */ - return; - } - if (!CustomData_has_math(&bm->ldata) && !CustomData_has_layer(&bm->ldata, CD_MDISPS)) { - /* There is no custom-data to correct. */ - return; - } + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); - struct TransCustomDataLayer *tcld = MEM_callocN(sizeof(*tcld), __func__); - tcld->bm = bm; - tcld->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - - /* Init `cd_loop_mdisp_offset` to -1 to avoid problems with a valid index. */ - tcld->cd_loop_mdisp_offset = -1; - tcld->use_merge_group = use_merge_group; - - mesh_customdatacorrect_init_container_generic(tc, tcld); - - if (tcld->use_merge_group) { - mesh_customdatacorrect_init_container_merge_group(tc, tcld); - } - - { - /* Setup Verts. */ - int i = 0; - - TransData *tob = tc->data; - for (int j = tc->data_len; j--; tob++, i++) { - mesh_customdatacorrect_init_vert(tcld, (TransDataBasic *)tob, i); - } - - TransDataMirror *td_mirror = tc->data_mirror; - for (int j = tc->data_mirror_len; j--; td_mirror++, i++) { - mesh_customdatacorrect_init_vert(tcld, (TransDataBasic *)td_mirror, i); + int verts_len = 0; + int i; + TransData *td; + for (i = 0, td = tc->data; i < tc->data_len; i++, td++) { + if (td->factor != 0.0f) { + BMVert *v = (BMVert *)td->extra; + BM_elem_flag_enable(v, BM_ELEM_TAG); + verts_len += 1; } } - tc->custom.type.data = tcld; - tc->custom.type.free_cb = mesh_customdatacorrect_free_cb; -} + TransDataMirror *td_mirror = tc->data_mirror; + for (i = 0; i < tc->data_mirror_len; i++, td_mirror++) { + BMVert *v_mirr = (BMVert *)POINTER_OFFSET(td_mirror->loc_src, -offsetof(BMVert, co)); -void mesh_customdatacorrect_init(TransInfo *t) -{ - bool use_merge_group = false; - if (ELEM(t->mode, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { - if (!(t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT_SLIDE)) { - /* No custom-data correction. */ - return; - } - use_merge_group = true; - } - else if (ELEM(t->mode, - TFM_TRANSLATION, - TFM_ROTATION, - TFM_RESIZE, - TFM_TOSPHERE, - TFM_SHEAR, - TFM_BEND, - TFM_SHRINKFATTEN, - TFM_TRACKBALL, - TFM_PUSHPULL, - TFM_ALIGN)) { - { - if (!(t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) { - /* No custom-data correction. */ - return; - } - use_merge_group = (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT_KEEP_CONNECTED) != 0; + /* The equality check is to account for the case when topology mirror moves + * the vertex from it's original location to match it's symmetrical position, + * with proportional editing enabled. */ + if (BM_elem_flag_test(v_mirr, BM_ELEM_TAG) || !equals_v3v3(td_mirror->loc, td_mirror->iloc)) { + BMVert *v_mirr_other = (BMVert *)td_mirror->extra; + /* This assert should never fail since there is no overlap + * between mirrored vertices and non-mirrored. */ + BLI_assert(!BM_elem_flag_test(v_mirr_other, BM_ELEM_TAG)); + BM_elem_flag_enable(v_mirr_other, BM_ELEM_TAG); + verts_len += 1; } } - else { - return; - } - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - mesh_customdatacorrect_init_container(tc, use_merge_group); - } -} + tcmd->partial_update.cache = BM_mesh_partial_create_from_verts(em->bm, + &(BMPartialUpdate_Params){ + .do_tessellate = true, + .do_normals = true, + }, + verts_len, + bm_vert_tag_filter_fn, + NULL); -/** - * If we're sliding the vert, return its original location, if not, the current location is good. - */ -static const float *trans_vert_orig_co_get(struct TransCustomDataLayer *tcld, BMVert *v) -{ - TransDataBasic *td = BLI_ghash_lookup(tcld->merge_group.origverts, v); - return td ? td->iloc : v->co; + tcmd->partial_update.prop_size_prev = t->prop_size; + tcmd->partial_update.prop_size = t->prop_size; + + return tcmd->partial_update.cache; } -static void mesh_customdatacorrect_apply_vert(struct TransCustomDataLayer *tcld, - struct TransDataBasic *td, - struct TransCustomDataMergeGroup *merge_data, - bool do_loop_mdisps) +static void tc_mesh_transdata_mirror_apply(TransDataContainer *tc) { - BMesh *bm = tcld->bm; - BMVert *v = td->extra; - const float *co_orig_3d = td->iloc; - - BMIter liter; - int j, l_num; - float *loop_weights; - const bool is_moved = (len_squared_v3v3(v->co, co_orig_3d) > FLT_EPSILON); - const bool do_loop_weight = is_moved && tcld->merge_group.customdatalayer_map_len; - const float *v_proj_axis = v->no; - /* original (l->prev, l, l->next) projections for each loop ('l' remains unchanged) */ - float v_proj[3][3]; - - if (do_loop_weight) { - project_plane_normalized_v3_v3v3(v_proj[1], co_orig_3d, v_proj_axis); - } - - // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) - BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, v); - l_num = liter.count; - loop_weights = do_loop_weight ? BLI_array_alloca(loop_weights, l_num) : NULL; - for (j = 0; j < l_num; j++) { - BMFace *f_copy; /* the copy of 'f' */ - BMLoop *l = BM_iter_step(&liter); - - f_copy = BLI_ghash_lookup(tcld->origfaces, l->f); - -#ifdef USE_FACE_SUBSTITUTE - /* In some faces it is not possible to calculate interpolation, - * so we use a substitute. */ - if (BM_elem_index_get(f_copy) == FACE_SUBSTITUTE_INDEX) { - f_copy = mesh_customdatacorrect_face_substitute_get(f_copy); - } -#endif - - /* only loop data, no vertex data since that contains shape keys, - * and we do not want to mess up other shape keys */ - BM_loop_interp_from_face(bm, l, f_copy, false, false); - - /* weight the loop */ - if (do_loop_weight) { - const float eps = 1.0e-8f; - const BMLoop *l_prev = l->prev; - const BMLoop *l_next = l->next; - const float *co_prev = trans_vert_orig_co_get(tcld, l_prev->v); - const float *co_next = trans_vert_orig_co_get(tcld, l_next->v); - bool co_prev_ok; - bool co_next_ok; - - /* In the unlikely case that we're next to a zero length edge - - * walk around the to the next. - * - * Since we only need to check if the vertex is in this corner, - * its not important _which_ loop - as long as its not overlapping - * 'sv->co_orig_3d', see: T45096. */ - project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis); - while (UNLIKELY(((co_prev_ok = (len_squared_v3v3(v_proj[1], v_proj[0]) > eps)) == false) && - ((l_prev = l_prev->prev) != l->next))) { - co_prev = trans_vert_orig_co_get(tcld, l_prev->v); - project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis); - } - project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis); - while (UNLIKELY(((co_next_ok = (len_squared_v3v3(v_proj[1], v_proj[2]) > eps)) == false) && - ((l_next = l_next->next) != l->prev))) { - co_next = trans_vert_orig_co_get(tcld, l_next->v); - project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis); - } - - if (co_prev_ok && co_next_ok) { - const float dist = dist_signed_squared_to_corner_v3v3v3( - v->co, UNPACK3(v_proj), v_proj_axis); - - loop_weights[j] = (dist >= 0.0f) ? 1.0f : ((dist <= -eps) ? 0.0f : (1.0f + (dist / eps))); - if (UNLIKELY(!isfinite(loop_weights[j]))) { - loop_weights[j] = 0.0f; + if (tc->use_mirror_axis_any) { + int i; + TransData *td; + for (i = 0, td = tc->data; i < tc->data_len; i++, td++) { + if (td->flag & (TD_MIRROR_EDGE_X | TD_MIRROR_EDGE_Y | TD_MIRROR_EDGE_Z)) { + if (td->flag & TD_MIRROR_EDGE_X) { + td->loc[0] = 0.0f; } - } - else { - loop_weights[j] = 0.0f; - } - } - } - - if (tcld->use_merge_group) { - struct LinkNode **cd_loop_groups = merge_data->cd_loop_groups; - if (tcld->merge_group.customdatalayer_map_len && cd_loop_groups) { - if (do_loop_weight) { - for (j = 0; j < tcld->merge_group.customdatalayer_map_len; j++) { - BM_vert_loop_groups_data_layer_merge_weights( - bm, cd_loop_groups[j], tcld->merge_group.customdatalayer_map[j], loop_weights); + if (td->flag & TD_MIRROR_EDGE_Y) { + td->loc[1] = 0.0f; } - } - else { - for (j = 0; j < tcld->merge_group.customdatalayer_map_len; j++) { - BM_vert_loop_groups_data_layer_merge( - bm, cd_loop_groups[j], tcld->merge_group.customdatalayer_map[j]); + if (td->flag & TD_MIRROR_EDGE_Z) { + td->loc[2] = 0.0f; } } } - } - - /* Special handling for multires - * - * Interpolate from every other loop (not ideal) - * However values will only be taken from loops which overlap other mdisps. - */ - const bool update_loop_mdisps = is_moved && do_loop_mdisps && (tcld->cd_loop_mdisp_offset != -1); - if (update_loop_mdisps) { - float(*faces_center)[3] = BLI_array_alloca(faces_center, l_num); - BMLoop *l; - - BM_ITER_ELEM_INDEX (l, &liter, v, BM_LOOPS_OF_VERT, j) { - BM_face_calc_center_median(l->f, faces_center[j]); - } - - BM_ITER_ELEM_INDEX (l, &liter, v, BM_LOOPS_OF_VERT, j) { - BMFace *f_copy = BLI_ghash_lookup(tcld->origfaces, l->f); - float f_copy_center[3]; - BMIter liter_other; - BMLoop *l_other; - int j_other; - - BM_face_calc_center_median(f_copy, f_copy_center); - - BM_ITER_ELEM_INDEX (l_other, &liter_other, v, BM_LOOPS_OF_VERT, j_other) { - BM_face_interp_multires_ex(bm, - l_other->f, - f_copy, - faces_center[j_other], - f_copy_center, - tcld->cd_loop_mdisp_offset); - } - } - } -} - -static void mesh_customdatacorrect_apply(TransInfo *t, bool is_final) -{ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - if (!tc->custom.type.data) { - continue; - } - struct TransCustomDataLayer *tcld = tc->custom.type.data; - const bool use_merge_group = tcld->use_merge_group; - - struct TransCustomDataMergeGroup *merge_data = tcld->merge_group.data; - TransData *tob = tc->data; - for (int i = tc->data_len; i--; tob++) { - mesh_customdatacorrect_apply_vert(tcld, (TransDataBasic *)tob, merge_data, is_final); - - if (use_merge_group) { - merge_data++; - } - } TransDataMirror *td_mirror = tc->data_mirror; - for (int i = tc->data_mirror_len; i--; td_mirror++) { - mesh_customdatacorrect_apply_vert(tcld, (TransDataBasic *)td_mirror, merge_data, is_final); - - if (use_merge_group) { - merge_data++; + for (i = 0; i < tc->data_mirror_len; i++, td_mirror++) { + copy_v3_v3(td_mirror->loc, td_mirror->loc_src); + if (td_mirror->flag & TD_MIRROR_X) { + td_mirror->loc[0] *= -1; } - } - } -} - -static void mesh_customdatacorrect_restore(struct TransInfo *t) -{ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - struct TransCustomDataLayer *tcld = tc->custom.type.data; - if (!tcld) { - continue; - } - - BMesh *bm = tcld->bm; - BMesh *bm_copy = tcld->bm_origfaces; - - GHashIterator gh_iter; - GHASH_ITER (gh_iter, tcld->origfaces) { - BMFace *f = BLI_ghashIterator_getKey(&gh_iter); - BMFace *f_copy = BLI_ghashIterator_getValue(&gh_iter); - BLI_assert(f->len == f_copy->len); - - BMLoop *l_iter, *l_first, *l_copy; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - l_copy = BM_FACE_FIRST_LOOP(f_copy); - do { - /* TODO: Restore only the elements that transform. */ - BM_elem_attrs_copy(bm_copy, bm, l_copy, l_iter); - l_copy = l_copy->next; - } while ((l_iter = l_iter->next) != l_first); - } - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Recalc Mesh Data - * \{ */ - -static void mesh_apply_to_mirror(TransInfo *t) -{ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - if (tc->use_mirror_axis_any) { - int i; - TransData *td; - for (i = 0, td = tc->data; i < tc->data_len; i++, td++) { - if (td->flag & (TD_MIRROR_EDGE_X | TD_MIRROR_EDGE_Y | TD_MIRROR_EDGE_Z)) { - if (td->flag & TD_MIRROR_EDGE_X) { - td->loc[0] = 0.0f; - } - if (td->flag & TD_MIRROR_EDGE_Y) { - td->loc[1] = 0.0f; - } - if (td->flag & TD_MIRROR_EDGE_Z) { - td->loc[2] = 0.0f; - } - } + if (td_mirror->flag & TD_MIRROR_Y) { + td_mirror->loc[1] *= -1; } - - TransDataMirror *td_mirror = tc->data_mirror; - for (i = 0; i < tc->data_mirror_len; i++, td_mirror++) { - copy_v3_v3(td_mirror->loc, td_mirror->loc_src); - if (td_mirror->flag & TD_MIRROR_X) { - td_mirror->loc[0] *= -1; - } - if (td_mirror->flag & TD_MIRROR_Y) { - td_mirror->loc[1] *= -1; - } - if (td_mirror->flag & TD_MIRROR_Z) { - td_mirror->loc[2] *= -1; - } + if (td_mirror->flag & TD_MIRROR_Z) { + td_mirror->loc[2] *= -1; } } } @@ -1623,27 +1811,45 @@ static void mesh_apply_to_mirror(TransInfo *t) void recalcData_mesh(TransInfo *t) { bool is_canceling = t->state == TRANS_CANCEL; - /* mirror modifier clipping? */ + /* Apply corrections. */ if (!is_canceling) { - /* apply clipping after so we never project past the clip plane T25423. */ applyProject(t); - clipMirrorModifier(t); - if ((t->flag & T_NO_MIRROR) == 0 && (t->options & CTX_NO_MIRROR) == 0) { - mesh_apply_to_mirror(t); - } + bool do_mirror = !(t->flag & T_NO_MIRROR); + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + /* Apply clipping after so we never project past the clip plane T25423. */ + transform_convert_clip_mirror_modifier_apply(tc); + + if (do_mirror) { + tc_mesh_transdata_mirror_apply(tc); + } - mesh_customdatacorrect_apply(t, false); + tc_mesh_customdatacorrect_apply(tc, false); + } } else { - mesh_customdatacorrect_restore(t); + tc_mesh_customdatacorrect_restore(t); } FOREACH_TRANS_DATA_CONTAINER (t, tc) { - DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */ + DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY); BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); - EDBM_mesh_normals_update(em); - BKE_editmesh_looptri_calc(em); + + /* The additional cost of generating the partial connectivity data isn't justified + * when all data needs to be updated. + * + * While proportional editing can cause all geometry to need updating with a partial selection. + * It's impractical to calculate this ahead of time. + * Further, the down side of using partial updates when their not needed is negligible. */ + if (em->bm->totvert == em->bm->totvertsel) { + EDBM_mesh_normals_update(em); + BKE_editmesh_looptri_calc(em); + } + else { + BMPartialUpdate *partial_update_cache = tc_mesh_ensure_partial_update(t, tc); + BM_mesh_normals_update_with_partial(em->bm, partial_update_cache); + BKE_editmesh_looptri_calc_with_partial(em, partial_update_cache); + } } } /** \} */ @@ -1660,7 +1866,9 @@ void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) if (!is_canceling && ELEM(t->mode, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { /* NOTE(joeedh): Handle multi-res re-projection, * done on transform completion since it's really slow. */ - mesh_customdatacorrect_apply(t, true); + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + tc_mesh_customdatacorrect_apply(tc, true); + } } if (use_automerge) { diff --git a/source/blender/editors/transform/transform_convert_mesh_edge.c b/source/blender/editors/transform/transform_convert_mesh_edge.c index bb9296b4b90..3b1191a3401 100644 --- a/source/blender/editors/transform/transform_convert_mesh_edge.c +++ b/source/blender/editors/transform/transform_convert_mesh_edge.c @@ -123,4 +123,11 @@ void createTransEdge(TransInfo *t) } } +void recalcData_mesh_edge(TransInfo *t) +{ + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY); + } +} + /** \} */ diff --git a/source/blender/editors/transform/transform_convert_mesh_skin.c b/source/blender/editors/transform/transform_convert_mesh_skin.c index 5dbb1947773..7c61da31f72 100644 --- a/source/blender/editors/transform/transform_convert_mesh_skin.c +++ b/source/blender/editors/transform/transform_convert_mesh_skin.c @@ -47,9 +47,9 @@ /** \name Edit Mesh #CD_MVERT_SKIN Transform Creation * \{ */ -static float *mesh_skin_transdata_center(const struct TransIslandData *island_data, - const int island_index, - BMVert *eve) +static float *tc_mesh_skin_transdata_center(const struct TransIslandData *island_data, + const int island_index, + BMVert *eve) { if (island_data->center && island_index != -1) { return island_data->center[island_index]; @@ -57,11 +57,11 @@ static float *mesh_skin_transdata_center(const struct TransIslandData *island_da return eve->co; } -static void mesh_skin_transdata_create(TransDataBasic *td, - BMEditMesh *em, - BMVert *eve, - const struct TransIslandData *island_data, - const int island_index) +static void tc_mesh_skin_transdata_create(TransDataBasic *td, + BMEditMesh *em, + BMVert *eve, + const struct TransIslandData *island_data, + const int island_index) { BLI_assert(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) == 0); MVertSkin *vs = CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MVERT_SKIN); @@ -78,7 +78,7 @@ static void mesh_skin_transdata_create(TransDataBasic *td, td->flag |= TD_SELECTED; } - copy_v3_v3(td->center, mesh_skin_transdata_center(island_data, island_index, eve)); + copy_v3_v3(td->center, tc_mesh_skin_transdata_center(island_data, island_index, eve)); td->extra = eve; } @@ -209,7 +209,7 @@ void createTransMeshSkin(TransInfo *t) } if (mirror_data.vert_map && mirror_data.vert_map[a].index != -1) { - mesh_skin_transdata_create( + tc_mesh_skin_transdata_create( (TransDataBasic *)td_mirror, em, eve, &island_data, island_index); int elem_index = mirror_data.vert_map[a].index; @@ -221,7 +221,7 @@ void createTransMeshSkin(TransInfo *t) td_mirror++; } else if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - mesh_skin_transdata_create((TransDataBasic *)td, em, eve, &island_data, island_index); + tc_mesh_skin_transdata_create((TransDataBasic *)td, em, eve, &island_data, island_index); if (t->around == V3D_AROUND_LOCAL_ORIGINS) { createSpaceNormal(td->axismtx, eve->no); @@ -275,7 +275,7 @@ void createTransMeshSkin(TransInfo *t) /** \name Recalc Mesh Data * \{ */ -static void mesh_skin_apply_to_mirror(TransInfo *t) +static void tc_mesh_skin_apply_to_mirror(TransInfo *t) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { if (tc->use_mirror_axis_any) { @@ -292,13 +292,13 @@ void recalcData_mesh_skin(TransInfo *t) bool is_canceling = t->state == TRANS_CANCEL; /* mirror modifier clipping? */ if (!is_canceling) { - if ((t->flag & T_NO_MIRROR) == 0 && (t->options & CTX_NO_MIRROR) == 0) { - mesh_skin_apply_to_mirror(t); + if (!(t->flag & T_NO_MIRROR)) { + tc_mesh_skin_apply_to_mirror(t); } } FOREACH_TRANS_DATA_CONTAINER (t, tc) { - DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */ + DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY); BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); EDBM_mesh_normals_update(em); BKE_editmesh_looptri_calc(em); diff --git a/source/blender/editors/transform/transform_convert_mesh_uv.c b/source/blender/editors/transform/transform_convert_mesh_uv.c index a5f90e9ac5f..d91a2a8be4b 100644 --- a/source/blender/editors/transform/transform_convert_mesh_uv.c +++ b/source/blender/editors/transform/transform_convert_mesh_uv.c @@ -475,7 +475,7 @@ void recalcData_uv(TransInfo *t) FOREACH_TRANS_DATA_CONTAINER (t, tc) { if (tc->data_len) { - DEG_id_tag_update(tc->obedit->data, 0); + DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY); } } } diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c index b546f1d0b4c..c217478bd04 100644 --- a/source/blender/editors/transform/transform_convert_object.c +++ b/source/blender/editors/transform/transform_convert_object.c @@ -282,9 +282,17 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) */ BKE_object_to_mat3(ob, obmtx); copy_m3_m4(totmat, ob->obmat); - invert_m3_m3(obinv, totmat); + + /* If the object scale is zero on any axis, this might result in a zero matrix. + * In this case, the transformation would not do anything, see: T50103. */ + orthogonalize_m3_zero_axes(obmtx, 1.0f); + orthogonalize_m3_zero_axes(totmat, 1.0f); + + /* Use safe invert even though the input matrices have had zero axes set to unit length, + * in the unlikely case of failure (float precision for eg) this uses unit matrix fallback. */ + invert_m3_m3_safe_ortho(obinv, totmat); mul_m3_m3m3(td->smtx, obmtx, obinv); - invert_m3_m3(td->mtx, td->smtx); + invert_m3_m3_safe_ortho(td->mtx, td->smtx); } else { /* no conversion to/from dataspace */ diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index 30418471d6d..6a09008e657 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -90,8 +90,8 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_recursive, int *r_c Scene *scene = t->scene; int cfra = CFRA; - int left = SEQ_transform_get_left_handle_frame(seq, false); - int right = SEQ_transform_get_right_handle_frame(seq, false); + int left = SEQ_transform_get_left_handle_frame(seq); + int right = SEQ_transform_get_right_handle_frame(seq); if (seq->depth == 0 && ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK))) { *r_recursive = false; @@ -172,7 +172,7 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_recursive, int *r_c } } -static int SeqTransCount(TransInfo *t, Sequence *parent, ListBase *seqbase, int depth) +static int SeqTransCount(TransInfo *t, ListBase *seqbase, int depth) { Sequence *seq; int tot = 0, recursive, count, flag; @@ -180,16 +180,11 @@ static int SeqTransCount(TransInfo *t, Sequence *parent, ListBase *seqbase, int for (seq = seqbase->first; seq; seq = seq->next) { seq->depth = depth; - /* 'seq->tmp' is used by seq_tx_get_final_{left, right} - * to check sequence's range and clamp to it if needed. - * It's first place where digging into sequences tree, so store link to parent here. */ - seq->tmp = parent; - SeqTransInfo(t, seq, &recursive, &count, &flag); /* ignore the flag */ tot += count; if (recursive) { - tot += SeqTransCount(t, seq, &seq->seqbase, depth + 1); + tot += SeqTransCount(t, &seq->seqbase, depth + 1); } } @@ -206,16 +201,16 @@ static TransData *SeqToTransData( /* Use seq_tx_get_final_left() and an offset here * so transform has the left hand location of the strip. * tdsq->start_offset is used when flushing the tx data back */ - start_left = SEQ_transform_get_left_handle_frame(seq, false); + start_left = SEQ_transform_get_left_handle_frame(seq); td2d->loc[0] = start_left; tdsq->start_offset = start_left - seq->start; /* use to apply the original location */ break; case SEQ_LEFTSEL: - start_left = SEQ_transform_get_left_handle_frame(seq, false); + start_left = SEQ_transform_get_left_handle_frame(seq); td2d->loc[0] = start_left; break; case SEQ_RIGHTSEL: - td2d->loc[0] = SEQ_transform_get_right_handle_frame(seq, false); + td2d->loc[0] = SEQ_transform_get_right_handle_frame(seq); break; } @@ -491,7 +486,7 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c } } - SEQ_sort(t->scene); + SEQ_sort(seqbasep); } else { /* Canceled, need to update the strips display */ @@ -562,7 +557,7 @@ void createTransSeqData(TransInfo *t) } #endif - count = SeqTransCount(t, NULL, ed->seqbasep, 0); + count = SeqTransCount(t, ed->seqbasep, 0); /* allocate memory for data */ tc->data_len = count; @@ -707,7 +702,7 @@ static void flushTransSeq(TransInfo *t) /* originally TFM_TIME_EXTEND, transform changes */ if (ELEM(t->mode, TFM_SEQ_SLIDE, TFM_TIME_TRANSLATE)) { - /* Special annoying case here, need to calc metas with TFM_TIME_EXTEND only */ + /* Special annoying case here, need to calc meta-strips with TFM_TIME_EXTEND only */ /* calc all meta's then effects T27953. */ for (seq = seqbasep->first; seq; seq = seq->next) { diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index e43a3ff3635..71c91221fbb 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -409,11 +409,10 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve short orient_types[3]; float custom_matrix[3][3]; - short orient_type_scene = V3D_ORIENT_GLOBAL; - short orient_type_set = V3D_ORIENT_GLOBAL; - short orient_type_matrix_set = -1; - - bool use_orient_axis = false; + int orient_type_scene = V3D_ORIENT_GLOBAL; + int orient_type_default = -1; + int orient_type_set = -1; + int orient_type_matrix_set = -1; if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT]; @@ -424,40 +423,20 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } } - short orient_type_default = orient_type_scene; - - if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) { - t->orient_axis = RNA_property_enum_get(op->ptr, prop); - use_orient_axis = true; - } - - if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) { - t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop); - } - if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) && RNA_property_is_set(op->ptr, prop))) { orient_type_set = RNA_property_enum_get(op->ptr, prop); if (orient_type_set >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) { orient_type_set = V3D_ORIENT_GLOBAL; } - - /* Change the default orientation to be used when redoing. */ - orient_type_default = orient_type_set; } - else if (t->con.mode & CON_APPLY) { - orient_type_set = orient_type_scene; + + if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) { + t->orient_axis = RNA_property_enum_get(op->ptr, prop); } - else { - if (orient_type_set == orient_type_scene) { - BLI_assert(orient_type_set == V3D_ORIENT_GLOBAL); - orient_type_set = V3D_ORIENT_LOCAL; - } - if ((t->flag & T_MODAL) && (use_orient_axis || transform_mode_is_changeable(t->mode)) && - (t->mode != TFM_ALIGN)) { - orient_type_default = V3D_ORIENT_VIEW; - } + if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) { + t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop); } if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) && @@ -468,19 +447,41 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve RNA_property_is_set(op->ptr, prop)) { orient_type_matrix_set = RNA_property_enum_get(op->ptr, prop); } - else { - orient_type_matrix_set = orient_type_set; + else if (orient_type_set == -1) { + orient_type_set = V3D_ORIENT_CUSTOM_MATRIX; } + } - if (orient_type_matrix_set == orient_type_set) { - /* Constraints are forced to use the custom matrix when redoing. */ - orient_type_set = V3D_ORIENT_CUSTOM_MATRIX; + if (orient_type_set != -1) { + orient_type_default = orient_type_set; + t->is_orient_set = true; + } + else if (orient_type_matrix_set != -1) { + orient_type_default = orient_type_set = orient_type_matrix_set; + t->is_orient_set = true; + } + else if (t->con.mode & CON_APPLY) { + orient_type_default = orient_type_set = orient_type_scene; + } + else { + orient_type_default = orient_type_scene; + if (orient_type_scene == V3D_ORIENT_GLOBAL) { + orient_type_set = V3D_ORIENT_LOCAL; } + else { + orient_type_set = V3D_ORIENT_GLOBAL; + } + } + + BLI_assert(!ELEM(-1, orient_type_default, orient_type_set)); + if (orient_type_matrix_set == orient_type_set) { + /* Constraints are forced to use the custom matrix when redoing. */ + orient_type_set = V3D_ORIENT_CUSTOM_MATRIX; } - orient_types[0] = orient_type_default; - orient_types[1] = orient_type_scene; - orient_types[2] = orient_type_set; + orient_types[O_DEFAULT] = (short)orient_type_default; + orient_types[O_SCENE] = (short)orient_type_scene; + orient_types[O_SET] = (short)orient_type_set; for (int i = 0; i < 3; i++) { /* For efficiency, avoid calculating the same orientation twice. */ @@ -497,9 +498,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } } - /* Set orient_curr to -1 in order to force the update in - * `transform_orientations_current_set`. */ - t->orient_curr = -1; transform_orientations_current_set(t, (t->con.mode & CON_APPLY) ? 2 : 0); } @@ -529,7 +527,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } else { /* Avoid mirroring for unsupported contexts. */ - t->options |= CTX_NO_MIRROR; + t->flag |= T_NO_MIRROR; } /* setting PET flag only if property exist in operator. Otherwise, assume it's not supported */ diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index 27df29afd8d..7a780df0def 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -512,11 +512,11 @@ static void protectflag_to_drawflags(short protectflag, short *drawflags) /* for pose mode */ static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, const bPoseChannel *pchan, - short orientation_type) + short orientation_index) { /* Protect-flags apply to local space in pose mode, so only let them influence axis * visibility if we show the global orientation, otherwise it's confusing. */ - if (orientation_type == V3D_ORIENT_LOCAL) { + if (orientation_index == V3D_ORIENT_LOCAL) { protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag); } } @@ -657,12 +657,9 @@ int ED_transform_calc_gizmo_stats(const bContext *C, int a, totsel = 0; const int pivot_point = scene->toolsettings->transform_pivot_point; - const short orientation_type = params->orientation_type ? - (params->orientation_type - 1) : - scene->orientation_slots[SCE_ORIENT_DEFAULT].type; - const short orientation_index_custom = - params->orientation_type ? params->orientation_index_custom : - scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom; + const short orient_index = params->orientation_index ? + (params->orientation_index - 1) : + BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT); /* transform widget matrix */ unit_m4(rv3d->twmat); @@ -678,7 +675,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, if (ob) { float mat[3][3]; ED_transform_calc_orientation_from_type_ex( - C, mat, scene, rv3d, ob, obedit, orientation_type, orientation_index_custom, pivot_point); + C, mat, scene, rv3d, ob, obedit, orient_index, pivot_point); copy_m4_m3(rv3d->twmat, mat); } @@ -976,7 +973,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, Bone *bone = pchan->bone; if (bone && (bone->flag & BONE_TRANSFORM)) { calc_tw_center_with_matrix(tbounds, pchan->pose_head, use_mat_local, mat_local); - protectflag_to_drawflags_pchan(rv3d, pchan, orientation_type); + protectflag_to_drawflags_pchan(rv3d, pchan, orient_index); } } totsel += totsel_iter; @@ -1063,7 +1060,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, /* Protect-flags apply to world space in object mode, so only let them influence axis * visibility if we show the global orientation, otherwise it's confusing. */ - if (orientation_type == V3D_ORIENT_GLOBAL) { + if (orient_index == V3D_ORIENT_GLOBAL) { protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag); } totsel++; @@ -1689,18 +1686,15 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup) } } - const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get_from_flag( - scene, ggd->twtype_init); + const int orient_index = BKE_scene_orientation_get_index_from_flag(scene, ggd->twtype_init); /* skip, we don't draw anything anyway */ - if ((ggd->all_hidden = (ED_transform_calc_gizmo_stats( - C, - &(struct TransformCalcParams){ - .use_only_center = true, - .orientation_type = orient_slot->type + 1, - .orientation_index_custom = orient_slot->index_custom, - }, - &tbounds) == 0))) { + if ((ggd->all_hidden = (ED_transform_calc_gizmo_stats(C, + &(struct TransformCalcParams){ + .use_only_center = true, + .orientation_index = orient_index + 1, + }, + &tbounds) == 0))) { return; } @@ -2119,14 +2113,12 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgr gzgroup->use_fallback_keymap = false; } - const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get(scene, - SCE_ORIENT_SCALE); + const int orient_index = BKE_scene_orientation_get_index_from_flag(scene, SCE_ORIENT_SCALE); if ((ED_transform_calc_gizmo_stats(C, &(struct TransformCalcParams){ .use_local_axis = true, - .orientation_type = orient_slot->type + 1, - .orientation_index_custom = orient_slot->index_custom, + .orientation_index = orient_index + 1, }, &tbounds) == 0) || equals_v3v3(rv3d->tw_axis_min, rv3d->tw_axis_max)) { @@ -2335,14 +2327,14 @@ static void WIDGETGROUP_xform_shear_refresh(const bContext *C, wmGizmoGroup *gzg /* Needed to test view orientation changes. */ copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv); - const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get(scene, - SCE_ORIENT_ROTATE); + TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get_from_flag( + scene, SCE_ORIENT_ROTATE); + const int orient_index = BKE_scene_orientation_slot_get_index(orient_slot); if (ED_transform_calc_gizmo_stats(C, &(struct TransformCalcParams){ .use_local_axis = false, - .orientation_type = orient_slot->type + 1, - .orientation_index_custom = orient_slot->index_custom, + .orientation_index = orient_index + 1, }, &tbounds) == 0) { for (int i = 0; i < 3; i++) { diff --git a/source/blender/editors/transform/transform_gizmo_extrude_3d.c b/source/blender/editors/transform/transform_gizmo_extrude_3d.c index 63c8efdd475..ed6c3eb0255 100644 --- a/source/blender/editors/transform/transform_gizmo_extrude_3d.c +++ b/source/blender/editors/transform/transform_gizmo_extrude_3d.c @@ -25,6 +25,7 @@ #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_scene.h" #include "RNA_access.h" #include "RNA_define.h" @@ -88,7 +89,7 @@ typedef struct GizmoExtrudeGroup { struct { float normal_mat3[3][3]; /* use Z axis for normal. */ - int orientation_type; + int orientation_index; } data; wmOperatorType *ot_extrude; @@ -254,8 +255,8 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup) axis_type = RNA_property_enum_get(&ptr, ggd->gzgt_axis_type_prop); } - ggd->data.orientation_type = scene->orientation_slots[SCE_ORIENT_DEFAULT].type; - const bool use_normal = ((ggd->data.orientation_type != V3D_ORIENT_NORMAL) || + ggd->data.orientation_index = BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT); + const bool use_normal = ((ggd->data.orientation_index != V3D_ORIENT_NORMAL) || (axis_type == EXTRUDE_AXIS_NORMAL)); const int axis_len_used = use_normal ? 4 : 3; @@ -265,7 +266,7 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup) struct TransformBounds tbounds_normal; if (!ED_transform_calc_gizmo_stats(C, &(struct TransformCalcParams){ - .orientation_type = V3D_ORIENT_NORMAL + 1, + .orientation_index = V3D_ORIENT_NORMAL + 1, }, &tbounds_normal)) { unit_m3(tbounds_normal.axis); @@ -276,7 +277,7 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup) /* TODO(campbell): run second since this modifies the 3D view, it should not. */ if (!ED_transform_calc_gizmo_stats(C, &(struct TransformCalcParams){ - .orientation_type = ggd->data.orientation_type + 1, + .orientation_index = ggd->data.orientation_index + 1, }, &tbounds)) { return; @@ -391,7 +392,7 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup) static void gizmo_mesh_extrude_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) { GizmoExtrudeGroup *ggd = gzgroup->customdata; - switch (ggd->data.orientation_type) { + switch (ggd->data.orientation_index) { case V3D_ORIENT_VIEW: { RegionView3D *rv3d = CTX_wm_region_view3d(C); float mat[3][3]; @@ -451,7 +452,7 @@ static void gizmo_mesh_extrude_invoke_prepare(const bContext *UNUSED(C), if (i == 3) { use_normal_matrix = true; } - else if (ggd->data.orientation_type == V3D_ORIENT_NORMAL) { + else if (ggd->data.orientation_index == V3D_ORIENT_NORMAL) { use_normal_matrix = true; } if (use_normal_matrix) { diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c index bfeb96d18c4..414199badd7 100644 --- a/source/blender/editors/transform/transform_input.c +++ b/source/blender/editors/transform/transform_input.c @@ -186,57 +186,24 @@ struct InputAngle_Data { static void InputAngle(TransInfo *UNUSED(t), MouseInput *mi, const double mval[2], float output[3]) { struct InputAngle_Data *data = mi->data; - double dx2 = mval[0] - (double)mi->center[0]; - double dy2 = mval[1] - (double)mi->center[1]; - double B = sqrt(dx2 * dx2 + dy2 * dy2); + float dir_prev[2], dir_curr[2], mi_center[2]; + copy_v2_v2(mi_center, mi->center); - double dx1 = data->mval_prev[0] - (double)mi->center[0]; - double dy1 = data->mval_prev[1] - (double)mi->center[1]; - double A = sqrt(dx1 * dx1 + dy1 * dy1); + sub_v2_v2v2(dir_prev, (const float[2]){UNPACK2(data->mval_prev)}, mi_center); + sub_v2_v2v2(dir_curr, (const float[2]){UNPACK2(mval)}, mi_center); - double dx3 = mval[0] - data->mval_prev[0]; - double dy3 = mval[1] - data->mval_prev[1]; + if (normalize_v2(dir_prev) && normalize_v2(dir_curr)) { + float dphi = angle_normalized_v2v2(dir_prev, dir_curr); - /* use doubles here, to make sure a "1.0" (no rotation) - * doesn't become 9.999999e-01, which gives 0.02 for acos */ - double deler = (((dx1 * dx1 + dy1 * dy1) + (dx2 * dx2 + dy2 * dy2) - (dx3 * dx3 + dy3 * dy3)) / - (2.0 * (((A * B) != 0.0) ? (A * B) : 1.0))); - /* ((A * B) ? (A * B) : 1.0) this takes care of potential divide by zero errors */ - - float dphi; - - dphi = saacos((float)deler); - if ((dx1 * dy2 - dx2 * dy1) > 0.0) { - dphi = -dphi; - } - - /* If the angle is zero, because of lack of precision close to the 1.0 value in acos - * approximate the angle with the opposite side of the normalized triangle - * This is a good approximation here since the smallest acos value seems to be around - * 0.02 degree and lower values don't even have a 0.01% error compared to the approximation - */ - if (dphi == 0) { - double dx, dy; - - dx2 /= A; - dy2 /= A; - - dx1 /= B; - dy1 /= B; - - dx = dx1 - dx2; - dy = dy1 - dy2; - - dphi = sqrt(dx * dx + dy * dy); - if ((dx1 * dy2 - dx2 * dy1) > 0.0) { + if (cross_v2v2(dir_prev, dir_curr) > 0.0f) { dphi = -dphi; } - } - data->angle += ((double)dphi) * (mi->precision ? (double)mi->precision_factor : 1.0); + data->angle += ((double)dphi) * (mi->precision ? (double)mi->precision_factor : 1.0); - data->mval_prev[0] = mval[0]; - data->mval_prev[1] = mval[1]; + data->mval_prev[0] = mval[0]; + data->mval_prev[1] = mval[1]; + } output[0] = data->angle; } diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index d14f693da9c..350be247014 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -45,6 +45,7 @@ #include "transform.h" #include "transform_convert.h" +#include "transform_orientations.h" #include "transform_snap.h" /* Own include. */ @@ -523,7 +524,7 @@ void constraintSizeLim(TransInfo *t, TransData *td) /** \name Transform (Rotation Utils) * \{ */ /* Used by Transform Rotation and Transform Normal Rotation */ -void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final) +void headerRotation(TransInfo *t, char *str, const int str_size, float final) { size_t ofs = 0; @@ -532,25 +533,21 @@ void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final) outputNumInput(&(t->num), c, &t->scene->unit); - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - TIP_("Rotation: %s %s %s"), - &c[0], - t->con.text, - t->proptext); + ofs += BLI_snprintf_rlen( + str + ofs, str_size - ofs, TIP_("Rotation: %s %s %s"), &c[0], t->con.text, t->proptext); } else { - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - TIP_("Rotation: %.2f%s %s"), - RAD2DEGF(final), - t->con.text, - t->proptext); + ofs += BLI_snprintf_rlen(str + ofs, + str_size - ofs, + TIP_("Rotation: %.2f%s %s"), + RAD2DEGF(final), + t->con.text, + t->proptext); } if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf( - str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); + ofs += BLI_snprintf_rlen( + str + ofs, str_size - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); } } @@ -810,7 +807,7 @@ void ElementRotation( /* -------------------------------------------------------------------- */ /** \name Transform (Resize Utils) * \{ */ -void headerResize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR]) +void headerResize(TransInfo *t, const float vec[3], char *str, const int str_size) { char tvec[NUM_STR_REP_LEN * 3]; size_t ofs = 0; @@ -826,59 +823,55 @@ void headerResize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR]) if (t->con.mode & CON_APPLY) { switch (t->num.idx_max) { case 0: - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - TIP_("Scale: %s%s %s"), - &tvec[0], - t->con.text, - t->proptext); + ofs += BLI_snprintf_rlen( + str + ofs, str_size - ofs, TIP_("Scale: %s%s %s"), &tvec[0], t->con.text, t->proptext); break; case 1: - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - TIP_("Scale: %s : %s%s %s"), - &tvec[0], - &tvec[NUM_STR_REP_LEN], - t->con.text, - t->proptext); + ofs += BLI_snprintf_rlen(str + ofs, + str_size - ofs, + TIP_("Scale: %s : %s%s %s"), + &tvec[0], + &tvec[NUM_STR_REP_LEN], + t->con.text, + t->proptext); break; case 2: - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - TIP_("Scale: %s : %s : %s%s %s"), - &tvec[0], - &tvec[NUM_STR_REP_LEN], - &tvec[NUM_STR_REP_LEN * 2], - t->con.text, - t->proptext); + ofs += BLI_snprintf_rlen(str + ofs, + str_size - ofs, + TIP_("Scale: %s : %s : %s%s %s"), + &tvec[0], + &tvec[NUM_STR_REP_LEN], + &tvec[NUM_STR_REP_LEN * 2], + t->con.text, + t->proptext); break; } } else { if (t->flag & T_2D_EDIT) { - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - TIP_("Scale X: %s Y: %s%s %s"), - &tvec[0], - &tvec[NUM_STR_REP_LEN], - t->con.text, - t->proptext); + ofs += BLI_snprintf_rlen(str + ofs, + str_size - ofs, + TIP_("Scale X: %s Y: %s%s %s"), + &tvec[0], + &tvec[NUM_STR_REP_LEN], + t->con.text, + t->proptext); } else { - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - TIP_("Scale X: %s Y: %s Z: %s%s %s"), - &tvec[0], - &tvec[NUM_STR_REP_LEN], - &tvec[NUM_STR_REP_LEN * 2], - t->con.text, - t->proptext); + ofs += BLI_snprintf_rlen(str + ofs, + str_size - ofs, + TIP_("Scale X: %s Y: %s Z: %s%s %s"), + &tvec[0], + &tvec[NUM_STR_REP_LEN], + &tvec[NUM_STR_REP_LEN * 2], + t->con.text, + t->proptext); } } if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf( - str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); + ofs += BLI_snprintf_rlen( + str + ofs, str_size - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); } } @@ -1263,7 +1256,7 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode) if (t->data_type == TC_MESH_VERTS) { /* Init Custom Data correction. * Ideally this should be called when creating the TransData. */ - mesh_customdatacorrect_init(t); + transform_convert_mesh_customdatacorrect_init(t); } /* TODO(germano): Some of these operations change the `t->mode`. @@ -1271,4 +1264,38 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode) * BLI_assert(t->mode == mode); */ } +/** + * When in modal and not set, initializes a default orientation for the mode. + */ +void transform_mode_default_modal_orientation_set(TransInfo *t, int type) +{ + /* Currently only these types are supported. */ + BLI_assert(ELEM(type, V3D_ORIENT_GLOBAL, V3D_ORIENT_VIEW)); + + if (t->is_orient_set) { + return; + } + + if (!(t->flag & T_MODAL)) { + return; + } + + if (t->orient[O_DEFAULT].type == type) { + return; + } + + RegionView3D *rv3d = NULL; + if ((type == V3D_ORIENT_VIEW) && (t->spacetype == SPACE_VIEW3D) && t->region && + (t->region->regiontype == RGN_TYPE_WINDOW)) { + rv3d = t->region->regiondata; + } + + t->orient[O_DEFAULT].type = ED_transform_calc_orientation_from_type_ex( + NULL, t->orient[O_DEFAULT].matrix, NULL, rv3d, NULL, NULL, type, 0); + + if (t->orient_curr == O_DEFAULT) { + /* Update Orientation. */ + transform_orientations_current_set(t, O_DEFAULT); + } +} /** \} */ diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h index 6d7a0b528ae..a2b95eb3de4 100644 --- a/source/blender/editors/transform/transform_mode.h +++ b/source/blender/editors/transform/transform_mode.h @@ -47,7 +47,7 @@ void protectedTransBits(short protectflag, float vec[3]); void protectedSizeBits(short protectflag, float size[3]); void constraintTransLim(TransInfo *t, TransData *td); void constraintSizeLim(TransInfo *t, TransData *td); -void headerRotation(TransInfo *t, char *str, float final); +void headerRotation(TransInfo *t, char *str, int str_size, float final); void ElementRotation_ex(TransInfo *t, TransDataContainer *tc, TransData *td, @@ -55,12 +55,13 @@ void ElementRotation_ex(TransInfo *t, const float *center); void ElementRotation( TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around); -void headerResize(TransInfo *t, const float vec[3], char *str); +void headerResize(TransInfo *t, const float vec[3], char *str, int str_size); void ElementResize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3]); short getAnimEdit_SnapMode(TransInfo *t); void doAnimEdit_SnapFrame( TransInfo *t, TransData *td, TransData2D *td2d, struct AnimData *adt, short autosnap); void transform_mode_init(TransInfo *t, struct wmOperator *op, const int mode); +void transform_mode_default_modal_orientation_set(TransInfo *t, int type); /* transform_mode_align.c */ void initAlign(TransInfo *t); diff --git a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c index ee63bf4be6f..68416c780ef 100644 --- a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c +++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c @@ -107,7 +107,6 @@ void initCurveShrinkFatten(TransInfo *t) t->num.unit_sys = t->scene->unit.system; t->num.unit_type[0] = B_UNIT_NONE; - t->flag |= T_NO_ZERO; #ifdef USE_NUM_NO_ZERO t->num.val_flag[0] |= NUM_NO_ZERO; #endif diff --git a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c index c78115561b2..6f2bcc148ce 100644 --- a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c +++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c @@ -103,7 +103,7 @@ static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2])) applyNumInput(&t->num, &angle); - headerRotation(t, str, angle); + headerRotation(t, str, sizeof(str), angle); axis_angle_normalized_to_mat3(mat, axis, angle); @@ -148,5 +148,7 @@ void initNormalRotation(TransInfo *t) storeCustomLNorValue(tc, bm); } + + transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW); } /** \} */ diff --git a/source/blender/editors/transform/transform_mode_edge_seq_slide.c b/source/blender/editors/transform/transform_mode_edge_seq_slide.c index 4330d5e79be..7e7b79c9f90 100644 --- a/source/blender/editors/transform/transform_mode_edge_seq_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c @@ -72,7 +72,7 @@ static void headerSeqSlide(TransInfo *t, const float val[2], char str[UI_MAX_DRA BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.0f, %.0f", val[0], val[1]); } - ofs += BLI_snprintf( + ofs += BLI_snprintf_rlen( str + ofs, UI_MAX_DRAW_STR - ofs, TIP_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text); const wmKeyMapItem *kmi = t->custom.mode.data; @@ -80,10 +80,10 @@ static void headerSeqSlide(TransInfo *t, const float val[2], char str[UI_MAX_DRA ofs += WM_keymap_item_to_string(kmi, false, str + ofs, UI_MAX_DRAW_STR - ofs); } - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - TIP_(" or Alt) Expand to fit %s"), - WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0)); + ofs += BLI_snprintf_rlen(str + ofs, + UI_MAX_DRAW_STR - ofs, + TIP_(" or Alt) Expand to fit %s"), + WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0)); } static void applySeqSlideValue(TransInfo *t, const float val[2]) diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c index 16c1c05a6f8..d255a7d5660 100644 --- a/source/blender/editors/transform/transform_mode_edge_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_slide.c @@ -1482,15 +1482,15 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2])) ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs); } else { - ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final); + ofs += BLI_snprintf_rlen(str + ofs, sizeof(str) - ofs, "%.4f ", final); } - ofs += BLI_snprintf( + ofs += BLI_snprintf_rlen( str + ofs, sizeof(str) - ofs, TIP_("(E)ven: %s, "), WM_bool_as_string(use_even)); if (use_even) { - ofs += BLI_snprintf( + ofs += BLI_snprintf_rlen( str + ofs, sizeof(str) - ofs, TIP_("(F)lipped: %s, "), WM_bool_as_string(flipped)); } - ofs += BLI_snprintf( + ofs += BLI_snprintf_rlen( str + ofs, sizeof(str) - ofs, TIP_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp)); /* done with header string */ diff --git a/source/blender/editors/transform/transform_mode_gpopacity.c b/source/blender/editors/transform/transform_mode_gpopacity.c index e67c6c03481..7c496d271ef 100644 --- a/source/blender/editors/transform/transform_mode_gpopacity.c +++ b/source/blender/editors/transform/transform_mode_gpopacity.c @@ -117,7 +117,6 @@ void initGPOpacity(TransInfo *t) t->num.unit_sys = t->scene->unit.system; t->num.unit_type[0] = B_UNIT_NONE; - t->flag |= T_NO_ZERO; #ifdef USE_NUM_NO_ZERO t->num.val_flag[0] |= NUM_NO_ZERO; #endif diff --git a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c index 95e3d89d2b7..608a49f38b1 100644 --- a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c +++ b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c @@ -119,7 +119,6 @@ void initGPShrinkFatten(TransInfo *t) t->num.unit_sys = t->scene->unit.system; t->num.unit_type[0] = B_UNIT_NONE; - t->flag |= T_NO_ZERO; #ifdef USE_NUM_NO_ZERO t->num.val_flag[0] |= NUM_NO_ZERO; #endif diff --git a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c index 3019984d70b..cfbd6030788 100644 --- a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c +++ b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c @@ -89,7 +89,7 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) /* apply shrink/fatten */ FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; + TransData *td; for (td = tc->data, i = 0; i < tc->data_len; i++, td++) { if (td->flag & TD_SKIP) { continue; @@ -133,7 +133,6 @@ void initMaskShrinkFatten(TransInfo *t) t->num.unit_sys = t->scene->unit.system; t->num.unit_type[0] = B_UNIT_NONE; - t->flag |= T_NO_ZERO; #ifdef USE_NUM_NO_ZERO t->num.val_flag[0] |= NUM_NO_ZERO; #endif diff --git a/source/blender/editors/transform/transform_mode_mirror.c b/source/blender/editors/transform/transform_mode_mirror.c index 9891af8b9a4..f225f1a7c06 100644 --- a/source/blender/editors/transform/transform_mode_mirror.c +++ b/source/blender/editors/transform/transform_mode_mirror.c @@ -235,8 +235,5 @@ void initMirror(TransInfo *t) initMouseInputMode(t, &t->mouse, INPUT_NONE); t->flag |= T_NULL_ONE; - if ((t->flag & T_EDIT) == 0) { - t->flag |= T_NO_ZERO; - } } /** \} */ diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c index 4d0bb7fbe9c..1d7d1369f29 100644 --- a/source/blender/editors/transform/transform_mode_resize.c +++ b/source/blender/editors/transform/transform_mode_resize.c @@ -113,10 +113,10 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2])) pvec[j++] = t->values_final[i]; } } - headerResize(t, pvec, str); + headerResize(t, pvec, str, sizeof(str)); } else { - headerResize(t, t->values_final, str); + headerResize(t, t->values_final, str, sizeof(str)); } copy_m3_m3(t->mat, mat); /* used in gizmo */ @@ -176,7 +176,6 @@ void initResize(TransInfo *t) t->num.val_flag[2] |= NUM_NULL_ONE; t->num.flag |= NUM_AFFECT_ALL; if ((t->flag & T_EDIT) == 0) { - t->flag |= T_NO_ZERO; #ifdef USE_NUM_NO_ZERO t->num.val_flag[0] |= NUM_NO_ZERO; t->num.val_flag[1] |= NUM_NO_ZERO; @@ -194,5 +193,7 @@ void initResize(TransInfo *t) t->num.unit_type[0] = B_UNIT_NONE; t->num.unit_type[1] = B_UNIT_NONE; t->num.unit_type[2] = B_UNIT_NONE; + + transform_mode_default_modal_orientation_set(t, V3D_ORIENT_GLOBAL); } /** \} */ diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c index 8d8594d5775..8350e94e0e8 100644 --- a/source/blender/editors/transform/transform_mode_rotate.c +++ b/source/blender/editors/transform/transform_mode_rotate.c @@ -217,7 +217,7 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2])) t->values_final[0] = final; - headerRotation(t, str, final); + headerRotation(t, str, sizeof(str), final); const bool is_large_rotation = hasNumInput(&t->num); applyRotationValue(t, final, axis_final, is_large_rotation); @@ -249,5 +249,7 @@ void initRotation(TransInfo *t) if (t->flag & T_2D_EDIT) { t->flag |= T_NO_CONSTRAINT; } + + transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW); } /** \} */ diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c index a41c49710b9..23ee55bf6c5 100644 --- a/source/blender/editors/transform/transform_mode_shear.c +++ b/source/blender/editors/transform/transform_mode_shear.c @@ -232,5 +232,7 @@ void initShear(TransInfo *t) t->num.unit_type[0] = B_UNIT_NONE; /* Don't think we have any unit here? */ t->flag |= T_NO_CONSTRAINT; + + transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW); } /** \} */ diff --git a/source/blender/editors/transform/transform_mode_shrink_fatten.c b/source/blender/editors/transform/transform_mode_shrink_fatten.c index 6e497d85417..d2d73a14396 100644 --- a/source/blender/editors/transform/transform_mode_shrink_fatten.c +++ b/source/blender/editors/transform/transform_mode_shrink_fatten.c @@ -79,7 +79,7 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; outputNumInput(&(t->num), c, unit); - ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%s", c); + ofs += BLI_snprintf_rlen(str + ofs, sizeof(str) - ofs, "%s", c); } else { /* default header print */ @@ -93,12 +93,12 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) true); } else { - ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f", distance); + ofs += BLI_snprintf_rlen(str + ofs, sizeof(str) - ofs, "%.4f", distance); } } if (t->proptext[0]) { - ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", t->proptext); + ofs += BLI_snprintf_rlen(str + ofs, sizeof(str) - ofs, " %s", t->proptext); } ofs += BLI_strncpy_rlen(str + ofs, ", (", sizeof(str) - ofs); diff --git a/source/blender/editors/transform/transform_mode_skin_resize.c b/source/blender/editors/transform/transform_mode_skin_resize.c index 8beacb844b9..75ad83b0787 100644 --- a/source/blender/editors/transform/transform_mode_skin_resize.c +++ b/source/blender/editors/transform/transform_mode_skin_resize.c @@ -64,7 +64,7 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2])) size_to_mat3(mat, t->values_final); - headerResize(t, t->values_final, str); + headerResize(t, t->values_final, str, sizeof(str)); FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; @@ -111,7 +111,6 @@ void initSkinResize(TransInfo *t) t->num.val_flag[2] |= NUM_NULL_ONE; t->num.flag |= NUM_AFFECT_ALL; if ((t->flag & T_EDIT) == 0) { - t->flag |= T_NO_ZERO; #ifdef USE_NUM_NO_ZERO t->num.val_flag[0] |= NUM_NO_ZERO; t->num.val_flag[1] |= NUM_NO_ZERO; diff --git a/source/blender/editors/transform/transform_mode_timetranslate.c b/source/blender/editors/transform/transform_mode_timetranslate.c index 5ad6d04b4de..948242e547f 100644 --- a/source/blender/editors/transform/transform_mode_timetranslate.c +++ b/source/blender/editors/transform/transform_mode_timetranslate.c @@ -76,10 +76,10 @@ static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR]) } } - ofs += BLI_snprintf(str, UI_MAX_DRAW_STR, TIP_("DeltaX: %s"), &tvec[0]); + ofs += BLI_snprintf_rlen(str, UI_MAX_DRAW_STR, TIP_("DeltaX: %s"), &tvec[0]); if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf( + ofs += BLI_snprintf_rlen( str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); } } diff --git a/source/blender/editors/transform/transform_mode_trackball.c b/source/blender/editors/transform/transform_mode_trackball.c index 5a57a69f986..d05077ef1ef 100644 --- a/source/blender/editors/transform/transform_mode_trackball.c +++ b/source/blender/editors/transform/transform_mode_trackball.c @@ -102,24 +102,24 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c, &t->scene->unit); - ofs += BLI_snprintf(str + ofs, - sizeof(str) - ofs, - TIP_("Trackball: %s %s %s"), - &c[0], - &c[NUM_STR_REP_LEN], - t->proptext); + ofs += BLI_snprintf_rlen(str + ofs, + sizeof(str) - ofs, + TIP_("Trackball: %s %s %s"), + &c[0], + &c[NUM_STR_REP_LEN], + t->proptext); } else { - ofs += BLI_snprintf(str + ofs, - sizeof(str) - ofs, - TIP_("Trackball: %.2f %.2f %s"), - RAD2DEGF(phi[0]), - RAD2DEGF(phi[1]), - t->proptext); + ofs += BLI_snprintf_rlen(str + ofs, + sizeof(str) - ofs, + TIP_("Trackball: %.2f %.2f %s"), + RAD2DEGF(phi[0]), + RAD2DEGF(phi[1]), + t->proptext); } if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf( + ofs += BLI_snprintf_rlen( str + ofs, sizeof(str) - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); } diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 41fc6ee0aaf..3088f6a7776 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -141,67 +141,67 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_ if (t->con.mode & CON_APPLY) { switch (t->num.idx_max) { case 0: - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - "D: %s (%s)%s %s %s", - &tvec[0], - distvec, - t->con.text, - t->proptext, - autoik); + ofs += BLI_snprintf_rlen(str + ofs, + UI_MAX_DRAW_STR - ofs, + "D: %s (%s)%s %s %s", + &tvec[0], + distvec, + t->con.text, + t->proptext, + autoik); break; case 1: - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - "D: %s D: %s (%s)%s %s %s", - &tvec[0], - &tvec[NUM_STR_REP_LEN], - distvec, - t->con.text, - t->proptext, - autoik); + ofs += BLI_snprintf_rlen(str + ofs, + UI_MAX_DRAW_STR - ofs, + "D: %s D: %s (%s)%s %s %s", + &tvec[0], + &tvec[NUM_STR_REP_LEN], + distvec, + t->con.text, + t->proptext, + autoik); break; case 2: - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - "D: %s D: %s D: %s (%s)%s %s %s", - &tvec[0], - &tvec[NUM_STR_REP_LEN], - &tvec[NUM_STR_REP_LEN * 2], - distvec, - t->con.text, - t->proptext, - autoik); + ofs += BLI_snprintf_rlen(str + ofs, + UI_MAX_DRAW_STR - ofs, + "D: %s D: %s D: %s (%s)%s %s %s", + &tvec[0], + &tvec[NUM_STR_REP_LEN], + &tvec[NUM_STR_REP_LEN * 2], + distvec, + t->con.text, + t->proptext, + autoik); break; } } else { if (t->flag & T_2D_EDIT) { - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - "Dx: %s Dy: %s (%s)%s %s", - &tvec[0], - &tvec[NUM_STR_REP_LEN], - distvec, - t->con.text, - t->proptext); + ofs += BLI_snprintf_rlen(str + ofs, + UI_MAX_DRAW_STR - ofs, + "Dx: %s Dy: %s (%s)%s %s", + &tvec[0], + &tvec[NUM_STR_REP_LEN], + distvec, + t->con.text, + t->proptext); } else { - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - "Dx: %s Dy: %s Dz: %s (%s)%s %s %s", - &tvec[0], - &tvec[NUM_STR_REP_LEN], - &tvec[NUM_STR_REP_LEN * 2], - distvec, - t->con.text, - t->proptext, - autoik); + ofs += BLI_snprintf_rlen(str + ofs, + UI_MAX_DRAW_STR - ofs, + "Dx: %s Dy: %s Dz: %s (%s)%s %s %s", + &tvec[0], + &tvec[NUM_STR_REP_LEN], + &tvec[NUM_STR_REP_LEN * 2], + distvec, + t->con.text, + t->proptext, + autoik); } } if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf( + ofs += BLI_snprintf_rlen( str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); } @@ -217,12 +217,12 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_ WM_modalkeymap_items_to_string( t->keymap, TFM_MODAL_INSERTOFS_TOGGLE_DIR, true, str_km, sizeof(str_km)); - ofs += BLI_snprintf(str, - UI_MAX_DRAW_STR, - TIP_("Auto-offset set to %s - press %s to toggle direction | %s"), - str_dir, - str_km, - str_old); + ofs += BLI_snprintf_rlen(str, + UI_MAX_DRAW_STR, + TIP_("Auto-offset set to %s - press %s to toggle direction | %s"), + str_dir, + str_km, + str_old); MEM_freeN((void *)str_old); } @@ -470,5 +470,8 @@ void initTranslation(TransInfo *t) t->num.unit_type[1] = B_UNIT_NONE; t->num.unit_type[2] = B_UNIT_NONE; } + + transform_mode_default_modal_orientation_set( + t, (t->options & CTX_CAMERA) ? V3D_ORIENT_VIEW : V3D_ORIENT_GLOBAL); } /** \} */ diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c index 1e5d027e253..e16aa636872 100644 --- a/source/blender/editors/transform/transform_mode_vert_slide.c +++ b/source/blender/editors/transform/transform_mode_vert_slide.c @@ -606,15 +606,15 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2])) ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs); } else { - ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final); + ofs += BLI_snprintf_rlen(str + ofs, sizeof(str) - ofs, "%.4f ", final); } - ofs += BLI_snprintf( + ofs += BLI_snprintf_rlen( str + ofs, sizeof(str) - ofs, TIP_("(E)ven: %s, "), WM_bool_as_string(use_even)); if (use_even) { - ofs += BLI_snprintf( + ofs += BLI_snprintf_rlen( str + ofs, sizeof(str) - ofs, TIP_("(F)lipped: %s, "), WM_bool_as_string(flipped)); } - ofs += BLI_snprintf( + ofs += BLI_snprintf_rlen( str + ofs, sizeof(str) - ofs, TIP_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp)); /* done with header string */ diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 1470d3b7059..d97bcba161f 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -445,7 +445,7 @@ int BIF_countTransformOrientation(const bContext *C) return BLI_listbase_count(transform_orientations); } -void applyTransformOrientation(const TransformOrientation *ts, float r_mat[3][3], char *r_name) +void applyTransformOrientation(const TransformOrientation *ts, float r_mat[3][3], char r_name[64]) { if (r_name) { BLI_strncpy(r_name, ts->name, MAX_NAME); @@ -492,12 +492,11 @@ void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3 Object *obedit = CTX_data_edit_object(C); RegionView3D *rv3d = region->regiondata; Object *ob = OBACT(view_layer); - const short orientation_type = scene->orientation_slots[SCE_ORIENT_DEFAULT].type; - const short orientation_index_custom = scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom; + const short orient_index = BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT); const int pivot_point = scene->toolsettings->transform_pivot_point; ED_transform_calc_orientation_from_type_ex( - C, r_mat, scene, rv3d, ob, obedit, orientation_type, orientation_index_custom, pivot_point); + C, r_mat, scene, rv3d, ob, obedit, orient_index, pivot_point); } /** @@ -516,11 +515,10 @@ short ED_transform_calc_orientation_from_type_ex(const bContext *C, RegionView3D *rv3d, Object *ob, Object *obedit, - const short orientation_type, - int orientation_index_custom, + const short orientation_index, const int pivot_point) { - switch (orientation_type) { + switch (orientation_index) { case V3D_ORIENT_GIMBAL: { if (ob && gimbal_axis(ob, r_mat)) { break; @@ -577,24 +575,28 @@ short ED_transform_calc_orientation_from_type_ex(const bContext *C, } case V3D_ORIENT_CUSTOM: default: { - BLI_assert(orientation_type >= V3D_ORIENT_CUSTOM); + BLI_assert(orientation_index >= V3D_ORIENT_CUSTOM); + int orientation_index_custom = orientation_index - V3D_ORIENT_CUSTOM; TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find( scene, orientation_index_custom); applyTransformOrientation(custom_orientation, r_mat, NULL); - return V3D_ORIENT_CUSTOM + orientation_index_custom; + break; } } - return orientation_type; + return orientation_index; } /* Sets the matrix of the specified space orientation. * If the matrix cannot be obtained, an orientation different from the one * informed is returned */ -short transform_orientation_matrix_get( - bContext *C, TransInfo *t, short orientation, const float custom[3][3], float r_spacemtx[3][3]) +short transform_orientation_matrix_get(bContext *C, + TransInfo *t, + short orient_index, + const float custom[3][3], + float r_spacemtx[3][3]) { - if (orientation == V3D_ORIENT_CUSTOM_MATRIX) { + if (orient_index == V3D_ORIENT_CUSTOM_MATRIX) { copy_m3_m3(r_spacemtx, custom); return V3D_ORIENT_CUSTOM_MATRIX; } @@ -603,24 +605,20 @@ short transform_orientation_matrix_get( Object *obedit = CTX_data_edit_object(C); Scene *scene = t->scene; RegionView3D *rv3d = NULL; - int orientation_index_custom = 0; - - if (orientation >= V3D_ORIENT_CUSTOM) { - orientation_index_custom = orientation - V3D_ORIENT_CUSTOM; - orientation = V3D_ORIENT_CUSTOM; - } - else if (ob && (ob->mode & OB_MODE_ALL_WEIGHT_PAINT) && !(t->options & CTX_PAINT_CURVE)) { - Object *ob_armature = transform_object_deform_pose_armature_get(t, ob); - if (ob_armature) { - ob = ob_armature; - } - } if ((t->spacetype == SPACE_VIEW3D) && t->region && (t->region->regiontype == RGN_TYPE_WINDOW)) { rv3d = t->region->regiondata; + + if (ob && (ob->mode & OB_MODE_ALL_WEIGHT_PAINT) && !(t->options & CTX_PAINT_CURVE)) { + Object *ob_armature = transform_object_deform_pose_armature_get(t, ob); + if (ob_armature) { + /* The armature matrix is used for GIMBAL, NORMAL and LOCAL orientations. */ + ob = ob_armature; + } + } } - short orient_type = ED_transform_calc_orientation_from_type_ex( + short r_orient_index = ED_transform_calc_orientation_from_type_ex( C, r_spacemtx, /* extra args (can be accessed from context) */ @@ -628,13 +626,12 @@ short transform_orientation_matrix_get( rv3d, ob, obedit, - orientation, - orientation_index_custom, + orient_index, t->around); if (rv3d && (t->options & CTX_PAINT_CURVE)) { /* Screen space in the 3d region. */ - if (orient_type == V3D_ORIENT_VIEW) { + if (r_orient_index == V3D_ORIENT_VIEW) { unit_m3(r_spacemtx); } else { @@ -643,7 +640,7 @@ short transform_orientation_matrix_get( } } - return orient_type; + return r_orient_index; } const char *transform_orientations_spacename_get(TransInfo *t, const short orient_type) @@ -674,10 +671,6 @@ const char *transform_orientations_spacename_get(TransInfo *t, const short orien void transform_orientations_current_set(TransInfo *t, const short orient_index) { - if (t->orient_curr == orient_index) { - return; - } - const short orientation = t->orient[orient_index].type; const char *spacename = transform_orientations_spacename_get(t, orientation); diff --git a/source/blender/editors/transform/transform_orientations.h b/source/blender/editors/transform/transform_orientations.h index e9c146a6853..de8c9b165c1 100644 --- a/source/blender/editors/transform/transform_orientations.h +++ b/source/blender/editors/transform/transform_orientations.h @@ -27,7 +27,7 @@ struct TransInfo; short transform_orientation_matrix_get(struct bContext *C, struct TransInfo *t, - short orientation, + short orient_index, const float custom[3][3], float r_spacemtx[3][3]); const char *transform_orientations_spacename_get(struct TransInfo *t, const short orient_type); diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index d0f91802fff..bebef049718 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -345,7 +345,7 @@ void applyProject(TransInfo *t) SCE_SNAP_MODE_FACE, &(const struct SnapObjectParams){ .snap_select = t->tsnap.modeSelect, - .use_object_edit_cage = (t->flag & T_EDIT) != 0, + .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, .use_occlusion_test = false, .use_backface_culling = t->tsnap.use_backface_culling, }, @@ -1072,7 +1072,7 @@ static void TargetSnapClosest(TransInfo *t) if (t->options & CTX_OBJECT) { int i; FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; + TransData *td; for (td = tc->data, i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) { const BoundBox *bb = NULL; @@ -1167,7 +1167,7 @@ short snapObjectsTransform( t->settings->snap_mode, &(const struct SnapObjectParams){ .snap_select = t->tsnap.modeSelect, - .use_object_edit_cage = (t->flag & T_EDIT) != 0, + .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, .use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE, .use_backface_culling = t->tsnap.use_backface_culling, }, @@ -1201,7 +1201,7 @@ bool peelObjectsTransform(TransInfo *t, t->depsgraph, &(const struct SnapObjectParams){ .snap_select = t->tsnap.modeSelect, - .use_object_edit_cage = (t->flag & T_EDIT) != 0, + .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, }, mval, -1.0f, diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 58198f21ba2..512f912a532 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -43,6 +43,8 @@ #include "BKE_curve.h" #include "BKE_duplilist.h" #include "BKE_editmesh.h" +#include "BKE_geometry_set.h" +#include "BKE_global.h" #include "BKE_layer.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" @@ -144,9 +146,37 @@ struct SnapObjectContext { /** \name Utilities * \{ */ -static bool editmesh_eval_final_is_bmesh(const BMEditMesh *em) +/* Mesh used for snapping. + * If NULL the BMesh should be used. */ +static Mesh *mesh_for_snap(Object *ob_eval, eSnapEditType edit_mode_type, bool *r_use_hide) { - return (em->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH); + Mesh *me_eval = ob_eval->data; + bool use_hide = false; + if (BKE_object_is_in_editmode(ob_eval)) { + if (edit_mode_type == SNAP_GEOM_EDIT) { + return NULL; + } + + BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval); + if ((edit_mode_type == SNAP_GEOM_FINAL) && em_eval->mesh_eval_final) { + if (em_eval->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) { + return NULL; + } + me_eval = em_eval->mesh_eval_final; + use_hide = true; + } + else if ((edit_mode_type == SNAP_GEOM_CAGE) && em_eval->mesh_eval_cage) { + if (em_eval->mesh_eval_cage->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) { + return NULL; + } + me_eval = em_eval->mesh_eval_cage; + use_hide = true; + } + } + if (r_use_hide) { + *r_use_hide = use_hide; + } + return me_eval; } /** \} */ @@ -208,30 +238,69 @@ static void snap_object_data_clear(SnapObjectData *sod) memset(&sod->type, 0x0, sizeof(*sod) - offsetof(SnapObjectData, type)); } -static SnapObjectData *snap_object_data_lookup(SnapObjectContext *sctx, Object *ob) +static SnapObjectData *snap_object_data_lookup(SnapObjectContext *sctx, Object *ob_eval) { - SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob); + SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob_eval); if (sod == NULL) { if (sctx->cache.data_to_object_map != NULL) { - ob = BLI_ghash_lookup(sctx->cache.data_to_object_map, ob->data); + ob_eval = BLI_ghash_lookup(sctx->cache.data_to_object_map, ob_eval->data); /* Could be NULl when mixing edit-mode and non edit-mode objects. */ - if (ob != NULL) { - sod = BLI_ghash_lookup(sctx->cache.object_map, ob); + if (ob_eval != NULL) { + sod = BLI_ghash_lookup(sctx->cache.object_map, ob_eval); } } } return sod; } -static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, Object *ob) +static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, + Object *ob_eval, + Mesh *me_eval, + bool use_hide) { SnapObjectData *sod; void **sod_p; bool init = false; - if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { + if (BLI_ghash_ensure_p(sctx->cache.object_map, ob_eval, &sod_p)) { sod = *sod_p; + bool is_dirty = false; if (sod->type != SNAP_MESH) { + is_dirty = true; + } + else if (sod->treedata_mesh.tree && sod->treedata_mesh.cached && + !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->treedata_mesh.tree)) { + /* The tree is owned by the Mesh and may have been freed since we last used. */ + is_dirty = true; + } + else if (sod->bvhtree[0] && sod->cached[0] && + !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->bvhtree[0])) { + /* The tree is owned by the Mesh and may have been freed since we last used. */ + is_dirty = true; + } + else if (sod->bvhtree[1] && sod->cached[1] && + !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->bvhtree[1])) { + /* The tree is owned by the Mesh and may have been freed since we last used. */ + is_dirty = true; + } + else if (!sod->treedata_mesh.looptri_allocated && + sod->treedata_mesh.looptri != me_eval->runtime.looptris.array) { + is_dirty = true; + } + else if (!sod->treedata_mesh.vert_allocated && sod->treedata_mesh.vert != me_eval->mvert) { + is_dirty = true; + } + else if (!sod->treedata_mesh.loop_allocated && sod->treedata_mesh.loop != me_eval->mloop) { + is_dirty = true; + } + else if (!sod->treedata_mesh.edge_allocated && sod->treedata_mesh.edge != me_eval->medge) { + is_dirty = true; + } + else if (sod->poly != me_eval->mpoly) { + is_dirty = true; + } + + if (is_dirty) { snap_object_data_clear(sod); init = true; } @@ -243,8 +312,32 @@ static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, Object if (init) { sod->type = SNAP_MESH; - /* start assuming that it has each of these element types */ - sod->has_looptris = true; + + /* The BVHTree from looptris is always required. */ + BLI_assert(sod->treedata_mesh.tree == NULL); + BKE_bvhtree_from_mesh_get(&sod->treedata_mesh, + me_eval, + use_hide ? BVHTREE_FROM_LOOPTRI_NO_HIDDEN : BVHTREE_FROM_LOOPTRI, + 4); + + if (sod->treedata_mesh.tree == NULL) { + sod->treedata_mesh.vert = me_eval->mvert; + sod->treedata_mesh.loop = me_eval->mloop; + sod->treedata_mesh.looptri = BKE_mesh_runtime_looptri_ensure(me_eval); + BLI_assert(sod->has_looptris == false); + } + else { + BLI_assert(sod->treedata_mesh.vert != NULL); + BLI_assert(sod->treedata_mesh.loop != NULL); + BLI_assert(sod->treedata_mesh.looptri != NULL); + sod->has_looptris = true; + } + + /* Required for snapping with occlusion. */ + sod->treedata_mesh.edge = me_eval->medge; + sod->poly = me_eval->mpoly; + + /* Start assuming that it has each of these element types. */ sod->has_loose_edge = true; sod->has_loose_vert = true; } @@ -252,26 +345,26 @@ static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, Object return sod; } -static struct Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob) +static struct Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob_eval) { - BMEditMesh *em = BKE_editmesh_from_object(ob); - if (em->mesh_eval_final) { - return &em->mesh_eval_final->runtime; + BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval); + if (em_eval->mesh_eval_final) { + return &em_eval->mesh_eval_final->runtime; } - if (em->mesh_eval_cage) { - return &em->mesh_eval_cage->runtime; + if (em_eval->mesh_eval_cage) { + return &em_eval->mesh_eval_cage->runtime; } - return &((Mesh *)ob->data)->runtime; + return &((Mesh *)ob_eval->data)->runtime; } static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx, - Object *ob, + Object *ob_eval, BMEditMesh *em) { SnapObjectData *sod; void **sod_p; - bool init = false, init_min_max = true, clear_cache = false; + bool init = false; { /* Use object-data as the key in ghash since the editmesh @@ -280,48 +373,53 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx, sctx->cache.data_to_object_map = BLI_ghash_ptr_new(__func__); } void **ob_p; - if (BLI_ghash_ensure_p(sctx->cache.data_to_object_map, ob->data, &ob_p)) { - ob = *ob_p; + if (BLI_ghash_ensure_p(sctx->cache.data_to_object_map, ob_eval->data, &ob_p)) { + ob_eval = *ob_p; } else { - *ob_p = ob; + *ob_p = ob_eval; } } - if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { + if (BLI_ghash_ensure_p(sctx->cache.object_map, ob_eval, &sod_p)) { sod = *sod_p; - bool clear = false; + bool is_dirty = false; /* Check if the geometry has changed. */ if (sod->type != SNAP_EDIT_MESH) { - clear = true; + is_dirty = true; } else if (sod->treedata_editmesh.em != em) { - clear_cache = true; - init = true; + is_dirty = true; } else if (sod->mesh_runtime) { - if (sod->mesh_runtime != snap_object_data_editmesh_runtime_get(ob)) { - clear_cache = true; - init = true; + if (sod->mesh_runtime != snap_object_data_editmesh_runtime_get(ob_eval)) { + if (G.moving) { + /* Hack to 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); + } + else { + is_dirty = true; + } } else if (sod->treedata_editmesh.tree && sod->treedata_editmesh.cached && !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->treedata_editmesh.tree)) { /* The tree is owned by the EditMesh and may have been freed since we last used! */ - clear = true; + is_dirty = true; } else if (sod->bvhtree[0] && sod->cached[0] && !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[0])) { /* The tree is owned by the EditMesh and may have been freed since we last used! */ - clear = true; + is_dirty = true; } else if (sod->bvhtree[1] && sod->cached[1] && !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[1])) { /* The tree is owned by the EditMesh and may have been freed since we last used! */ - clear = true; + is_dirty = true; } } - if (clear) { + if (is_dirty) { snap_object_data_clear(sod); init = true; } @@ -334,27 +432,8 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx, if (init) { sod->type = SNAP_EDIT_MESH; sod->treedata_editmesh.em = em; - - if (clear_cache) { - /* Only init min and max when you have a non-custom bvhtree pending. */ - init_min_max = false; - if (sod->treedata_editmesh.cached) { - sod->treedata_editmesh.tree = NULL; - init_min_max = true; - } - for (int i = 0; i < ARRAY_SIZE(sod->bvhtree); i++) { - if (sod->cached[i]) { - sod->bvhtree[i] = NULL; - init_min_max = true; - } - } - } - - if (init_min_max) { - bm_mesh_minmax(em->bm, sod->min, sod->max); - } - - sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob); + sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob_eval); + bm_mesh_minmax(em->bm, sod->min, sod->max); } return sod; @@ -367,9 +446,9 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx, * \{ */ typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx, - Object *ob, + Object *ob_eval, float obmat[4][4], - bool use_obedit, + eSnapEditType edit_mode_type, bool use_backface_culling, bool is_object_active, void *data); @@ -386,10 +465,17 @@ static void iter_snap_objects(SnapObjectContext *sctx, ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); const View3D *v3d = sctx->v3d_data.v3d; const eSnapSelect snap_select = params->snap_select; - const bool use_object_edit_cage = params->use_object_edit_cage; + const eSnapEditType edit_mode_type = params->edit_mode_type; const bool use_backface_culling = params->use_backface_culling; Base *base_act = view_layer->basact; + if (snap_select == SNAP_ONLY_ACTIVE) { + Object *obj_eval = DEG_get_evaluated_object(depsgraph, base_act->object); + sob_callback( + sctx, obj_eval, obj_eval->obmat, edit_mode_type, use_backface_culling, true, data); + return; + } + for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) { if (!BASE_VISIBLE(v3d, base)) { continue; @@ -415,14 +501,16 @@ static void iter_snap_objects(SnapObjectContext *sctx, } Object *obj_eval = DEG_get_evaluated_object(depsgraph, base->object); - if (obj_eval->transflag & OB_DUPLI) { - DupliObject *dupli_ob; + if (obj_eval->transflag & OB_DUPLI || + (obj_eval->runtime.geometry_set_eval != NULL && + BKE_geometry_set_has_instances(obj_eval->runtime.geometry_set_eval))) { ListBase *lb = object_duplilist(depsgraph, sctx->scene, obj_eval); - for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { + for (DupliObject *dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { + BLI_assert(DEG_is_evaluated_object(dupli_ob->ob)); sob_callback(sctx, dupli_ob->ob, dupli_ob->mat, - use_object_edit_cage, + edit_mode_type, use_backface_culling, is_object_active, data); @@ -433,7 +521,7 @@ static void iter_snap_objects(SnapObjectContext *sctx, sob_callback(sctx, obj_eval, obj_eval->obmat, - use_object_edit_cage, + edit_mode_type, use_backface_culling, is_object_active, data); @@ -461,7 +549,7 @@ struct RayCastAll_Data { float len_diff; float local_scale; - Object *ob; + Object *ob_eval; uint ob_uuid; /* output data */ @@ -473,7 +561,7 @@ static struct SnapObjectHitDepth *hit_depth_create(const float depth, const float co[3], const float no[3], int index, - Object *ob, + Object *ob_eval, const float obmat[4][4], uint ob_uuid) { @@ -484,7 +572,7 @@ static struct SnapObjectHitDepth *hit_depth_create(const float depth, copy_v3_v3(hit->no, no); hit->index = index; - hit->ob = ob; + hit->ob_eval = ob_eval; copy_m4_m4(hit->obmat, (float(*)[4])obmat); hit->ob_uuid = ob_uuid; @@ -526,7 +614,7 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH normalize_v3(normal); struct SnapObjectHitDepth *hit_item = hit_depth_create( - depth, location, normal, hit->index, data->ob, data->obmat, data->ob_uuid); + depth, location, normal, hit->index, data->ob_eval, data->obmat, data->ob_uuid); BLI_addtail(data->hit_list, hit_item); } } @@ -598,8 +686,8 @@ static void editmesh_looptri_raycast_backface_culling_cb(void *userdata, static bool raycastMesh(SnapObjectContext *sctx, const float ray_start[3], const float ray_dir[3], - Object *ob, - Mesh *me, + Object *ob_eval, + Mesh *me_eval, const float obmat[4][4], const uint ob_index, bool use_hide, @@ -614,7 +702,7 @@ static bool raycastMesh(SnapObjectContext *sctx, { bool retval = false; - if (me->totpoly == 0) { + if (me_eval->totpoly == 0) { return retval; } @@ -638,7 +726,7 @@ static bool raycastMesh(SnapObjectContext *sctx, } /* Test BoundBox */ - BoundBox *bb = BKE_mesh_boundbox_get(ob); + BoundBox *bb = BKE_mesh_boundbox_get(ob_eval); if (bb) { /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */ if (!isect_ray_aabb_v3_simple( @@ -658,53 +746,18 @@ static bool raycastMesh(SnapObjectContext *sctx, len_diff = 0.0f; } - SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob); + SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide); BVHTreeFromMesh *treedata = &sod->treedata_mesh; - /* The tree is owned by the Mesh and may have been freed since we last used. */ - if (treedata->tree) { - BLI_assert(treedata->cached); - if (!bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)) { - free_bvhtree_from_mesh(treedata); - } - else { - /* Update Pointers. */ - if (treedata->vert && treedata->vert_allocated == false) { - treedata->vert = me->mvert; - } - if (treedata->loop && treedata->loop_allocated == false) { - treedata->loop = me->mloop; - } - if (treedata->looptri && treedata->looptri_allocated == false) { - treedata->looptri = BKE_mesh_runtime_looptri_ensure(me); - } - /* required for snapping with occlusion. */ - treedata->edge = me->medge; - sod->poly = me->mpoly; - } - } - if (treedata->tree == NULL) { - if (use_hide) { - BKE_bvhtree_from_mesh_get(treedata, me, BVHTREE_FROM_LOOPTRI_NO_HIDDEN, 4); - } - else { - BKE_bvhtree_from_mesh_get(treedata, me, BVHTREE_FROM_LOOPTRI, 4); - } - - /* required for snapping with occlusion. */ - treedata->edge = me->medge; - sod->poly = me->mpoly; - - if (treedata->tree == NULL) { - return retval; - } + return retval; } float timat[3][3]; /* transpose inverse matrix for normals */ transpose_m3_m4(timat, imat); + BLI_assert(treedata->raycast_callback != NULL); if (r_hit_list) { struct RayCastAll_Data data; @@ -714,7 +767,7 @@ static bool raycastMesh(SnapObjectContext *sctx, data.timat = timat; data.len_diff = len_diff; data.local_scale = local_scale; - data.ob = ob; + data.ob_eval = ob_eval; data.ob_uuid = ob_index; data.hit_list = r_hit_list; data.retval = retval; @@ -773,7 +826,7 @@ static bool raycastMesh(SnapObjectContext *sctx, static bool raycastEditMesh(SnapObjectContext *sctx, const float ray_start[3], const float ray_dir[3], - Object *ob, + Object *ob_eval, BMEditMesh *em, const float obmat[4][4], const uint ob_index, @@ -810,7 +863,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx, local_depth *= local_scale; } - SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob, em); + SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob_eval, em); /* Test BoundBox */ @@ -836,7 +889,8 @@ static bool raycastEditMesh(SnapObjectContext *sctx, if (treedata->tree == NULL) { /* Operators only update the editmesh looptris of the original mesh. */ - BLI_assert(sod->treedata_editmesh.em == BKE_editmesh_from_object(DEG_get_original_object(ob))); + BLI_assert(sod->treedata_editmesh.em == + BKE_editmesh_from_object(DEG_get_original_object(ob_eval))); em = sod->treedata_editmesh.em; if (sctx->callbacks.edit_mesh.test_face_fn) { @@ -883,7 +937,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx, data.timat = timat; data.len_diff = len_diff; data.local_scale = local_scale; - data.ob = ob; + data.ob_eval = ob_eval; data.ob_uuid = ob_index; data.hit_list = r_hit_list; data.retval = retval; @@ -964,9 +1018,9 @@ struct RaycastObjUserData { * \note Duplicate args here are documented at #snapObjectsRay */ static void raycast_obj_fn(SnapObjectContext *sctx, - Object *ob, + Object *ob_eval, float obmat[4][4], - bool use_obedit, + eSnapEditType edit_mode_type, bool use_backface_culling, bool is_object_active, void *data) @@ -979,53 +1033,46 @@ static void raycast_obj_fn(SnapObjectContext *sctx, bool retval = false; if (use_occlusion_test) { - if (use_obedit && sctx->use_v3d && XRAY_FLAG_ENABLED(sctx->v3d_data.v3d)) { + if ((edit_mode_type == SNAP_GEOM_EDIT) && sctx->use_v3d && + XRAY_FLAG_ENABLED(sctx->v3d_data.v3d)) { /* Use of occlude geometry in editing mode disabled. */ return; } - if (ELEM(ob->dt, OB_BOUNDBOX, OB_WIRE)) { + if (ELEM(ob_eval->dt, OB_BOUNDBOX, OB_WIRE)) { /* Do not hit objects that are in wire or bounding box * display mode. */ return; } } - switch (ob->type) { + switch (ob_eval->type) { case OB_MESH: { - Mesh *me = ob->data; bool use_hide = false; - if (BKE_object_is_in_editmode(ob)) { - if (use_obedit || editmesh_eval_final_is_bmesh(me->edit_mesh)) { - /* Operators only update the editmesh looptris of the original mesh. */ - BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob)); - retval = raycastEditMesh(sctx, - dt->ray_start, - dt->ray_dir, - ob, - em_orig, - obmat, - ob_index, - use_backface_culling, - ray_depth, - dt->r_loc, - dt->r_no, - dt->r_index, - dt->r_hit_list); - break; - } - - BMEditMesh *em = BKE_editmesh_from_object(ob); - if (em->mesh_eval_final) { - me = em->mesh_eval_final; - use_hide = true; - } + Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide); + if (me_eval == NULL) { + /* Operators only update the editmesh looptris of the original mesh. */ + BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob_eval)); + retval = raycastEditMesh(sctx, + dt->ray_start, + dt->ray_dir, + ob_eval, + em_orig, + obmat, + ob_index, + use_backface_culling, + ray_depth, + dt->r_loc, + dt->r_no, + dt->r_index, + dt->r_hit_list); + break; } retval = raycastMesh(sctx, dt->ray_start, dt->ray_dir, - ob, - me, + ob_eval, + me_eval, obmat, ob_index, use_hide, @@ -1041,12 +1088,12 @@ static void raycast_obj_fn(SnapObjectContext *sctx, case OB_SURF: case OB_FONT: { if (!is_object_active) { - Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); + Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval); if (mesh_eval) { retval = raycastMesh(sctx, dt->ray_start, dt->ray_dir, - ob, + ob_eval, mesh_eval, obmat, ob_index, @@ -1065,7 +1112,7 @@ static void raycast_obj_fn(SnapObjectContext *sctx, if (retval) { if (dt->r_ob) { - *dt->r_ob = ob; + *dt->r_ob = ob_eval; } if (dt->r_obmat) { copy_m4_m4(dt->r_obmat, obmat); @@ -1320,6 +1367,33 @@ typedef struct Nearest2dUserData { bool use_backface_culling; } Nearest2dUserData; +static void nearest2d_data_init(SnapObjectData *sod, + bool is_persp, + bool use_backface_culling, + Nearest2dUserData *r_nearest2d) +{ + if (sod->type == SNAP_MESH) { + r_nearest2d->userdata = &sod->treedata_mesh; + r_nearest2d->get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get; + r_nearest2d->get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get; + r_nearest2d->copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy; + r_nearest2d->get_tri_verts_index = (Nearest2DGetTriVertsCallback)cb_mlooptri_verts_get; + r_nearest2d->get_tri_edges_index = (Nearest2DGetTriEdgesCallback)cb_mlooptri_edges_get; + } + else { + BLI_assert(sod->type == SNAP_EDIT_MESH); + r_nearest2d->userdata = sod->treedata_editmesh.em; + r_nearest2d->get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get; + r_nearest2d->get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get; + r_nearest2d->copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy; + r_nearest2d->get_tri_verts_index = NULL; + r_nearest2d->get_tri_edges_index = NULL; + } + + r_nearest2d->is_persp = is_persp; + r_nearest2d->use_backface_culling = use_backface_culling; +} + static void cb_snap_vert(void *userdata, int index, const struct DistProjectedAABBPrecalc *precalc, @@ -1467,7 +1541,7 @@ static void cb_snap_tri_verts(void *userdata, static short snap_mesh_polygon(SnapObjectContext *sctx, SnapData *snapdata, - Object *ob, + Object *ob_eval, const float obmat[4][4], bool use_backface_culling, /* read/write args */ @@ -1492,28 +1566,21 @@ static short snap_mesh_polygon(SnapObjectContext *sctx, mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); } - Nearest2dUserData nearest2d = { - .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP, - .use_backface_culling = use_backface_culling, - }; - BVHTreeNearest nearest = { .index = -1, .dist_sq = square_f(*dist_px), }; - SnapObjectData *sod = snap_object_data_lookup(sctx, ob); - + SnapObjectData *sod = snap_object_data_lookup(sctx, ob_eval); BLI_assert(sod != NULL); + Nearest2dUserData nearest2d; + nearest2d_data_init( + sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d); + if (sod->type == SNAP_MESH) { BVHTreeFromMesh *treedata = &sod->treedata_mesh; - nearest2d.userdata = treedata; - nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get; - nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get; - nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy; - const MPoly *mp = &sod->poly[*r_index]; const MLoop *ml = &treedata->loop[mp->loopstart]; if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) { @@ -1544,11 +1611,6 @@ static short snap_mesh_polygon(SnapObjectContext *sctx, BLI_assert(sod->type == SNAP_EDIT_MESH); BMEditMesh *em = sod->treedata_editmesh.em; - nearest2d.userdata = em; - nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get; - nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get; - nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy; - BM_mesh_elem_table_ensure(em->bm, BM_FACE); BMFace *f = BM_face_at_index(em->bm, *r_index); BMLoop *l_iter, *l_first; @@ -1605,7 +1667,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx, static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, SnapData *snapdata, - Object *ob, + Object *ob_eval, const float obmat[4][4], float original_dist_px, const float prev_co[3], @@ -1619,32 +1681,16 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, { short elem = SCE_SNAP_MODE_EDGE; - if (ob->type != OB_MESH) { + if (ob_eval->type != OB_MESH) { return elem; } - SnapObjectData *sod = snap_object_data_lookup(sctx, ob); - + SnapObjectData *sod = snap_object_data_lookup(sctx, ob_eval); BLI_assert(sod != NULL); Nearest2dUserData nearest2d; - { - nearest2d.is_persp = snapdata->view_proj == VIEW_PROJ_PERSP; - nearest2d.use_backface_culling = use_backface_culling; - if (sod->type == SNAP_MESH) { - nearest2d.userdata = &sod->treedata_mesh; - nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get; - nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get; - nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy; - } - else { - BLI_assert(sod->type == SNAP_EDIT_MESH); - nearest2d.userdata = sod->treedata_editmesh.em; - nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get; - nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get; - nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy; - } - } + nearest2d_data_init( + sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d); int vindex[2]; nearest2d.get_edge_verts_index(*r_index, vindex, nearest2d.userdata); @@ -1769,9 +1815,8 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, } static short snapArmature(SnapData *snapdata, - Object *ob, + Object *ob_eval, const float obmat[4][4], - bool use_obedit, /* read/write args */ float *dist_px, /* return args */ @@ -1792,11 +1837,11 @@ static short snapArmature(SnapData *snapdata, dist_squared_to_projected_aabb_precalc( &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval); - use_obedit = use_obedit && BKE_object_is_in_editmode(ob); + bool use_obedit = ((bArmature *)ob_eval->data)->edbo != NULL; if (use_obedit == false) { /* Test BoundBox */ - BoundBox *bb = BKE_armature_boundbox_get(ob); + BoundBox *bb = BKE_armature_boundbox_get(ob_eval); if (bb && !snap_bound_box_check_dist( bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) { return retval; @@ -1811,7 +1856,7 @@ static short snapArmature(SnapData *snapdata, bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP; - bArmature *arm = ob->data; + bArmature *arm = ob_eval->data; if (arm->edbo) { LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) { if (eBone->layer & arm->layer) { @@ -1855,8 +1900,8 @@ static short snapArmature(SnapData *snapdata, } } } - else if (ob->pose && ob->pose->chanbase.first) { - LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { + else if (ob_eval->pose && ob_eval->pose->chanbase.first) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_eval->pose->chanbase) { Bone *bone = pchan->bone; /* skip hidden bones */ if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) { @@ -1914,7 +1959,7 @@ static short snapArmature(SnapData *snapdata, } static short snapCurve(SnapData *snapdata, - Object *ob, + Object *ob_eval, const float obmat[4][4], bool use_obedit, /* read/write args */ @@ -1931,7 +1976,7 @@ static short snapCurve(SnapData *snapdata, return 0; } - Curve *cu = ob->data; + Curve *cu = ob_eval->data; float dist_px_sq = square_f(*dist_px); float lpmat[4][4]; @@ -1941,11 +1986,11 @@ static short snapCurve(SnapData *snapdata, dist_squared_to_projected_aabb_precalc( &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval); - use_obedit = use_obedit && BKE_object_is_in_editmode(ob); + use_obedit = use_obedit && BKE_object_is_in_editmode(ob_eval); if (use_obedit == false) { /* Test BoundBox */ - BoundBox *bb = BKE_curve_boundbox_get(ob); + BoundBox *bb = BKE_curve_boundbox_get(ob_eval); if (bb && !snap_bound_box_check_dist( bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) { return 0; @@ -2065,7 +2110,7 @@ static short snapCurve(SnapData *snapdata, /* may extend later (for now just snaps to empty center) */ static short snap_object_center(SnapData *snapdata, - Object *ob, + Object *ob_eval, const float obmat[4][4], /* read/write args */ float *dist_px, @@ -2076,7 +2121,7 @@ static short snap_object_center(SnapData *snapdata, { short retval = 0; - if (ob->transflag & OB_DUPLI) { + if (ob_eval->transflag & OB_DUPLI) { return retval; } @@ -2219,9 +2264,10 @@ static short snapCamera(const SnapObjectContext *sctx, static short snapMesh(SnapObjectContext *sctx, SnapData *snapdata, - Object *ob, - Mesh *me, + Object *ob_eval, + Mesh *me_eval, const float obmat[4][4], + bool use_hide, bool use_backface_culling, /* read/write args */ float *dist_px, @@ -2231,16 +2277,11 @@ static short snapMesh(SnapObjectContext *sctx, int *r_index) { BLI_assert(snapdata->snap_to_flag != SCE_SNAP_MODE_FACE); - - if ((snapdata->snap_to_flag & ~SCE_SNAP_MODE_FACE) == SCE_SNAP_MODE_VERTEX) { - if (me->totvert == 0) { - return 0; - } + if (me_eval->totvert == 0) { + return 0; } - else { - if (me->totedge == 0) { - return 0; - } + if (me_eval->totedge == 0 && !(snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) { + return 0; } float lpmat[4][4]; @@ -2249,65 +2290,46 @@ static short snapMesh(SnapObjectContext *sctx, float dist_px_sq = square_f(*dist_px); /* Test BoundBox */ - BoundBox *bb = BKE_mesh_boundbox_get(ob); + BoundBox *bb = BKE_mesh_boundbox_get(ob_eval); if (bb && !snap_bound_box_check_dist( bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) { return 0; } - SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob); + SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide); - BVHTreeFromMesh *treedata, dummy_treedata; + BVHTreeFromMesh *treedata, treedata_tmp; treedata = &sod->treedata_mesh; - /* The tree is owned by the Mesh and may have been freed since we last used! */ - if (treedata->cached && treedata->tree && - !bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)) { - free_bvhtree_from_mesh(treedata); - } - if (sod->cached[0] && sod->bvhtree[0] && - !bvhcache_has_tree(me->runtime.bvh_cache, sod->bvhtree[0])) { - sod->bvhtree[0] = NULL; - } - if (sod->cached[1] && sod->bvhtree[1] && - !bvhcache_has_tree(me->runtime.bvh_cache, sod->bvhtree[1])) { - sod->bvhtree[1] = NULL; - } - - if (sod->has_looptris && treedata->tree == NULL) { - BKE_bvhtree_from_mesh_get(treedata, me, BVHTREE_FROM_LOOPTRI, 4); - sod->has_looptris = (treedata->tree != NULL); - if (sod->has_looptris) { - /* Make sure that the array of edges is referenced in the callbacks. */ - treedata->edge = me->medge; /* CustomData_get_layer(&me->edata, CD_MEDGE);? */ - } - } if (sod->has_loose_edge && sod->bvhtree[0] == NULL) { - sod->bvhtree[0] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEEDGES, 2); - sod->has_loose_edge = sod->bvhtree[0] != NULL; - sod->cached[0] = dummy_treedata.cached; - - if (sod->has_loose_edge) { - BLI_assert(treedata->vert_allocated == false); - treedata->vert = dummy_treedata.vert; - treedata->vert_allocated = dummy_treedata.vert_allocated; - - BLI_assert(treedata->edge_allocated == false); - treedata->edge = dummy_treedata.edge; - treedata->edge_allocated = dummy_treedata.edge_allocated; + sod->bvhtree[0] = BKE_bvhtree_from_mesh_get( + &treedata_tmp, me_eval, BVHTREE_FROM_LOOSEEDGES, 2); + if (sod->bvhtree[0] == NULL) { + sod->has_loose_edge = false; } + sod->cached[0] = treedata_tmp.cached; + BLI_assert(!ELEM(true, + treedata_tmp.vert_allocated, + treedata_tmp.edge_allocated, + treedata_tmp.face_allocated, + treedata_tmp.loop_allocated, + treedata_tmp.looptri_allocated)); } + if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) { if (sod->has_loose_vert && sod->bvhtree[1] == NULL) { - sod->bvhtree[1] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEVERTS, 2); - sod->has_loose_vert = sod->bvhtree[1] != NULL; - sod->cached[1] = dummy_treedata.cached; - - if (sod->has_loose_vert) { - BLI_assert(treedata->vert_allocated == false); - treedata->vert = dummy_treedata.vert; - treedata->vert_allocated = dummy_treedata.vert_allocated; + sod->bvhtree[1] = BKE_bvhtree_from_mesh_get( + &treedata_tmp, me_eval, BVHTREE_FROM_LOOSEVERTS, 2); + if (sod->bvhtree[1] == NULL) { + sod->has_loose_vert = false; } + sod->cached[1] = treedata_tmp.cached; + BLI_assert(!ELEM(true, + treedata_tmp.vert_allocated, + treedata_tmp.edge_allocated, + treedata_tmp.face_allocated, + treedata_tmp.loop_allocated, + treedata_tmp.looptri_allocated)); } } else { @@ -2315,33 +2337,9 @@ static short snapMesh(SnapObjectContext *sctx, sod->has_loose_vert = false; } - /* Update pointers. */ - if (treedata->vert_allocated == false) { - treedata->vert = me->mvert; /* CustomData_get_layer(&me->vdata, CD_MVERT);? */ - } - if (treedata->tree || sod->bvhtree[0]) { - if (treedata->edge_allocated == false) { - /* If raycast has been executed before, `treedata->edge` can be NULL. */ - treedata->edge = me->medge; /* CustomData_get_layer(&me->edata, CD_MEDGE);? */ - } - if (treedata->loop && treedata->loop_allocated == false) { - treedata->loop = me->mloop; /* CustomData_get_layer(&me->edata, CD_MLOOP);? */ - } - if (treedata->looptri && treedata->looptri_allocated == false) { - treedata->looptri = BKE_mesh_runtime_looptri_ensure(me); - } - } - - Nearest2dUserData nearest2d = { - .userdata = treedata, - .get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get, - .get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get, - .get_tri_verts_index = (Nearest2DGetTriVertsCallback)cb_mlooptri_verts_get, - .get_tri_edges_index = (Nearest2DGetTriEdgesCallback)cb_mlooptri_edges_get, - .copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy, - .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP, - .use_backface_culling = use_backface_culling, - }; + Nearest2dUserData nearest2d; + nearest2d_data_init( + sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d); BVHTreeNearest nearest = { .index = -1, @@ -2457,7 +2455,7 @@ static short snapMesh(SnapObjectContext *sctx, static short snapEditMesh(SnapObjectContext *sctx, SnapData *snapdata, - Object *ob, + Object *ob_eval, BMEditMesh *em, const float obmat[4][4], bool use_backface_culling, @@ -2486,7 +2484,7 @@ static short snapEditMesh(SnapObjectContext *sctx, float dist_px_sq = square_f(*dist_px); - SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob, em); + SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob_eval, em); /* Test BoundBox */ @@ -2560,14 +2558,9 @@ static short snapEditMesh(SnapObjectContext *sctx, } } - Nearest2dUserData nearest2d = { - .userdata = em, - .get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get, - .get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get, - .copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy, - .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP, - .use_backface_culling = use_backface_culling, - }; + Nearest2dUserData nearest2d; + nearest2d_data_init( + sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d); BVHTreeNearest nearest = { .index = -1, @@ -2661,9 +2654,9 @@ struct SnapObjUserData { * \note Duplicate args here are documented at #snapObjectsRay */ static void snap_obj_fn(SnapObjectContext *sctx, - Object *ob, + Object *ob_eval, float obmat[4][4], - bool use_obedit, + eSnapEditType edit_mode_type, bool use_backface_culling, bool UNUSED(is_object_active), void *data) @@ -2671,41 +2664,36 @@ static void snap_obj_fn(SnapObjectContext *sctx, struct SnapObjUserData *dt = data; short retval = 0; - switch (ob->type) { + switch (ob_eval->type) { case OB_MESH: { - Mesh *me = ob->data; - if (BKE_object_is_in_editmode(ob)) { - if (use_obedit || editmesh_eval_final_is_bmesh(me->edit_mesh)) { - /* Operators only update the editmesh looptris of the original mesh. */ - BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob)); - retval = snapEditMesh(sctx, - dt->snapdata, - ob, - em_orig, - obmat, - use_backface_culling, - dt->dist_px, - dt->r_loc, - dt->r_no, - dt->r_index); - break; - } - - BMEditMesh *em = BKE_editmesh_from_object(ob); - if (em->mesh_eval_final) { - me = em->mesh_eval_final; - } + bool use_hide; + Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide); + if (me_eval == NULL) { + /* Operators only update the editmesh looptris of the original mesh. */ + BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob_eval)); + retval = snapEditMesh(sctx, + dt->snapdata, + ob_eval, + em_orig, + obmat, + use_backface_culling, + dt->dist_px, + dt->r_loc, + dt->r_no, + dt->r_index); + break; } - else if (ob->dt == OB_BOUNDBOX) { + if (ob_eval->dt == OB_BOUNDBOX) { /* Do not snap to objects that are in bounding box display mode */ return; } retval = snapMesh(sctx, dt->snapdata, - ob, - me, + ob_eval, + me_eval, obmat, + use_hide, use_backface_culling, dt->dist_px, dt->r_loc, @@ -2715,21 +2703,28 @@ static void snap_obj_fn(SnapObjectContext *sctx, } case OB_ARMATURE: retval = snapArmature( - dt->snapdata, ob, obmat, use_obedit, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); + dt->snapdata, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); break; case OB_CURVE: - retval = snapCurve( - dt->snapdata, ob, obmat, use_obedit, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); + retval = snapCurve(dt->snapdata, + ob_eval, + obmat, + edit_mode_type == SNAP_GEOM_EDIT, + dt->dist_px, + dt->r_loc, + dt->r_no, + dt->r_index); break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */ case OB_SURF: case OB_FONT: { - Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); + Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval); if (mesh_eval) { retval |= snapMesh(sctx, dt->snapdata, - ob, + ob_eval, mesh_eval, obmat, + false, use_backface_culling, dt->dist_px, dt->r_loc, @@ -2742,17 +2737,17 @@ static void snap_obj_fn(SnapObjectContext *sctx, case OB_GPENCIL: case OB_LAMP: retval = snap_object_center( - dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); + dt->snapdata, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); break; case OB_CAMERA: retval = snapCamera( - sctx, dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); + sctx, dt->snapdata, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); break; } if (retval) { if (dt->r_ob) { - *dt->r_ob = ob; + *dt->r_ob = ob_eval; } if (dt->r_obmat) { copy_m4_m4(dt->r_obmat, obmat); @@ -3025,7 +3020,7 @@ static short transform_snap_context_project_view3d_mixed_impl( short retval = 0; bool has_hit = false; - Object *ob = NULL; + Object *ob_eval = NULL; float loc[3]; /* Not all snapping callbacks set the normal, * initialize this since any hit copies both the `loc` and `no`. */ @@ -3062,7 +3057,7 @@ static short transform_snap_context_project_view3d_mixed_impl( loc, no, &index, - &ob, + &ob_eval, obmat, NULL); @@ -3074,7 +3069,7 @@ static short transform_snap_context_project_view3d_mixed_impl( copy_v3_v3(r_no, no); } if (r_ob) { - *r_ob = ob; + *r_ob = ob_eval; } if (r_obmat) { copy_m4_m4(r_obmat, obmat); @@ -3110,9 +3105,10 @@ static short transform_snap_context_project_view3d_mixed_impl( snapdata.has_occlusion_plane = false; /* By convention we only snap to the original elements of a curve. */ - if (has_hit && ob->type != OB_CURVE) { + if (has_hit && ob_eval->type != OB_CURVE) { /* Compute the new clip_pane but do not add it yet. */ float new_clipplane[4]; + BLI_ASSERT_UNIT_V3(no); plane_from_point_normal_v3(new_clipplane, loc, no); if (dot_v3v3(snapdata.clip_plane[0], new_clipplane) > 0.0f) { /* The plane is facing the wrong direction. */ @@ -3123,8 +3119,15 @@ static short transform_snap_context_project_view3d_mixed_impl( new_clipplane[3] += 0.01f; /* Try to snap only to the polygon. */ - elem_test = snap_mesh_polygon( - sctx, &snapdata, ob, obmat, params->use_backface_culling, &dist_px_tmp, loc, no, &index); + elem_test = snap_mesh_polygon(sctx, + &snapdata, + ob_eval, + obmat, + params->use_backface_culling, + &dist_px_tmp, + loc, + no, + &index); if (elem_test) { elem = elem_test; } @@ -3139,7 +3142,7 @@ static short transform_snap_context_project_view3d_mixed_impl( } elem_test = snapObjectsRay( - sctx, depsgraph, &snapdata, params, &dist_px_tmp, loc, no, &index, &ob, obmat); + sctx, depsgraph, &snapdata, params, &dist_px_tmp, loc, no, &index, &ob_eval, obmat); if (elem_test) { elem = elem_test; } @@ -3150,7 +3153,7 @@ static short transform_snap_context_project_view3d_mixed_impl( snapdata.snap_to_flag = snap_to_flag; elem = snap_mesh_edge_verts_mixed(sctx, &snapdata, - ob, + ob_eval, obmat, *dist_px, prev_co, @@ -3169,7 +3172,7 @@ static short transform_snap_context_project_view3d_mixed_impl( copy_v3_v3(r_no, no); } if (r_ob) { - *r_ob = ob; + *r_ob = ob_eval; } if (r_obmat) { copy_m4_m4(r_obmat, obmat); |