diff options
Diffstat (limited to 'source/blender/editors/transform')
30 files changed, 1004 insertions, 911 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..f03defe26e2 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -88,12 +88,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 +104,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 +430,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 +596,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..b4175faacf4 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) { @@ -1742,7 +1732,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..11550ec8803 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 { diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index 7f24a0fa5f8..aaea9d05f84 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -1268,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 3ff83e00f43..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,7 +459,10 @@ void recalcData_curve(TransInfo *t) } } else { - /* Normal updating */ + /* 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..f715228e25e 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -48,7 +48,575 @@ #include "transform_convert.h" +/* -------------------------------------------------------------------- */ +/** \name Container TransCustomData 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; +}; + +static void tc_mesh_customdatacorrect_free_fn(struct TransInfo *UNUSED(t), + struct TransDataContainer *UNUSED(tc), + struct TransCustomData *custom_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; +} + #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(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_customdata_create(TransDataContainer *tc, const bool use_merge_group) +{ + struct TransCustomDataLayer *customdatacorrect; + customdatacorrect = tc_mesh_customdatacorrect_create(tc, use_merge_group); + + if (!customdatacorrect) { + return; + } + + BLI_assert(tc->custom.type.data == NULL); + tc->custom.type.data = customdatacorrect; + tc->custom.type.free_cb = tc_mesh_customdatacorrect_free_fn; +} + +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) { + tc_mesh_customdatacorrect_free_fn(t, tc, &tc->custom.type); + } + + tc_mesh_customdata_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) +{ + if (!tc->custom.type.data) { + return; + } + 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++) { + 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 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 Island Creation @@ -384,6 +952,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 +968,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 +995,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 +1009,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 +1026,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 +1309,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 +1351,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 +1541,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 +1614,39 @@ 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) -{ - 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; - } -} - -static BMFace *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 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)) { - 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 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; - } - } - 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); - } - - 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; - } - - 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); - } - } - - tc->custom.type.data = tcld; - tc->custom.type.free_cb = mesh_customdatacorrect_free_cb; -} - -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; - } - } - else { - return; - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - mesh_customdatacorrect_init_container(tc, use_merge_group); - } -} - -/** - * 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; -} - -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,24 +1655,28 @@ 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); @@ -1660,7 +1696,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_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_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index 30418471d6d..34be89e5ed9 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -491,7 +491,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 */ @@ -707,7 +707,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 c0c4b22da98..71c91221fbb 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -414,8 +414,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve int orient_type_set = -1; int orient_type_matrix_set = -1; - bool use_orient_axis = false; - if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT]; orient_type_scene = orient_slot->type; @@ -435,7 +433,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve 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"))) { @@ -457,28 +454,23 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve 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; } - - if ((t->flag & T_MODAL) && (use_orient_axis || transform_mode_is_changeable(t->mode)) && - (t->mode != TFM_ALIGN)) { - orient_type_default = V3D_ORIENT_VIEW; - } - else { - orient_type_default = orient_type_scene; - } } BLI_assert(!ELEM(-1, orient_type_default, orient_type_set)); @@ -487,9 +479,9 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve orient_type_set = V3D_ORIENT_CUSTOM_MATRIX; } - orient_types[0] = (short)orient_type_default; - orient_types[1] = (short)orient_type_scene; - orient_types[2] = (short)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. */ @@ -506,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); } @@ -538,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_mode.c b/source/blender/editors/transform/transform_mode.c index d14f693da9c..d61e7bb867c 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. */ @@ -1263,7 +1264,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 +1272,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..106dc68c9ee 100644 --- a/source/blender/editors/transform/transform_mode.h +++ b/source/blender/editors/transform/transform_mode.h @@ -61,6 +61,7 @@ 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..b7b3de69731 100644 --- a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c +++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c @@ -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_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..857ee37f0ad 100644 --- a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c +++ b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c @@ -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..0d7d0be3c0e 100644 --- a/source/blender/editors/transform/transform_mode_resize.c +++ b/source/blender/editors/transform/transform_mode_resize.c @@ -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..0fdbfb25989 100644 --- a/source/blender/editors/transform/transform_mode_rotate.c +++ b/source/blender/editors/transform/transform_mode_rotate.c @@ -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_skin_resize.c b/source/blender/editors/transform/transform_mode_skin_resize.c index 8beacb844b9..77e57484bef 100644 --- a/source/blender/editors/transform/transform_mode_skin_resize.c +++ b/source/blender/editors/transform/transform_mode_skin_resize.c @@ -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_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 41fc6ee0aaf..175b7b52a1a 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -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_orientations.c b/source/blender/editors/transform/transform_orientations.c index 5a5f478fc2b..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); @@ -671,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); |