diff options
Diffstat (limited to 'source/blender/editors/transform/transform.c')
-rw-r--r-- | source/blender/editors/transform/transform.c | 6824 |
1 files changed, 45 insertions, 6779 deletions
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 24efa33bdfa..e00af488f46 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -22,73 +22,41 @@ */ #include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <math.h> -#include <float.h> #include "MEM_guardedalloc.h" -#include "DNA_anim_types.h" #include "DNA_armature_types.h" -#include "DNA_constraint_types.h" +#include "DNA_gpencil_types.h" #include "DNA_mask_types.h" #include "DNA_mesh_types.h" -#include "DNA_movieclip_types.h" -#include "DNA_scene_types.h" /* PET modes */ -#include "DNA_workspace_types.h" -#include "DNA_gpencil_types.h" -#include "BLI_alloca.h" -#include "BLI_utildefines.h" #include "BLI_math.h" #include "BLI_rect.h" -#include "BLI_listbase.h" -#include "BLI_string.h" -#include "BLI_ghash.h" -#include "BLI_utildefines_stack.h" -#include "BLI_memarena.h" -#include "BKE_nla.h" #include "BKE_editmesh.h" -#include "BKE_editmesh_bvh.h" #include "BKE_context.h" -#include "BKE_constraint.h" -#include "BKE_particle.h" -#include "BKE_unit.h" -#include "BKE_scene.h" #include "BKE_mask.h" -#include "BKE_mesh.h" -#include "BKE_report.h" -#include "BKE_workspace.h" - -#include "DEG_depsgraph.h" +#include "BKE_scene.h" -#include "GPU_immediate.h" -#include "GPU_matrix.h" #include "GPU_state.h" +#include "ED_clip.h" +#include "ED_gpencil.h" #include "ED_image.h" #include "ED_keyframing.h" #include "ED_screen.h" +#include "ED_sculpt.h" #include "ED_space_api.h" -#include "ED_view3d.h" -#include "ED_mesh.h" -#include "ED_clip.h" #include "ED_node.h" -#include "ED_gpencil.h" -#include "ED_sculpt.h" -#include "WM_types.h" #include "WM_api.h" +#include "WM_types.h" -#include "UI_view2d.h" -#include "UI_interface.h" #include "UI_interface_icons.h" #include "UI_resources.h" +#include "UI_view2d.h" #include "RNA_access.h" -#include "RNA_define.h" #include "BLF_api.h" #include "BLT_translation.h" @@ -96,6 +64,7 @@ #include "transform.h" #include "transform_convert.h" #include "transform_draw_cursors.h" +#include "transform_mode.h" #include "transform_snap.h" /* Disabling, since when you type you know what you are doing, @@ -103,128 +72,11 @@ // #define USE_NUM_NO_ZERO static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg); -static void doEdgeSlide(TransInfo *t, float perc); -static void doVertSlide(TransInfo *t, float perc); - -static void drawEdgeSlide(TransInfo *t); -static void drawVertSlide(TransInfo *t); -static void postInputRotation(TransInfo *t, float values[3]); -static void ElementRotation( - TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around); static void initSnapSpatial(TransInfo *t, float r_snap[3]); static void storeCustomLNorValue(TransDataContainer *t, BMesh *bm); -/* Transform Callbacks */ -static void initBend(TransInfo *t); -static eRedrawFlag handleEventBend(TransInfo *t, const struct wmEvent *event); -static void Bend(TransInfo *t, const int mval[2]); - -static void initShear(TransInfo *t); -static eRedrawFlag handleEventShear(TransInfo *t, const struct wmEvent *event); -static void applyShear(TransInfo *t, const int mval[2]); - -static void initResize(TransInfo *t); -static void applyResize(TransInfo *t, const int mval[2]); - -static void initSkinResize(TransInfo *t); -static void applySkinResize(TransInfo *t, const int mval[2]); - -static void initTranslation(TransInfo *t); -static void applyTranslation(TransInfo *t, const int mval[2]); - -static void initToSphere(TransInfo *t); -static void applyToSphere(TransInfo *t, const int mval[2]); - -static void initRotation(TransInfo *t); -static void applyRotation(TransInfo *t, const int mval[2]); - -static void initNormalRotation(TransInfo *t); -static void applyNormalRotation(TransInfo *t, const int mval[2]); - -static void initShrinkFatten(TransInfo *t); -static void applyShrinkFatten(TransInfo *t, const int mval[2]); - -static void initTilt(TransInfo *t); -static void applyTilt(TransInfo *t, const int mval[2]); - -static void initCurveShrinkFatten(TransInfo *t); -static void applyCurveShrinkFatten(TransInfo *t, const int mval[2]); - -static void initMaskShrinkFatten(TransInfo *t); -static void applyMaskShrinkFatten(TransInfo *t, const int mval[2]); - -static void initGPShrinkFatten(TransInfo *t); -static void applyGPShrinkFatten(TransInfo *t, const int mval[2]); - -static void initTrackball(TransInfo *t); -static void applyTrackball(TransInfo *t, const int mval[2]); - -static void initPushPull(TransInfo *t); -static void applyPushPull(TransInfo *t, const int mval[2]); - -static void initBevelWeight(TransInfo *t); -static void applyBevelWeight(TransInfo *t, const int mval[2]); - -static void initCrease(TransInfo *t); -static void applyCrease(TransInfo *t, const int mval[2]); - -static void initBoneSize(TransInfo *t); -static void applyBoneSize(TransInfo *t, const int mval[2]); - -static void initBoneEnvelope(TransInfo *t); -static void applyBoneEnvelope(TransInfo *t, const int mval[2]); - -static void initBoneRoll(TransInfo *t); -static void applyBoneRoll(TransInfo *t, const int mval[2]); - -static void initEdgeSlide_ex( - TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp); -static void initEdgeSlide(TransInfo *t); -static eRedrawFlag handleEventEdgeSlide(TransInfo *t, const struct wmEvent *event); -static void applyEdgeSlide(TransInfo *t, const int mval[2]); - -static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp); -static void initVertSlide(TransInfo *t); -static eRedrawFlag handleEventVertSlide(TransInfo *t, const struct wmEvent *event); -static void applyVertSlide(TransInfo *t, const int mval[2]); - -static void initTimeTranslate(TransInfo *t); -static void applyTimeTranslate(TransInfo *t, const int mval[2]); - -static void initTimeSlide(TransInfo *t); -static void applyTimeSlide(TransInfo *t, const int mval[2]); - -static void initTimeScale(TransInfo *t); -static void applyTimeScale(TransInfo *t, const int mval[2]); - -static void initBakeTime(TransInfo *t); -static void applyBakeTime(TransInfo *t, const int mval[2]); - -static void initMirror(TransInfo *t); -static void applyMirror(TransInfo *t, const int mval[2]); - -static void initAlign(TransInfo *t); -static void applyAlign(TransInfo *t, const int mval[2]); - -static void initSeqSlide(TransInfo *t); -static void applySeqSlide(TransInfo *t, const int mval[2]); - -static void initGPOpacity(TransInfo *t); -static void applyGPOpacity(TransInfo *t, const int mval[2]); -/* end transform callbacks */ - -static bool transdata_check_local_center(TransInfo *t, short around) -{ - return ((around == V3D_AROUND_LOCAL_ORIGINS) && - ((t->flag & (T_OBJECT | T_POSE)) || - /* implicit: (t->flag & T_EDIT) */ - (ELEM(t->obedit_type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE, OB_GPENCIL)) || - (t->spacetype == SPACE_GRAPH) || - (t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE)))); -} - bool transdata_check_local_islands(TransInfo *t, short around) { return ((around == V3D_AROUND_LOCAL_ORIGINS) && ((ELEM(t->obedit_type, OB_MESH)))); @@ -797,42 +649,6 @@ static void view_editmove(unsigned short UNUSED(event)) /* ************************************************* */ -/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ -enum { - TFM_MODAL_CANCEL = 1, - TFM_MODAL_CONFIRM = 2, - TFM_MODAL_TRANSLATE = 3, - TFM_MODAL_ROTATE = 4, - TFM_MODAL_RESIZE = 5, - TFM_MODAL_SNAP_INV_ON = 6, - TFM_MODAL_SNAP_INV_OFF = 7, - TFM_MODAL_SNAP_TOGGLE = 8, - TFM_MODAL_AXIS_X = 9, - TFM_MODAL_AXIS_Y = 10, - TFM_MODAL_AXIS_Z = 11, - TFM_MODAL_PLANE_X = 12, - TFM_MODAL_PLANE_Y = 13, - TFM_MODAL_PLANE_Z = 14, - TFM_MODAL_CONS_OFF = 15, - TFM_MODAL_ADD_SNAP = 16, - TFM_MODAL_REMOVE_SNAP = 17, - - /* 18 and 19 used by numinput, defined in transform.h */ - - TFM_MODAL_PROPSIZE_UP = 20, - TFM_MODAL_PROPSIZE_DOWN = 21, - TFM_MODAL_AUTOIK_LEN_INC = 22, - TFM_MODAL_AUTOIK_LEN_DEC = 23, - - TFM_MODAL_EDGESLIDE_UP = 24, - TFM_MODAL_EDGESLIDE_DOWN = 25, - - /* for analog input, like trackpad */ - TFM_MODAL_PROPSIZE = 26, - /* node editor insert offset (aka auto-offset) direction toggle */ - TFM_MODAL_INSERTOFS_TOGGLE_DIR = 27, -}; - static bool transform_modal_item_poll(const wmOperator *op, int value) { const TransInfo *t = op->customdata; @@ -2031,6 +1847,43 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } } +static void initSnapSpatial(TransInfo *t, float r_snap[3]) +{ + if (t->spacetype == SPACE_VIEW3D) { + RegionView3D *rv3d = t->ar->regiondata; + + if (rv3d) { + View3D *v3d = t->sa->spacedata.first; + r_snap[0] = 0.0f; + r_snap[1] = ED_view3d_grid_view_scale(t->scene, v3d, rv3d, NULL) * 1.0f; + r_snap[2] = r_snap[1] * 0.1f; + } + } + else if (t->spacetype == SPACE_IMAGE) { + r_snap[0] = 0.0f; + r_snap[1] = 0.0625f; + r_snap[2] = 0.03125f; + } + else if (t->spacetype == SPACE_CLIP) { + r_snap[0] = 0.0f; + r_snap[1] = 0.125f; + r_snap[2] = 0.0625f; + } + else if (t->spacetype == SPACE_NODE) { + r_snap[0] = 0.0f; + r_snap[1] = r_snap[2] = ED_node_grid_size(); + } + else if (t->spacetype == SPACE_GRAPH) { + r_snap[0] = 0.0f; + r_snap[1] = 1.0; + r_snap[2] = 0.1f; + } + else { + r_snap[0] = 0.0f; + r_snap[1] = r_snap[2] = 1.0f; + } +} + /** * \note caller needs to free 't' on a 0 return * \warning \a event might be NULL (when tweaking from redo panel) @@ -2575,6593 +2428,6 @@ int transformEnd(bContext *C, TransInfo *t) return exit_code; } -/* ************************** TRANSFORM LOCKS **************************** */ - -static void protectedTransBits(short protectflag, float vec[3]) -{ - if (protectflag & OB_LOCK_LOCX) { - vec[0] = 0.0f; - } - if (protectflag & OB_LOCK_LOCY) { - vec[1] = 0.0f; - } - if (protectflag & OB_LOCK_LOCZ) { - vec[2] = 0.0f; - } -} - -static void protectedSizeBits(short protectflag, float size[3]) -{ - if (protectflag & OB_LOCK_SCALEX) { - size[0] = 1.0f; - } - if (protectflag & OB_LOCK_SCALEY) { - size[1] = 1.0f; - } - if (protectflag & OB_LOCK_SCALEZ) { - size[2] = 1.0f; - } -} - -static void protectedRotateBits(short protectflag, float eul[3], const float oldeul[3]) -{ - if (protectflag & OB_LOCK_ROTX) { - eul[0] = oldeul[0]; - } - if (protectflag & OB_LOCK_ROTY) { - eul[1] = oldeul[1]; - } - if (protectflag & OB_LOCK_ROTZ) { - eul[2] = oldeul[2]; - } -} - -/* this function only does the delta rotation */ -/* axis-angle is usually internally stored as quats... */ -static void protectedAxisAngleBits( - short protectflag, float axis[3], float *angle, float oldAxis[3], float oldAngle) -{ - /* check that protection flags are set */ - if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0) { - return; - } - - if (protectflag & OB_LOCK_ROT4D) { - /* axis-angle getting limited as 4D entities that they are... */ - if (protectflag & OB_LOCK_ROTW) { - *angle = oldAngle; - } - if (protectflag & OB_LOCK_ROTX) { - axis[0] = oldAxis[0]; - } - if (protectflag & OB_LOCK_ROTY) { - axis[1] = oldAxis[1]; - } - if (protectflag & OB_LOCK_ROTZ) { - axis[2] = oldAxis[2]; - } - } - else { - /* axis-angle get limited with euler... */ - float eul[3], oldeul[3]; - - axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, axis, *angle); - axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, oldAxis, oldAngle); - - if (protectflag & OB_LOCK_ROTX) { - eul[0] = oldeul[0]; - } - if (protectflag & OB_LOCK_ROTY) { - eul[1] = oldeul[1]; - } - if (protectflag & OB_LOCK_ROTZ) { - eul[2] = oldeul[2]; - } - - eulO_to_axis_angle(axis, angle, eul, EULER_ORDER_DEFAULT); - - /* When converting to axis-angle, - * we need a special exception for the case when there is no axis. */ - if (IS_EQF(axis[0], axis[1]) && IS_EQF(axis[1], axis[2])) { - /* for now, rotate around y-axis then (so that it simply becomes the roll) */ - axis[1] = 1.0f; - } - } -} - -/* this function only does the delta rotation */ -static void protectedQuaternionBits(short protectflag, float quat[4], const float oldquat[4]) -{ - /* check that protection flags are set */ - if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0) { - return; - } - - if (protectflag & OB_LOCK_ROT4D) { - /* quaternions getting limited as 4D entities that they are... */ - if (protectflag & OB_LOCK_ROTW) { - quat[0] = oldquat[0]; - } - if (protectflag & OB_LOCK_ROTX) { - quat[1] = oldquat[1]; - } - if (protectflag & OB_LOCK_ROTY) { - quat[2] = oldquat[2]; - } - if (protectflag & OB_LOCK_ROTZ) { - quat[3] = oldquat[3]; - } - } - else { - /* quaternions get limited with euler... (compatibility mode) */ - float eul[3], oldeul[3], nquat[4], noldquat[4]; - float qlen; - - qlen = normalize_qt_qt(nquat, quat); - normalize_qt_qt(noldquat, oldquat); - - quat_to_eul(eul, nquat); - quat_to_eul(oldeul, noldquat); - - if (protectflag & OB_LOCK_ROTX) { - eul[0] = oldeul[0]; - } - if (protectflag & OB_LOCK_ROTY) { - eul[1] = oldeul[1]; - } - if (protectflag & OB_LOCK_ROTZ) { - eul[2] = oldeul[2]; - } - - eul_to_quat(quat, eul); - - /* restore original quat size */ - mul_qt_fl(quat, qlen); - - /* quaternions flip w sign to accumulate rotations correctly */ - if ((nquat[0] < 0.0f && quat[0] > 0.0f) || (nquat[0] > 0.0f && quat[0] < 0.0f)) { - mul_qt_fl(quat, -1.0f); - } - } -} - -/* ******************* TRANSFORM LIMITS ********************** */ - -static void constraintTransLim(TransInfo *t, TransData *td) -{ - if (td->con) { - const bConstraintTypeInfo *ctiLoc = BKE_constraint_typeinfo_from_type( - CONSTRAINT_TYPE_LOCLIMIT); - const bConstraintTypeInfo *ctiDist = BKE_constraint_typeinfo_from_type( - CONSTRAINT_TYPE_DISTLIMIT); - - bConstraintOb cob = {NULL}; - bConstraint *con; - float ctime = (float)(t->scene->r.cfra); - - /* Make a temporary bConstraintOb for using these limit constraints - * - they only care that cob->matrix is correctly set ;-) - * - current space should be local - */ - unit_m4(cob.matrix); - copy_v3_v3(cob.matrix[3], td->loc); - - /* Evaluate valid constraints */ - for (con = td->con; con; con = con->next) { - const bConstraintTypeInfo *cti = NULL; - ListBase targets = {NULL, NULL}; - - /* only consider constraint if enabled */ - if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) { - continue; - } - if (con->enforce == 0.0f) { - continue; - } - - /* only use it if it's tagged for this purpose (and the right type) */ - if (con->type == CONSTRAINT_TYPE_LOCLIMIT) { - bLocLimitConstraint *data = con->data; - - if ((data->flag2 & LIMIT_TRANSFORM) == 0) { - continue; - } - cti = ctiLoc; - } - else if (con->type == CONSTRAINT_TYPE_DISTLIMIT) { - bDistLimitConstraint *data = con->data; - - if ((data->flag & LIMITDIST_TRANSFORM) == 0) { - continue; - } - cti = ctiDist; - } - - if (cti) { - /* do space conversions */ - if (con->ownspace == CONSTRAINT_SPACE_WORLD) { - /* just multiply by td->mtx (this should be ok) */ - mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix); - } - else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) { - /* skip... incompatible spacetype */ - continue; - } - - /* get constraint targets if needed */ - BKE_constraint_targets_for_solving_get(t->depsgraph, con, &cob, &targets, ctime); - - /* do constraint */ - cti->evaluate_constraint(con, &cob, &targets); - - /* convert spaces again */ - if (con->ownspace == CONSTRAINT_SPACE_WORLD) { - /* just multiply by td->smtx (this should be ok) */ - mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix); - } - - /* free targets list */ - BLI_freelistN(&targets); - } - } - - /* copy results from cob->matrix */ - copy_v3_v3(td->loc, cob.matrix[3]); - } -} - -static void constraintob_from_transdata(bConstraintOb *cob, TransData *td) -{ - /* Make a temporary bConstraintOb for use by limit constraints - * - they only care that cob->matrix is correctly set ;-) - * - current space should be local - */ - memset(cob, 0, sizeof(bConstraintOb)); - if (td->ext) { - if (td->ext->rotOrder == ROT_MODE_QUAT) { - /* quats */ - /* objects and bones do normalization first too, otherwise - * we don't necessarily end up with a rotation matrix, and - * then conversion back to quat gives a different result */ - float quat[4]; - normalize_qt_qt(quat, td->ext->quat); - quat_to_mat4(cob->matrix, quat); - } - else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) { - /* axis angle */ - axis_angle_to_mat4(cob->matrix, td->ext->rotAxis, *td->ext->rotAngle); - } - else { - /* eulers */ - eulO_to_mat4(cob->matrix, td->ext->rot, td->ext->rotOrder); - } - } -} - -static void constraintRotLim(TransInfo *UNUSED(t), TransData *td) -{ - if (td->con) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_ROTLIMIT); - bConstraintOb cob; - bConstraint *con; - bool do_limit = false; - - /* Evaluate valid constraints */ - for (con = td->con; con; con = con->next) { - /* only consider constraint if enabled */ - if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) { - continue; - } - if (con->enforce == 0.0f) { - continue; - } - - /* we're only interested in Limit-Rotation constraints */ - if (con->type == CONSTRAINT_TYPE_ROTLIMIT) { - bRotLimitConstraint *data = con->data; - - /* only use it if it's tagged for this purpose */ - if ((data->flag2 & LIMIT_TRANSFORM) == 0) { - continue; - } - - /* skip incompatible spacetypes */ - if (!ELEM(con->ownspace, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) { - continue; - } - - /* only do conversion if necessary, to preserve quats and eulers */ - if (do_limit == false) { - constraintob_from_transdata(&cob, td); - do_limit = true; - } - - /* do space conversions */ - if (con->ownspace == CONSTRAINT_SPACE_WORLD) { - /* just multiply by td->mtx (this should be ok) */ - mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix); - } - - /* do constraint */ - cti->evaluate_constraint(con, &cob, NULL); - - /* convert spaces again */ - if (con->ownspace == CONSTRAINT_SPACE_WORLD) { - /* just multiply by td->smtx (this should be ok) */ - mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix); - } - } - } - - if (do_limit) { - /* copy results from cob->matrix */ - if (td->ext->rotOrder == ROT_MODE_QUAT) { - /* quats */ - mat4_to_quat(td->ext->quat, cob.matrix); - } - else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) { - /* axis angle */ - mat4_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, cob.matrix); - } - else { - /* eulers */ - mat4_to_eulO(td->ext->rot, td->ext->rotOrder, cob.matrix); - } - } - } -} - -static void constraintSizeLim(TransInfo *t, TransData *td) -{ - if (td->con && td->ext) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_SIZELIMIT); - bConstraintOb cob = {NULL}; - bConstraint *con; - float size_sign[3], size_abs[3]; - int i; - - /* Make a temporary bConstraintOb for using these limit constraints - * - they only care that cob->matrix is correctly set ;-) - * - current space should be local - */ - if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) { - /* scale val and reset size */ - return; // TODO: fix this case - } - else { - /* Reset val if SINGLESIZE but using a constraint */ - if (td->flag & TD_SINGLESIZE) { - return; - } - - /* separate out sign to apply back later */ - for (i = 0; i < 3; i++) { - size_sign[i] = signf(td->ext->size[i]); - size_abs[i] = fabsf(td->ext->size[i]); - } - - size_to_mat4(cob.matrix, size_abs); - } - - /* Evaluate valid constraints */ - for (con = td->con; con; con = con->next) { - /* only consider constraint if enabled */ - if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) { - continue; - } - if (con->enforce == 0.0f) { - continue; - } - - /* we're only interested in Limit-Scale constraints */ - if (con->type == CONSTRAINT_TYPE_SIZELIMIT) { - bSizeLimitConstraint *data = con->data; - - /* only use it if it's tagged for this purpose */ - if ((data->flag2 & LIMIT_TRANSFORM) == 0) { - continue; - } - - /* do space conversions */ - if (con->ownspace == CONSTRAINT_SPACE_WORLD) { - /* just multiply by td->mtx (this should be ok) */ - mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix); - } - else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) { - /* skip... incompatible spacetype */ - continue; - } - - /* do constraint */ - cti->evaluate_constraint(con, &cob, NULL); - - /* convert spaces again */ - if (con->ownspace == CONSTRAINT_SPACE_WORLD) { - /* just multiply by td->smtx (this should be ok) */ - mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix); - } - } - } - - /* copy results from cob->matrix */ - if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) { - /* scale val and reset size */ - return; // TODO: fix this case - } - else { - /* Reset val if SINGLESIZE but using a constraint */ - if (td->flag & TD_SINGLESIZE) { - return; - } - - /* extrace scale from matrix and apply back sign */ - mat4_to_size(td->ext->size, cob.matrix); - mul_v3_v3(td->ext->size, size_sign); - } - } -} - -/* -------------------------------------------------------------------- */ -/* Transform (Bend) */ - -/** \name Transform Bend - * \{ */ - -struct BendCustomData { - /* All values are in global space. */ - float warp_sta[3]; - float warp_end[3]; - - float warp_nor[3]; - float warp_tan[3]; - - /* for applying the mouse distance */ - float warp_init_dist; -}; - -static void initBend(TransInfo *t) -{ - const float mval_fl[2] = {UNPACK2(t->mval)}; - const float *curs; - float tvec[3]; - struct BendCustomData *data; - - t->mode = TFM_BEND; - t->transform = Bend; - t->handleEvent = handleEventBend; - - setInputPostFct(&t->mouse, postInputRotation); - initMouseInputMode(t, &t->mouse, INPUT_ANGLE_SPRING); - - t->idx_max = 1; - t->num.idx_max = 1; - t->snap[0] = 0.0f; - t->snap[1] = SNAP_INCREMENTAL_ANGLE; - t->snap[2] = t->snap[1] * 0.2; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); - t->num.unit_type[0] = B_UNIT_ROTATION; - t->num.unit_type[1] = B_UNIT_LENGTH; - - t->flag |= T_NO_CONSTRAINT; - - // copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view)); - if ((t->flag & T_OVERRIDE_CENTER) == 0) { - calculateCenterCursor(t, t->center_global); - } - calculateCenterLocal(t, t->center_global); - - t->val = 0.0f; - - data = MEM_callocN(sizeof(*data), __func__); - - curs = t->scene->cursor.location; - copy_v3_v3(data->warp_sta, curs); - ED_view3d_win_to_3d(t->sa->spacedata.first, t->ar, curs, mval_fl, data->warp_end); - - copy_v3_v3(data->warp_nor, t->viewinv[2]); - normalize_v3(data->warp_nor); - - /* tangent */ - sub_v3_v3v3(tvec, data->warp_end, data->warp_sta); - cross_v3_v3v3(data->warp_tan, tvec, data->warp_nor); - normalize_v3(data->warp_tan); - - data->warp_init_dist = len_v3v3(data->warp_end, data->warp_sta); - - t->custom.mode.data = data; - t->custom.mode.use_free = true; -} - -static eRedrawFlag handleEventBend(TransInfo *UNUSED(t), const wmEvent *event) -{ - eRedrawFlag status = TREDRAW_NOTHING; - - if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) { - status = TREDRAW_HARD; - } - - return status; -} - -static void Bend(TransInfo *t, const int UNUSED(mval[2])) -{ - float vec[3]; - float pivot_global[3]; - float warp_end_radius_global[3]; - int i; - char str[UI_MAX_DRAW_STR]; - const struct BendCustomData *data = t->custom.mode.data; - const bool is_clamp = (t->flag & T_ALT_TRANSFORM) == 0; - - union { - struct { - float angle, scale; - }; - float vector[2]; - } values; - - /* amount of radians for bend */ - copy_v2_v2(values.vector, t->values); - -#if 0 - snapGrid(t, angle_rad); -#else - /* hrmf, snapping radius is using 'angle' steps, need to convert to something else - * this isnt essential but nicer to give reasonable snapping values for radius */ - if (t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) { - const float radius_snap = 0.1f; - const float snap_hack = (t->snap[1] * data->warp_init_dist) / radius_snap; - values.scale *= snap_hack; - snapGridIncrement(t, values.vector); - values.scale /= snap_hack; - } -#endif - - if (applyNumInput(&t->num, values.vector)) { - values.scale = values.scale / data->warp_init_dist; - } - - copy_v2_v2(t->values_final, values.vector); - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN * 2]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - BLI_snprintf(str, - sizeof(str), - TIP_("Bend Angle: %s Radius: %s Alt, Clamp %s"), - &c[0], - &c[NUM_STR_REP_LEN], - WM_bool_as_string(is_clamp)); - } - else { - /* default header print */ - BLI_snprintf(str, - sizeof(str), - TIP_("Bend Angle: %.3f Radius: %.4f, Alt, Clamp %s"), - RAD2DEGF(values.angle), - values.scale * data->warp_init_dist, - WM_bool_as_string(is_clamp)); - } - - values.angle *= -1.0f; - values.scale *= data->warp_init_dist; - - /* calc 'data->warp_end' from 'data->warp_end_init' */ - copy_v3_v3(warp_end_radius_global, data->warp_end); - dist_ensure_v3_v3fl(warp_end_radius_global, data->warp_sta, values.scale); - /* done */ - - /* calculate pivot */ - copy_v3_v3(pivot_global, data->warp_sta); - if (values.angle > 0.0f) { - madd_v3_v3fl(pivot_global, - data->warp_tan, - -values.scale * shell_angle_to_dist((float)M_PI_2 - values.angle)); - } - else { - madd_v3_v3fl(pivot_global, - data->warp_tan, - +values.scale * shell_angle_to_dist((float)M_PI_2 + values.angle)); - } - - /* TODO(campbell): xform, compensate object center. */ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - - float warp_sta_local[3]; - float warp_end_local[3]; - float warp_end_radius_local[3]; - float pivot_local[3]; - - if (tc->use_local_mat) { - sub_v3_v3v3(warp_sta_local, data->warp_sta, tc->mat[3]); - sub_v3_v3v3(warp_end_local, data->warp_end, tc->mat[3]); - sub_v3_v3v3(warp_end_radius_local, warp_end_radius_global, tc->mat[3]); - sub_v3_v3v3(pivot_local, pivot_global, tc->mat[3]); - } - else { - copy_v3_v3(warp_sta_local, data->warp_sta); - copy_v3_v3(warp_end_local, data->warp_end); - copy_v3_v3(warp_end_radius_local, warp_end_radius_global); - copy_v3_v3(pivot_local, pivot_global); - } - - for (i = 0; i < tc->data_len; i++, td++) { - float mat[3][3]; - float delta[3]; - float fac, fac_scaled; - - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (UNLIKELY(values.angle == 0.0f)) { - copy_v3_v3(td->loc, td->iloc); - continue; - } - - copy_v3_v3(vec, td->iloc); - mul_m3_v3(td->mtx, vec); - - fac = line_point_factor_v3(vec, warp_sta_local, warp_end_radius_local); - if (is_clamp) { - CLAMP(fac, 0.0f, 1.0f); - } - - if (t->options & CTX_GPENCIL_STROKES) { - /* grease pencil multiframe falloff */ - bGPDstroke *gps = (bGPDstroke *)td->extra; - if (gps != NULL) { - fac_scaled = fac * td->factor * gps->runtime.multi_frame_falloff; - } - else { - fac_scaled = fac * td->factor; - } - } - else { - fac_scaled = fac * td->factor; - } - - axis_angle_normalized_to_mat3(mat, data->warp_nor, values.angle * fac_scaled); - interp_v3_v3v3(delta, warp_sta_local, warp_end_radius_local, fac_scaled); - sub_v3_v3(delta, warp_sta_local); - - /* delta is subtracted, rotation adds back this offset */ - sub_v3_v3(vec, delta); - - sub_v3_v3(vec, pivot_local); - mul_m3_v3(mat, vec); - add_v3_v3(vec, pivot_local); - - mul_m3_v3(td->smtx, vec); - - /* rotation */ - if ((t->flag & T_POINTS) == 0) { - ElementRotation(t, tc, td, mat, V3D_AROUND_LOCAL_ORIGINS); - } - - /* location */ - copy_v3_v3(td->loc, vec); - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Shear) */ - -/** \name Transform Shear - * \{ */ - -static void initShear_mouseInputMode(TransInfo *t) -{ - float dir[3]; - bool dir_flip = false; - copy_v3_v3(dir, t->orient_matrix[t->orient_axis_ortho]); - - /* Needed for axis aligned view gizmo. */ - if (t->orientation.user == V3D_ORIENT_VIEW) { - if (t->orient_axis_ortho == 0) { - if (t->center2d[1] > t->mouse.imval[1]) { - dir_flip = !dir_flip; - } - } - else if (t->orient_axis_ortho == 1) { - if (t->center2d[0] > t->mouse.imval[0]) { - dir_flip = !dir_flip; - } - } - } - - /* Without this, half the gizmo handles move in the opposite direction. */ - if ((t->orient_axis_ortho + 1) % 3 != t->orient_axis) { - dir_flip = !dir_flip; - } - - if (dir_flip) { - negate_v3(dir); - } - - mul_mat3_m4_v3(t->viewmat, dir); - if (normalize_v2(dir) == 0.0f) { - dir[0] = 1.0f; - } - setCustomPointsFromDirection(t, &t->mouse, dir); - - initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO); -} - -static void initShear(TransInfo *t) -{ - t->mode = TFM_SHEAR; - t->transform = applyShear; - t->handleEvent = handleEventShear; - - if (t->orient_axis == t->orient_axis_ortho) { - t->orient_axis = 2; - t->orient_axis_ortho = 1; - } - - initShear_mouseInputMode(t); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; /* Don't think we have any unit here? */ - - t->flag |= T_NO_CONSTRAINT; -} - -static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event) -{ - eRedrawFlag status = TREDRAW_NOTHING; - - if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) { - /* Use custom.mode.data pointer to signal Shear direction */ - do { - t->orient_axis_ortho = (t->orient_axis_ortho + 1) % 3; - } while (t->orient_axis_ortho == t->orient_axis); - - initShear_mouseInputMode(t); - - status = TREDRAW_HARD; - } - else if (event->type == XKEY && event->val == KM_PRESS) { - t->orient_axis_ortho = (t->orient_axis + 1) % 3; - initShear_mouseInputMode(t); - - status = TREDRAW_HARD; - } - else if (event->type == YKEY && event->val == KM_PRESS) { - t->orient_axis_ortho = (t->orient_axis + 2) % 3; - initShear_mouseInputMode(t); - - status = TREDRAW_HARD; - } - - return status; -} - -static void applyShear(TransInfo *t, const int UNUSED(mval[2])) -{ - float vec[3]; - float smat[3][3], tmat[3][3], totmat[3][3], axismat[3][3], axismat_inv[3][3]; - float value; - int i; - char str[UI_MAX_DRAW_STR]; - const bool is_local_center = transdata_check_local_center(t, t->around); - - value = t->values[0]; - - snapGridIncrement(t, &value); - - applyNumInput(&t->num, &value); - - t->values_final[0] = value; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - BLI_snprintf(str, sizeof(str), TIP_("Shear: %s %s"), c, t->proptext); - } - else { - /* default header print */ - BLI_snprintf(str, - sizeof(str), - TIP_("Shear: %.3f %s (Press X or Y to set shear axis)"), - value, - t->proptext); - } - - unit_m3(smat); - smat[1][0] = value; - - copy_v3_v3(axismat_inv[0], t->orient_matrix[t->orient_axis_ortho]); - copy_v3_v3(axismat_inv[2], t->orient_matrix[t->orient_axis]); - cross_v3_v3v3(axismat_inv[1], axismat_inv[0], axismat_inv[2]); - invert_m3_m3(axismat, axismat_inv); - - mul_m3_series(totmat, axismat_inv, smat, axismat); - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - const float *center, *co; - - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (t->flag & T_EDIT) { - mul_m3_series(tmat, td->smtx, totmat, td->mtx); - } - else { - copy_m3_m3(tmat, totmat); - } - - if (is_local_center) { - center = td->center; - co = td->loc; - } - else { - center = tc->center_local; - co = td->center; - } - - sub_v3_v3v3(vec, co, center); - - mul_m3_v3(tmat, vec); - - add_v3_v3(vec, center); - sub_v3_v3(vec, co); - - if (t->options & CTX_GPENCIL_STROKES) { - /* grease pencil multiframe falloff */ - bGPDstroke *gps = (bGPDstroke *)td->extra; - if (gps != NULL) { - mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff); - } - else { - mul_v3_fl(vec, td->factor); - } - } - else { - mul_v3_fl(vec, td->factor); - } - - add_v3_v3v3(td->loc, td->iloc, vec); - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Resize) */ - -/** \name Transform Resize - * \{ */ - -static void initResize(TransInfo *t) -{ - t->mode = TFM_RESIZE; - t->transform = applyResize; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP); - - t->flag |= T_NULL_ONE; - t->num.val_flag[0] |= NUM_NULL_ONE; - t->num.val_flag[1] |= NUM_NULL_ONE; - 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; - t->num.val_flag[2] |= NUM_NO_ZERO; -#endif - } - - t->idx_max = 2; - t->num.idx_max = 2; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - t->num.unit_type[1] = B_UNIT_NONE; - t->num.unit_type[2] = B_UNIT_NONE; -} - -static void headerResize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR]) -{ - char tvec[NUM_STR_REP_LEN * 3]; - size_t ofs = 0; - if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, &t->scene->unit); - } - else { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]); - BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", vec[1]); - BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", vec[2]); - } - - 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); - 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); - 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); - 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); - } - 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); - } - } - - if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf( - str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); - } -} - -/** - * \a smat is reference matrix only. - * - * \note this is a tricky area, before making changes see: T29633, T42444 - */ -static void TransMat3ToSize(float mat[3][3], float smat[3][3], float size[3]) -{ - float rmat[3][3]; - - mat3_to_rot_size(rmat, size, mat); - - /* first tried with dotproduct... but the sign flip is crucial */ - if (dot_v3v3(rmat[0], smat[0]) < 0.0f) { - size[0] = -size[0]; - } - if (dot_v3v3(rmat[1], smat[1]) < 0.0f) { - size[1] = -size[1]; - } - if (dot_v3v3(rmat[2], smat[2]) < 0.0f) { - size[2] = -size[2]; - } -} - -static void ElementResize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3]) -{ - float tmat[3][3], smat[3][3], center[3]; - float vec[3]; - - if (t->flag & T_EDIT) { - mul_m3_m3m3(smat, mat, td->mtx); - mul_m3_m3m3(tmat, td->smtx, smat); - } - else { - copy_m3_m3(tmat, mat); - } - - if (t->con.applySize) { - t->con.applySize(t, tc, td, tmat); - } - - /* local constraint shouldn't alter center */ - if (transdata_check_local_center(t, t->around)) { - copy_v3_v3(center, td->center); - } - else if (t->options & CTX_MOVIECLIP) { - if (td->flag & TD_INDIVIDUAL_SCALE) { - copy_v3_v3(center, td->center); - } - else { - copy_v3_v3(center, tc->center_local); - } - } - else { - copy_v3_v3(center, tc->center_local); - } - - /* Size checked needed since the 3D cursor only uses rotation fields. */ - if (td->ext && td->ext->size) { - float fsize[3]; - - if ((t->options & CTX_SCULPT) || t->flag & (T_OBJECT | T_TEXTURE | T_POSE)) { - float obsizemat[3][3]; - /* Reorient the size mat to fit the oriented object. */ - mul_m3_m3m3(obsizemat, tmat, td->axismtx); - /* print_m3("obsizemat", obsizemat); */ - TransMat3ToSize(obsizemat, td->axismtx, fsize); - /* print_v3("fsize", fsize); */ - } - else { - mat3_to_size(fsize, tmat); - } - - protectedSizeBits(td->protectflag, fsize); - - if ((t->flag & T_V3D_ALIGN) == 0) { /* align mode doesn't resize objects itself */ - if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) { - /* scale val and reset size */ - *td->val = td->ival * (1 + (fsize[0] - 1) * td->factor); - - td->ext->size[0] = td->ext->isize[0]; - td->ext->size[1] = td->ext->isize[1]; - td->ext->size[2] = td->ext->isize[2]; - } - else { - /* Reset val if SINGLESIZE but using a constraint */ - if (td->flag & TD_SINGLESIZE) { - *td->val = td->ival; - } - - td->ext->size[0] = td->ext->isize[0] * (1 + (fsize[0] - 1) * td->factor); - td->ext->size[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor); - td->ext->size[2] = td->ext->isize[2] * (1 + (fsize[2] - 1) * td->factor); - } - } - - constraintSizeLim(t, td); - } - - /* For individual element center, Editmode need to use iloc */ - if (t->flag & T_POINTS) { - sub_v3_v3v3(vec, td->iloc, center); - } - else { - sub_v3_v3v3(vec, td->center, center); - } - - mul_m3_v3(tmat, vec); - - add_v3_v3(vec, center); - if (t->flag & T_POINTS) { - sub_v3_v3(vec, td->iloc); - } - else { - sub_v3_v3(vec, td->center); - } - - /* grease pencil falloff */ - if (t->options & CTX_GPENCIL_STROKES) { - bGPDstroke *gps = (bGPDstroke *)td->extra; - mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff); - - /* scale stroke thickness */ - if (td->val) { - snapGridIncrement(t, t->values_final); - applyNumInput(&t->num, t->values_final); - - float ratio = t->values_final[0]; - *td->val = td->ival * ratio * gps->runtime.multi_frame_falloff; - CLAMP_MIN(*td->val, 0.001f); - } - } - else { - mul_v3_fl(vec, td->factor); - } - - if (t->flag & (T_OBJECT | T_POSE)) { - mul_m3_v3(td->smtx, vec); - } - - protectedTransBits(td->protectflag, vec); - if (td->loc) { - add_v3_v3v3(td->loc, td->iloc, vec); - } - - constraintTransLim(t, td); -} - -static void applyResize(TransInfo *t, const int UNUSED(mval[2])) -{ - float mat[3][3]; - int i; - char str[UI_MAX_DRAW_STR]; - - if (t->flag & T_INPUT_IS_VALUES_FINAL) { - copy_v3_v3(t->values_final, t->values); - } - else { - float ratio = t->values[0]; - - copy_v3_fl(t->values_final, ratio); - - snapGridIncrement(t, t->values_final); - - if (applyNumInput(&t->num, t->values_final)) { - constraintNumInput(t, t->values_final); - } - - applySnapping(t, t->values_final); - } - - size_to_mat3(mat, t->values_final); - if (t->con.mode & CON_APPLY) { - t->con.applySize(t, NULL, NULL, mat); - - /* Only so we have re-usable value with redo. */ - float pvec[3] = {0.0f, 0.0f, 0.0f}; - int j = 0; - for (i = 0; i < 3; i++) { - if (!(t->con.mode & (CON_AXIS0 << i))) { - t->values_final[i] = 1.0f; - } - else { - pvec[j++] = t->values_final[i]; - } - } - headerResize(t, pvec, str); - } - else { - headerResize(t, t->values_final, str); - } - - copy_m3_m3(t->mat, mat); // used in gizmo - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - ElementResize(t, tc, td, mat); - } - } - - /* evil hack - redo resize if cliping needed */ - if (t->flag & T_CLIP_UV && clipUVTransform(t, t->values_final, 1)) { - size_to_mat3(mat, t->values_final); - - if (t->con.mode & CON_APPLY) { - t->con.applySize(t, NULL, NULL, mat); - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - ElementResize(t, tc, td, mat); - } - - /* In proportional edit it can happen that */ - /* vertices in the radius of the brush end */ - /* outside the clipping area */ - /* XXX HACK - dg */ - if (t->flag & T_PROP_EDIT_ALL) { - clipUVData(t); - } - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Skin) */ - -/** \name Transform Skin - * \{ */ - -static void initSkinResize(TransInfo *t) -{ - t->mode = TFM_SKIN_RESIZE; - t->transform = applySkinResize; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP); - - t->flag |= T_NULL_ONE; - t->num.val_flag[0] |= NUM_NULL_ONE; - t->num.val_flag[1] |= NUM_NULL_ONE; - 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; - t->num.val_flag[2] |= NUM_NO_ZERO; -#endif - } - - t->idx_max = 2; - t->num.idx_max = 2; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - t->num.unit_type[1] = B_UNIT_NONE; - t->num.unit_type[2] = B_UNIT_NONE; -} - -static void applySkinResize(TransInfo *t, const int UNUSED(mval[2])) -{ - float mat[3][3]; - int i; - char str[UI_MAX_DRAW_STR]; - - if (t->flag & T_INPUT_IS_VALUES_FINAL) { - copy_v3_v3(t->values_final, t->values); - } - else { - copy_v3_fl(t->values_final, t->values[0]); - - snapGridIncrement(t, t->values_final); - - if (applyNumInput(&t->num, t->values_final)) { - constraintNumInput(t, t->values_final); - } - - applySnapping(t, t->values_final); - } - - size_to_mat3(mat, t->values_final); - - headerResize(t, t->values_final, str); - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - float tmat[3][3], smat[3][3]; - float fsize[3]; - - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (t->flag & T_EDIT) { - mul_m3_m3m3(smat, mat, td->mtx); - mul_m3_m3m3(tmat, td->smtx, smat); - } - else { - copy_m3_m3(tmat, mat); - } - - if (t->con.applySize) { - t->con.applySize(t, NULL, NULL, tmat); - } - - mat3_to_size(fsize, tmat); - td->val[0] = td->ext->isize[0] * (1 + (fsize[0] - 1) * td->factor); - td->val[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor); - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (ToSphere) */ - -/** \name Transform ToSphere - * \{ */ - -static void initToSphere(TransInfo *t) -{ - int i; - - t->mode = TFM_TOSPHERE; - t->transform = applyToSphere; - - initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - - t->num.val_flag[0] |= NUM_NULL_ONE | NUM_NO_NEGATIVE; - t->flag |= T_NO_CONSTRAINT; - - // Calculate average radius - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - t->val += len_v3v3(tc->center_local, td->iloc); - } - } - - t->val /= (float)t->data_len_all; -} - -static void applyToSphere(TransInfo *t, const int UNUSED(mval[2])) -{ - float vec[3]; - float ratio, radius; - int i; - char str[UI_MAX_DRAW_STR]; - - ratio = t->values[0]; - - snapGridIncrement(t, &ratio); - - applyNumInput(&t->num, &ratio); - - CLAMP(ratio, 0.0f, 1.0f); - - t->values_final[0] = ratio; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - BLI_snprintf(str, sizeof(str), TIP_("To Sphere: %s %s"), c, t->proptext); - } - else { - /* default header print */ - BLI_snprintf(str, sizeof(str), TIP_("To Sphere: %.4f %s"), ratio, t->proptext); - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - float tratio; - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - sub_v3_v3v3(vec, td->iloc, tc->center_local); - - radius = normalize_v3(vec); - - tratio = ratio * td->factor; - - mul_v3_fl(vec, radius * (1.0f - tratio) + t->val * tratio); - - add_v3_v3v3(td->loc, tc->center_local, vec); - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Rotation) */ - -/** \name Transform Rotation - * \{ */ - -static void postInputRotation(TransInfo *t, float values[3]) -{ - float axis_final[3]; - copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]); - if ((t->con.mode & CON_APPLY) && t->con.applyRot) { - t->con.applyRot(t, NULL, NULL, axis_final, values); - } -} - -static void initRotation(TransInfo *t) -{ - t->mode = TFM_ROTATION; - t->transform = applyRotation; - - setInputPostFct(&t->mouse, postInputRotation); - initMouseInputMode(t, &t->mouse, INPUT_ANGLE); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = DEG2RAD(5.0); - t->snap[2] = DEG2RAD(1.0); - - copy_v3_fl(t->num.val_inc, t->snap[2]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); - t->num.unit_type[0] = B_UNIT_ROTATION; - - if (t->flag & T_2D_EDIT) { - t->flag |= T_NO_CONSTRAINT; - } -} - -/* Used by Transform Rotation and Transform Normal Rotation */ -static void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final) -{ - size_t ofs = 0; - - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - ofs += BLI_snprintf( - str + ofs, UI_MAX_DRAW_STR - ofs, TIP_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext); - } - else { - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - TIP_("Rot: %.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); - } -} - -/** - * Applies values of rotation to `td->loc` and `td->ext->quat` - * based on a rotation matrix (mat) and a pivot (center). - * - * Protected axis and other transform settings are taken into account. - */ -static void ElementRotation_ex(TransInfo *t, - TransDataContainer *tc, - TransData *td, - const float mat[3][3], - const float *center) -{ - float vec[3], totmat[3][3], smat[3][3]; - float eul[3], fmat[3][3], quat[4]; - - if (t->flag & T_POINTS) { - mul_m3_m3m3(totmat, mat, td->mtx); - mul_m3_m3m3(smat, td->smtx, totmat); - - /* apply gpencil falloff */ - if (t->options & CTX_GPENCIL_STROKES) { - bGPDstroke *gps = (bGPDstroke *)td->extra; - float sx = smat[0][0]; - float sy = smat[1][1]; - float sz = smat[2][2]; - - mul_m3_fl(smat, gps->runtime.multi_frame_falloff); - /* fix scale */ - smat[0][0] = sx; - smat[1][1] = sy; - smat[2][2] = sz; - } - - sub_v3_v3v3(vec, td->iloc, center); - mul_m3_v3(smat, vec); - - add_v3_v3v3(td->loc, vec, center); - - sub_v3_v3v3(vec, td->loc, td->iloc); - protectedTransBits(td->protectflag, vec); - add_v3_v3v3(td->loc, td->iloc, vec); - - if (td->flag & TD_USEQUAT) { - mul_m3_series(fmat, td->smtx, mat, td->mtx); - mat3_to_quat(quat, fmat); // Actual transform - - if (td->ext->quat) { - mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat); - - /* is there a reason not to have this here? -jahka */ - protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat); - } - } - } - /** - * HACK WARNING - * - * This is some VERY ugly special case to deal with pose mode. - * - * The problem is that mtx and smtx include each bone orientation. - * - * That is needed to rotate each bone properly, HOWEVER, to calculate - * the translation component, we only need the actual armature object's - * matrix (and inverse). That is not all though. Once the proper translation - * has been computed, it has to be converted back into the bone's space. - */ - else if (t->flag & T_POSE) { - // Extract and invert armature object matrix - - if ((td->flag & TD_NO_LOC) == 0) { - sub_v3_v3v3(vec, td->center, center); - - mul_m3_v3(tc->mat3, vec); // To Global space - mul_m3_v3(mat, vec); // Applying rotation - mul_m3_v3(tc->imat3, vec); // To Local space - - add_v3_v3(vec, center); - /* vec now is the location where the object has to be */ - - sub_v3_v3v3(vec, vec, td->center); // Translation needed from the initial location - - /* special exception, see TD_PBONE_LOCAL_MTX definition comments */ - if (td->flag & TD_PBONE_LOCAL_MTX_P) { - /* do nothing */ - } - else if (td->flag & TD_PBONE_LOCAL_MTX_C) { - mul_m3_v3(tc->mat3, vec); // To Global space - mul_m3_v3(td->ext->l_smtx, vec); // To Pose space (Local Location) - } - else { - mul_m3_v3(tc->mat3, vec); // To Global space - mul_m3_v3(td->smtx, vec); // To Pose space - } - - protectedTransBits(td->protectflag, vec); - - add_v3_v3v3(td->loc, td->iloc, vec); - - constraintTransLim(t, td); - } - - /* rotation */ - /* MORE HACK: as in some cases the matrix to apply location and rot/scale is not the same, - * and ElementRotation() might be called in Translation context (with align snapping), - * we need to be sure to actually use the *rotation* matrix here... - * So no other way than storing it in some dedicated members of td->ext! */ - if ((t->flag & T_V3D_ALIGN) == 0) { /* align mode doesn't rotate objects itself */ - /* euler or quaternion/axis-angle? */ - if (td->ext->rotOrder == ROT_MODE_QUAT) { - mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx); - - mat3_to_quat(quat, fmat); /* Actual transform */ - - mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat); - /* this function works on end result */ - protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat); - } - else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) { - /* calculate effect based on quats */ - float iquat[4], tquat[4]; - - axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle); - - mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx); - mat3_to_quat(quat, fmat); /* Actual transform */ - mul_qt_qtqt(tquat, quat, iquat); - - quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat); - - /* this function works on end result */ - protectedAxisAngleBits(td->protectflag, - td->ext->rotAxis, - td->ext->rotAngle, - td->ext->irotAxis, - td->ext->irotAngle); - } - else { - float eulmat[3][3]; - - mul_m3_m3m3(totmat, mat, td->ext->r_mtx); - mul_m3_m3m3(smat, td->ext->r_smtx, totmat); - - /* calculate the total rotatation in eulers */ - copy_v3_v3(eul, td->ext->irot); - eulO_to_mat3(eulmat, eul, td->ext->rotOrder); - - /* mat = transform, obmat = bone rotation */ - mul_m3_m3m3(fmat, smat, eulmat); - - mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat); - - /* and apply (to end result only) */ - protectedRotateBits(td->protectflag, eul, td->ext->irot); - copy_v3_v3(td->ext->rot, eul); - } - - constraintRotLim(t, td); - } - } - else { - if ((td->flag & TD_NO_LOC) == 0) { - /* translation */ - sub_v3_v3v3(vec, td->center, center); - mul_m3_v3(mat, vec); - add_v3_v3(vec, center); - /* vec now is the location where the object has to be */ - sub_v3_v3(vec, td->center); - mul_m3_v3(td->smtx, vec); - - protectedTransBits(td->protectflag, vec); - - add_v3_v3v3(td->loc, td->iloc, vec); - } - - constraintTransLim(t, td); - - /* rotation */ - if ((t->flag & T_V3D_ALIGN) == 0) { // align mode doesn't rotate objects itself - /* euler or quaternion? */ - if ((td->ext->rotOrder == ROT_MODE_QUAT) || (td->flag & TD_USEQUAT)) { - /* can be called for texture space translate for example, then opt out */ - if (td->ext->quat) { - mul_m3_series(fmat, td->smtx, mat, td->mtx); - mat3_to_quat(quat, fmat); // Actual transform - - mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat); - /* this function works on end result */ - protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat); - } - } - else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) { - /* calculate effect based on quats */ - float iquat[4], tquat[4]; - - axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle); - - mul_m3_series(fmat, td->smtx, mat, td->mtx); - mat3_to_quat(quat, fmat); // Actual transform - mul_qt_qtqt(tquat, quat, iquat); - - quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat); - - /* this function works on end result */ - protectedAxisAngleBits(td->protectflag, - td->ext->rotAxis, - td->ext->rotAngle, - td->ext->irotAxis, - td->ext->irotAngle); - } - else { - float obmat[3][3]; - - mul_m3_m3m3(totmat, mat, td->mtx); - mul_m3_m3m3(smat, td->smtx, totmat); - - /* calculate the total rotatation in eulers */ - add_v3_v3v3(eul, td->ext->irot, td->ext->drot); /* correct for delta rot */ - eulO_to_mat3(obmat, eul, td->ext->rotOrder); - /* mat = transform, obmat = object rotation */ - mul_m3_m3m3(fmat, smat, obmat); - - mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat); - - /* correct back for delta rot */ - sub_v3_v3v3(eul, eul, td->ext->drot); - - /* and apply */ - protectedRotateBits(td->protectflag, eul, td->ext->irot); - copy_v3_v3(td->ext->rot, eul); - } - - constraintRotLim(t, td); - } - } -} - -static void ElementRotation( - TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around) -{ - const float *center; - - /* local constraint shouldn't alter center */ - if (transdata_check_local_center(t, around)) { - center = td->center; - } - else { - center = tc->center_local; - } - - ElementRotation_ex(t, tc, td, mat, center); -} - -static float large_rotation_limit(float angle) -{ - /* Limit rotation to 1001 turns max - * (otherwise iterative handling of 'large' rotations would become too slow). */ - const float angle_max = (float)(M_PI * 2000.0); - if (fabsf(angle) > angle_max) { - const float angle_sign = angle < 0.0f ? -1.0f : 1.0f; - angle = angle_sign * (fmodf(fabsf(angle), (float)(M_PI * 2.0)) + angle_max); - } - return angle; -} - -static void applyRotationValue(TransInfo *t, - float angle, - float axis[3], - const bool is_large_rotation) -{ - float mat[3][3]; - int i; - - const float angle_sign = angle < 0.0f ? -1.0f : 1.0f; - /* We cannot use something too close to 180°, or 'continuous' rotation may fail - * due to computing error... */ - const float angle_step = angle_sign * (float)(0.9 * M_PI); - - if (is_large_rotation) { - /* Just in case, calling code should have already done that in practice - * (for UI feedback reasons). */ - angle = large_rotation_limit(angle); - } - - axis_angle_normalized_to_mat3(mat, axis, angle); - /* Counter for needed updates (when we need to update to non-default matrix, - * we also need another update on next iteration to go back to default matrix, - * hence the '2' value used here, instead of a mere boolean). */ - short do_update_matrix = 0; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - float angle_final = angle; - if (t->con.applyRot) { - t->con.applyRot(t, tc, td, axis, NULL); - angle_final = angle * td->factor; - /* Even though final angle might be identical to orig value, - * we have to update the rotation matrix in that case... */ - do_update_matrix = 2; - } - else if (t->flag & T_PROP_EDIT) { - angle_final = angle * td->factor; - } - - /* Rotation is very likely to be above 180°, we need to do rotation by steps. - * Note that this is only needed when doing 'absolute' rotation - * (i.e. from initial rotation again, typically when using numinput). - * regular incremental rotation (from mouse/widget/...) will be called often enough, - * hence steps are small enough to be properly handled without that complicated trick. - * Note that we can only do that kind of stepped rotation if we have initial rotation values - * (and access to some actual rotation value storage). - * Otherwise, just assume it's useless (e.g. in case of mesh/UV/etc. editing). - * Also need to be in Euler rotation mode, the others never allow more than one turn anyway. - */ - if (is_large_rotation && td->ext != NULL && td->ext->rotOrder == ROT_MODE_EUL) { - copy_v3_v3(td->ext->rot, td->ext->irot); - for (float angle_progress = angle_step; fabsf(angle_progress) < fabsf(angle_final); - angle_progress += angle_step) { - axis_angle_normalized_to_mat3(mat, axis, angle_progress); - ElementRotation(t, tc, td, mat, t->around); - } - do_update_matrix = 2; - } - else if (angle_final != angle) { - do_update_matrix = 2; - } - - if (do_update_matrix > 0) { - axis_angle_normalized_to_mat3(mat, axis, angle_final); - do_update_matrix--; - } - - ElementRotation(t, tc, td, mat, t->around); - } - } -} - -static void applyRotation(TransInfo *t, const int UNUSED(mval[2])) -{ - char str[UI_MAX_DRAW_STR]; - - float final; - - final = t->values[0]; - - snapGridIncrement(t, &final); - - float axis_final[3]; - copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]); - - if ((t->con.mode & CON_APPLY) && t->con.applyRot) { - t->con.applyRot(t, NULL, NULL, axis_final, NULL); - } - - applySnapping(t, &final); - - if (applyNumInput(&t->num, &final)) { - /* We have to limit the amount of turns to a reasonable number here, - * to avoid things getting *very* slow, see how applyRotationValue() handles those... */ - final = large_rotation_limit(final); - } - - t->values_final[0] = final; - - headerRotation(t, str, final); - - const bool is_large_rotation = hasNumInput(&t->num); - applyRotationValue(t, final, axis_final, is_large_rotation); - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Rotation - Trackball) */ - -/** \name Transform Rotation - Trackball - * \{ */ - -static void initTrackball(TransInfo *t) -{ - t->mode = TFM_TRACKBALL; - t->transform = applyTrackball; - - initMouseInputMode(t, &t->mouse, INPUT_TRACKBALL); - - t->idx_max = 1; - t->num.idx_max = 1; - t->snap[0] = 0.0f; - t->snap[1] = DEG2RAD(5.0); - t->snap[2] = DEG2RAD(1.0); - - copy_v3_fl(t->num.val_inc, t->snap[2]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); - t->num.unit_type[0] = B_UNIT_ROTATION; - t->num.unit_type[1] = B_UNIT_ROTATION; - - t->flag |= T_NO_CONSTRAINT; -} - -static void applyTrackballValue(TransInfo *t, - const float axis1[3], - const float axis2[3], - const float angles[2]) -{ - float mat[3][3]; - float axis[3]; - float angle; - int i; - - mul_v3_v3fl(axis, axis1, angles[0]); - madd_v3_v3fl(axis, axis2, angles[1]); - angle = normalize_v3(axis); - axis_angle_normalized_to_mat3(mat, axis, angle); - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (t->flag & T_PROP_EDIT) { - axis_angle_normalized_to_mat3(mat, axis, td->factor * angle); - } - - ElementRotation(t, tc, td, mat, t->around); - } - } -} - -static void applyTrackball(TransInfo *t, const int UNUSED(mval[2])) -{ - char str[UI_MAX_DRAW_STR]; - size_t ofs = 0; - float axis1[3], axis2[3]; -#if 0 /* UNUSED */ - float mat[3][3], totmat[3][3], smat[3][3]; -#endif - float phi[2]; - - copy_v3_v3(axis1, t->persinv[0]); - copy_v3_v3(axis2, t->persinv[1]); - normalize_v3(axis1); - normalize_v3(axis2); - - copy_v2_v2(phi, t->values); - - snapGridIncrement(t, phi); - - applyNumInput(&t->num, phi); - - copy_v2_v2(t->values_final, phi); - - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN * 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); - } - else { - ofs += BLI_snprintf(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( - str + ofs, sizeof(str) - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); - } - -#if 0 /* UNUSED */ - axis_angle_normalized_to_mat3(smat, axis1, phi[0]); - axis_angle_normalized_to_mat3(totmat, axis2, phi[1]); - - mul_m3_m3m3(mat, smat, totmat); - - // TRANSFORM_FIX_ME - //copy_m3_m3(t->mat, mat); // used in gizmo -#endif - - applyTrackballValue(t, axis1, axis2, phi); - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Normal Rotation) */ - -/** \name Transform Normal Rotation - * \{ */ - -static void storeCustomLNorValue(TransDataContainer *tc, BMesh *bm) -{ - BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false); - // BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; - - tc->custom.mode.data = lnors_ed_arr; - tc->custom.mode.free_cb = freeCustomNormalArray; -} - -void freeCustomNormalArray(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data) -{ - BMLoopNorEditDataArray *lnors_ed_arr = custom_data->data; - - if (t->state == TRANS_CANCEL) { - BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; - BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); - BMesh *bm = em->bm; - - /* Restore custom loop normal on cancel */ - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - BKE_lnor_space_custom_normal_to_data( - bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->niloc, lnor_ed->clnors_data); - } - } - - BM_loop_normal_editdata_array_free(lnors_ed_arr); - - tc->custom.mode.data = NULL; - tc->custom.mode.free_cb = NULL; -} - -static void initNormalRotation(TransInfo *t) -{ - t->mode = TFM_NORMAL_ROTATION; - t->transform = applyNormalRotation; - - setInputPostFct(&t->mouse, postInputRotation); - initMouseInputMode(t, &t->mouse, INPUT_ANGLE); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = DEG2RAD(5.0); - t->snap[2] = DEG2RAD(1.0); - - copy_v3_fl(t->num.val_inc, t->snap[2]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); - t->num.unit_type[0] = B_UNIT_ROTATION; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); - BMesh *bm = em->bm; - - BKE_editmesh_ensure_autosmooth(em, tc->obedit->data); - BKE_editmesh_lnorspace_update(em, tc->obedit->data); - - storeCustomLNorValue(tc, bm); - } -} - -/* Works by getting custom normal from clnor_data, transform, then store */ -static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2])) -{ - char str[UI_MAX_DRAW_STR]; - - float axis_final[3]; - copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]); - - if ((t->con.mode & CON_APPLY) && t->con.applyRot) { - t->con.applyRot(t, NULL, NULL, axis_final, NULL); - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); - BMesh *bm = em->bm; - - BMLoopNorEditDataArray *lnors_ed_arr = tc->custom.mode.data; - BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; - - float axis[3]; - float mat[3][3]; - float angle = t->values[0]; - copy_v3_v3(axis, axis_final); - - snapGridIncrement(t, &angle); - - applySnapping(t, &angle); - - applyNumInput(&t->num, &angle); - - headerRotation(t, str, angle); - - axis_angle_normalized_to_mat3(mat, axis, angle); - - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - mul_v3_m3v3(lnor_ed->nloc, mat, lnor_ed->niloc); - - BKE_lnor_space_custom_normal_to_data( - bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data); - } - - t->values_final[0] = angle; - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Translation) */ - -static void initSnapSpatial(TransInfo *t, float r_snap[3]) -{ - if (t->spacetype == SPACE_VIEW3D) { - RegionView3D *rv3d = t->ar->regiondata; - - if (rv3d) { - View3D *v3d = t->sa->spacedata.first; - r_snap[0] = 0.0f; - r_snap[1] = ED_view3d_grid_view_scale(t->scene, v3d, rv3d, NULL) * 1.0f; - r_snap[2] = r_snap[1] * 0.1f; - } - } - else if (t->spacetype == SPACE_IMAGE) { - r_snap[0] = 0.0f; - r_snap[1] = 0.0625f; - r_snap[2] = 0.03125f; - } - else if (t->spacetype == SPACE_CLIP) { - r_snap[0] = 0.0f; - r_snap[1] = 0.125f; - r_snap[2] = 0.0625f; - } - else if (t->spacetype == SPACE_NODE) { - r_snap[0] = 0.0f; - r_snap[1] = r_snap[2] = ED_node_grid_size(); - } - else if (t->spacetype == SPACE_GRAPH) { - r_snap[0] = 0.0f; - r_snap[1] = 1.0; - r_snap[2] = 0.1f; - } - else { - r_snap[0] = 0.0f; - r_snap[1] = r_snap[2] = 1.0f; - } -} - -/** \name Transform Translation - * \{ */ - -static void initTranslation(TransInfo *t) -{ - if (t->spacetype == SPACE_ACTION) { - /* this space uses time translate */ - BKE_report(t->reports, - RPT_ERROR, - "Use 'Time_Translate' transform mode instead of 'Translation' mode " - "for translating keyframes in Dope Sheet Editor"); - t->state = TRANS_CANCEL; - } - - t->mode = TFM_TRANSLATION; - t->transform = applyTranslation; - - initMouseInputMode(t, &t->mouse, INPUT_VECTOR); - - t->idx_max = (t->flag & T_2D_EDIT) ? 1 : 2; - t->num.flag = 0; - t->num.idx_max = t->idx_max; - - copy_v3_v3(t->snap, t->snap_spatial); - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - if (t->spacetype == SPACE_VIEW3D) { - /* Handling units makes only sense in 3Dview... See T38877. */ - t->num.unit_type[0] = B_UNIT_LENGTH; - t->num.unit_type[1] = B_UNIT_LENGTH; - t->num.unit_type[2] = B_UNIT_LENGTH; - } - else { - /* SPACE_GRAPH, SPACE_ACTION, etc. could use some time units, when we have them... */ - t->num.unit_type[0] = B_UNIT_NONE; - t->num.unit_type[1] = B_UNIT_NONE; - t->num.unit_type[2] = B_UNIT_NONE; - } -} - -static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR]) -{ - size_t ofs = 0; - char tvec[NUM_STR_REP_LEN * 3]; - char distvec[NUM_STR_REP_LEN]; - char autoik[NUM_STR_REP_LEN]; - float dist; - - if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, &t->scene->unit); - dist = len_v3(t->num.val); - } - else { - float dvec[3]; - - copy_v3_v3(dvec, vec); - applyAspectRatio(t, dvec); - - dist = len_v3(vec); - if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) { - int i; - - for (i = 0; i < 3; i++) { - bUnit_AsString2(&tvec[NUM_STR_REP_LEN * i], - NUM_STR_REP_LEN, - dvec[i] * t->scene->unit.scale_length, - 4, - B_UNIT_LENGTH, - &t->scene->unit, - true); - } - } - else { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", dvec[0]); - BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", dvec[1]); - BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", dvec[2]); - } - } - - if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) { - bUnit_AsString2(distvec, - sizeof(distvec), - dist * t->scene->unit.scale_length, - 4, - B_UNIT_LENGTH, - &t->scene->unit, - false); - } - else if (dist > 1e10f || dist < -1e10f) { - /* prevent string buffer overflow */ - BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4e", dist); - } - else { - BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4f", dist); - } - - if (t->flag & T_AUTOIK) { - short chainlen = t->settings->autoik_chainlen; - - if (chainlen) { - BLI_snprintf(autoik, NUM_STR_REP_LEN, TIP_("AutoIK-Len: %d"), chainlen); - } - else { - autoik[0] = '\0'; - } - } - else { - autoik[0] = '\0'; - } - - 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); - 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); - 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); - 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); - } - 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); - } - } - - if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf( - str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); - } - - if (t->spacetype == SPACE_NODE) { - SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first; - - if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) { - const char *str_old = BLI_strdup(str); - const char *str_dir = (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) ? TIP_("right") : - TIP_("left"); - char str_km[64]; - - 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); - - MEM_freeN((void *)str_old); - } - } -} - -static void applyTranslationValue(TransInfo *t, const float vec[3]) -{ - const bool apply_snap_align_rotation = usingSnappingNormal( - t); // && (t->tsnap.status & POINT_INIT); - float tvec[3]; - - /* The ideal would be "apply_snap_align_rotation" only when a snap point is found - * so, maybe inside this function is not the best place to apply this rotation. - * but you need "handle snapping rotation before doing the translation" (really?) */ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - - float pivot[3]; - if (apply_snap_align_rotation) { - copy_v3_v3(pivot, t->tsnap.snapTarget); - /* The pivot has to be in local-space (see T49494) */ - if (tc->use_local_mat) { - mul_m4_v3(tc->imat, pivot); - } - } - - TransData *td = tc->data; - for (int i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - float rotate_offset[3] = {0}; - bool use_rotate_offset = false; - - /* handle snapping rotation before doing the translation */ - if (apply_snap_align_rotation) { - float mat[3][3]; - - if (validSnappingNormal(t)) { - const float *original_normal; - - /* In pose mode, we want to align normals with Y axis of bones... */ - if (t->flag & T_POSE) { - original_normal = td->axismtx[1]; - } - else { - original_normal = td->axismtx[2]; - } - - rotation_between_vecs_to_mat3(mat, original_normal, t->tsnap.snapNormal); - } - else { - unit_m3(mat); - } - - ElementRotation_ex(t, tc, td, mat, pivot); - - if (td->loc) { - use_rotate_offset = true; - sub_v3_v3v3(rotate_offset, td->loc, td->iloc); - } - } - - if (t->con.applyVec) { - float pvec[3]; - t->con.applyVec(t, tc, td, vec, tvec, pvec); - } - else { - copy_v3_v3(tvec, vec); - } - - mul_m3_v3(td->smtx, tvec); - - if (use_rotate_offset) { - add_v3_v3(tvec, rotate_offset); - } - - if (t->options & CTX_GPENCIL_STROKES) { - /* grease pencil multiframe falloff */ - bGPDstroke *gps = (bGPDstroke *)td->extra; - if (gps != NULL) { - mul_v3_fl(tvec, td->factor * gps->runtime.multi_frame_falloff); - } - else { - mul_v3_fl(tvec, td->factor); - } - } - else { - /* proportional editing falloff */ - mul_v3_fl(tvec, td->factor); - } - - protectedTransBits(td->protectflag, tvec); - - if (td->loc) { - add_v3_v3v3(td->loc, td->iloc, tvec); - } - - constraintTransLim(t, td); - } - } -} - -static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) -{ - char str[UI_MAX_DRAW_STR]; - float values_final[3]; - - if (t->flag & T_INPUT_IS_VALUES_FINAL) { - copy_v3_v3(t->values_final, t->values); - } - else { - copy_v3_v3(t->values_final, t->values); - if ((t->con.mode & CON_APPLY) == 0) { - snapGridIncrement(t, t->values_final); - } - - if (applyNumInput(&t->num, t->values_final)) { - removeAspectRatio(t, t->values_final); - } - - applySnapping(t, t->values_final); - } - copy_v3_v3(values_final, t->values_final); - - if (t->con.mode & CON_APPLY) { - float pvec[3] = {0.0f, 0.0f, 0.0f}; - t->con.applyVec(t, NULL, NULL, t->values_final, values_final, pvec); - headerTranslation(t, pvec, str); - - /* only so we have re-usable value with redo, see T46741. */ - mul_v3_m3v3(t->values_final, t->con.imtx, values_final); - } - else { - headerTranslation(t, t->values_final, str); - copy_v3_v3(values_final, t->values_final); - } - - /* don't use 't->values' now on */ - - applyTranslationValue(t, values_final); - - /* evil hack - redo translation if clipping needed */ - if (t->flag & T_CLIP_UV && clipUVTransform(t, values_final, 0)) { - applyTranslationValue(t, values_final); - - /* In proportional edit it can happen that */ - /* vertices in the radius of the brush end */ - /* outside the clipping area */ - /* XXX HACK - dg */ - if (t->flag & T_PROP_EDIT_ALL) { - clipUVData(t); - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Shrink-Fatten) */ - -/** \name Transform Shrink-Fatten - * \{ */ - -static void initShrinkFatten(TransInfo *t) -{ - // If not in mesh edit mode, fallback to Resize - if ((t->flag & T_EDIT) == 0 || (t->obedit_type != OB_MESH)) { - initResize(t); - } - else { - t->mode = TFM_SHRINKFATTEN; - t->transform = applyShrinkFatten; - - initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 1.0f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_LENGTH; - - t->flag |= T_NO_CONSTRAINT; - } -} - -static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) -{ - float distance; - int i; - char str[UI_MAX_DRAW_STR]; - size_t ofs = 0; - - distance = -t->values[0]; - - snapGridIncrement(t, &distance); - - applyNumInput(&t->num, &distance); - - t->values_final[0] = -distance; - - /* header print for NumInput */ - ofs += BLI_strncpy_rlen(str + ofs, TIP_("Shrink/Fatten:"), sizeof(str) - ofs); - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, &t->scene->unit); - ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", c); - } - else { - /* default header print */ - ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %.4f", distance); - } - - if (t->proptext[0]) { - ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", t->proptext); - } - ofs += BLI_strncpy_rlen(str + ofs, ", (", sizeof(str) - ofs); - - if (t->keymap) { - wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE); - if (kmi) { - ofs += WM_keymap_item_to_string(kmi, false, str + ofs, sizeof(str) - ofs); - } - } - BLI_snprintf(str + ofs, - sizeof(str) - ofs, - TIP_(" or Alt) Even Thickness %s"), - WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0)); - /* done with header string */ - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - float tdistance; /* temp dist */ - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - /* get the final offset */ - tdistance = distance * td->factor; - if (td->ext && (t->flag & T_ALT_TRANSFORM) != 0) { - tdistance *= td->ext->isize[0]; /* shell factor */ - } - - madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance); - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Tilt) */ - -/** \name Transform Tilt - * \{ */ - -static void initTilt(TransInfo *t) -{ - t->mode = TFM_TILT; - t->transform = applyTilt; - - initMouseInputMode(t, &t->mouse, INPUT_ANGLE); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = DEG2RAD(5.0); - t->snap[2] = DEG2RAD(1.0); - - copy_v3_fl(t->num.val_inc, t->snap[2]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); - t->num.unit_type[0] = B_UNIT_ROTATION; - - t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; -} - -static void applyTilt(TransInfo *t, const int UNUSED(mval[2])) -{ - int i; - char str[UI_MAX_DRAW_STR]; - - float final; - - final = t->values[0]; - - snapGridIncrement(t, &final); - - applyNumInput(&t->num, &final); - - t->values_final[0] = final; - - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - BLI_snprintf(str, sizeof(str), TIP_("Tilt: %s° %s"), &c[0], t->proptext); - - /* XXX For some reason, this seems needed for this op, else RNA prop is not updated... :/ */ - t->values_final[0] = final; - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext); - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (td->val) { - *td->val = td->ival + final * td->factor; - } - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Curve Shrink/Fatten) */ - -/** \name Transform Curve Shrink/Fatten - * \{ */ - -static void initCurveShrinkFatten(TransInfo *t) -{ - t->mode = TFM_CURVE_SHRINKFATTEN; - t->transform = applyCurveShrinkFatten; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - 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 - - t->flag |= T_NO_CONSTRAINT; -} - -static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) -{ - float ratio; - int i; - char str[UI_MAX_DRAW_STR]; - - ratio = t->values[0]; - - snapGridIncrement(t, &ratio); - - applyNumInput(&t->num, &ratio); - - t->values_final[0] = ratio; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %s"), c); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %3f"), ratio); - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (td->val) { - *td->val = td->ival * ratio; - /* apply PET */ - *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival); - if (*td->val <= 0.0f) { - *td->val = 0.001f; - } - } - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Mask Shrink/Fatten) */ - -/** \name Transform Mask Shrink/Fatten - * \{ */ - -static void initMaskShrinkFatten(TransInfo *t) -{ - t->mode = TFM_MASK_SHRINKFATTEN; - t->transform = applyMaskShrinkFatten; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - 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 - - t->flag |= T_NO_CONSTRAINT; -} - -static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) -{ - float ratio; - int i; - bool initial_feather = false; - char str[UI_MAX_DRAW_STR]; - - ratio = t->values[0]; - - snapGridIncrement(t, &ratio); - - applyNumInput(&t->num, &ratio); - - t->values_final[0] = ratio; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, sizeof(str), TIP_("Feather Shrink/Fatten: %s"), c); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Feather Shrink/Fatten: %3f"), ratio); - } - - /* detect if no points have feather yet */ - if (ratio > 1.0f) { - initial_feather = true; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (td->ival >= 0.001f) { - initial_feather = false; - } - } - } - } - - /* apply shrink/fatten */ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (td = tc->data, i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (td->val) { - if (initial_feather) { - *td->val = td->ival + (ratio - 1.0f) * 0.01f; - } - else { - *td->val = td->ival * ratio; - } - - /* apply PET */ - *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival); - if (*td->val <= 0.0f) { - *td->val = 0.001f; - } - } - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (GPencil Shrink/Fatten) */ - -/** \name Transform GPencil Strokes Shrink/Fatten - * \{ */ - -static void initGPShrinkFatten(TransInfo *t) -{ - t->mode = TFM_GPENCIL_SHRINKFATTEN; - t->transform = applyGPShrinkFatten; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - 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 - - t->flag |= T_NO_CONSTRAINT; -} - -static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) -{ - float ratio; - int i; - char str[UI_MAX_DRAW_STR]; - - ratio = t->values[0]; - - snapGridIncrement(t, &ratio); - - applyNumInput(&t->num, &ratio); - - t->values_final[0] = ratio; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %s"), c); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %3f"), ratio); - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (td->val) { - *td->val = td->ival * ratio; - /* apply PET */ - *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival); - if (*td->val <= 0.0f) { - *td->val = 0.001f; - } - } - } - } - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (GPencil Opacity) */ - -/** \name Transform GPencil Strokes Opacity - * \{ */ - -static void initGPOpacity(TransInfo *t) -{ - t->mode = TFM_GPENCIL_OPACITY; - t->transform = applyGPOpacity; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - 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 - - t->flag |= T_NO_CONSTRAINT; -} - -static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2])) -{ - float ratio; - int i; - char str[UI_MAX_DRAW_STR]; - - ratio = t->values[0]; - - snapGridIncrement(t, &ratio); - - applyNumInput(&t->num, &ratio); - - t->values_final[0] = ratio; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, sizeof(str), TIP_("Opacity: %s"), c); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Opacity: %3f"), ratio); - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (td->val) { - *td->val = td->ival * ratio; - /* apply PET */ - *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival); - CLAMP(*td->val, 0.0f, 1.0f); - } - } - } - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Push/Pull) */ - -/** \name Transform Push/Pull - * \{ */ - -static void initPushPull(TransInfo *t) -{ - t->mode = TFM_PUSHPULL; - t->transform = applyPushPull; - - initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 1.0f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_LENGTH; -} - -static void applyPushPull(TransInfo *t, const int UNUSED(mval[2])) -{ - float vec[3], axis_global[3]; - float distance; - int i; - char str[UI_MAX_DRAW_STR]; - - distance = t->values[0]; - - snapGridIncrement(t, &distance); - - applyNumInput(&t->num, &distance); - - t->values_final[0] = distance; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - BLI_snprintf(str, sizeof(str), TIP_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext); - } - else { - /* default header print */ - BLI_snprintf( - str, sizeof(str), TIP_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext); - } - - if (t->con.applyRot && t->con.mode & CON_APPLY) { - t->con.applyRot(t, NULL, NULL, axis_global, NULL); - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - sub_v3_v3v3(vec, tc->center_local, td->center); - if (t->con.applyRot && t->con.mode & CON_APPLY) { - float axis[3]; - copy_v3_v3(axis, axis_global); - t->con.applyRot(t, tc, td, axis, NULL); - - mul_m3_v3(td->smtx, axis); - if (isLockConstraint(t)) { - float dvec[3]; - project_v3_v3v3(dvec, vec, axis); - sub_v3_v3(vec, dvec); - } - else { - project_v3_v3v3(vec, vec, axis); - } - } - normalize_v3_length(vec, distance * td->factor); - - add_v3_v3v3(td->loc, td->iloc, vec); - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Bevel Weight) */ - -/** \name Transform Bevel Weight - * \{ */ - -static void initBevelWeight(TransInfo *t) -{ - t->mode = TFM_BWEIGHT; - t->transform = applyBevelWeight; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING_DELTA); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - - t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; -} - -static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2])) -{ - float weight; - int i; - char str[UI_MAX_DRAW_STR]; - - weight = t->values[0]; - - CLAMP_MAX(weight, 1.0f); - - snapGridIncrement(t, &weight); - - applyNumInput(&t->num, &weight); - - t->values_final[0] = weight; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - if (weight >= 0.0f) { - BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: +%s %s"), c, t->proptext); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: %s %s"), c, t->proptext); - } - } - else { - /* default header print */ - if (weight >= 0.0f) { - BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: +%.3f %s"), weight, t->proptext); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: %.3f %s"), weight, t->proptext); - } - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->val) { - *td->val = td->ival + weight * td->factor; - if (*td->val < 0.0f) { - *td->val = 0.0f; - } - if (*td->val > 1.0f) { - *td->val = 1.0f; - } - } - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Crease) */ - -/** \name Transform Crease - * \{ */ - -static void initCrease(TransInfo *t) -{ - t->mode = TFM_CREASE; - t->transform = applyCrease; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING_DELTA); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - - t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; -} - -static void applyCrease(TransInfo *t, const int UNUSED(mval[2])) -{ - float crease; - int i; - char str[UI_MAX_DRAW_STR]; - - crease = t->values[0]; - - CLAMP_MAX(crease, 1.0f); - - snapGridIncrement(t, &crease); - - applyNumInput(&t->num, &crease); - - t->values_final[0] = crease; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - if (crease >= 0.0f) { - BLI_snprintf(str, sizeof(str), TIP_("Crease: +%s %s"), c, t->proptext); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Crease: %s %s"), c, t->proptext); - } - } - else { - /* default header print */ - if (crease >= 0.0f) { - BLI_snprintf(str, sizeof(str), TIP_("Crease: +%.3f %s"), crease, t->proptext); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Crease: %.3f %s"), crease, t->proptext); - } - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (td->val) { - *td->val = td->ival + crease * td->factor; - if (*td->val < 0.0f) { - *td->val = 0.0f; - } - if (*td->val > 1.0f) { - *td->val = 1.0f; - } - } - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (EditBone (B-bone) width scaling) */ - -/** \name Transform B-bone width scaling - * \{ */ - -static void initBoneSize(TransInfo *t) -{ - t->mode = TFM_BONESIZE; - t->transform = applyBoneSize; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP); - - t->idx_max = 2; - t->num.idx_max = 2; - t->num.val_flag[0] |= NUM_NULL_ONE; - t->num.val_flag[1] |= NUM_NULL_ONE; - t->num.val_flag[2] |= NUM_NULL_ONE; - t->num.flag |= NUM_AFFECT_ALL; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - t->num.unit_type[1] = B_UNIT_NONE; - t->num.unit_type[2] = B_UNIT_NONE; -} - -static void headerBoneSize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR]) -{ - char tvec[NUM_STR_REP_LEN * 3]; - if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, &t->scene->unit); - } - else { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]); - BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", vec[1]); - BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", vec[2]); - } - - /* hmm... perhaps the y-axis values don't need to be shown? */ - if (t->con.mode & CON_APPLY) { - if (t->num.idx_max == 0) { - BLI_snprintf( - str, UI_MAX_DRAW_STR, TIP_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext); - } - else { - BLI_snprintf(str, - UI_MAX_DRAW_STR, - TIP_("ScaleB: %s : %s : %s%s %s"), - &tvec[0], - &tvec[NUM_STR_REP_LEN], - &tvec[NUM_STR_REP_LEN * 2], - t->con.text, - t->proptext); - } - } - else { - BLI_snprintf(str, - UI_MAX_DRAW_STR, - TIP_("ScaleB 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); - } -} - -static void ElementBoneSize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3]) -{ - float tmat[3][3], smat[3][3], oldy; - float sizemat[3][3]; - - mul_m3_m3m3(smat, mat, td->mtx); - mul_m3_m3m3(tmat, td->smtx, smat); - - if (t->con.applySize) { - t->con.applySize(t, tc, td, tmat); - } - - /* we've tucked the scale in loc */ - oldy = td->iloc[1]; - size_to_mat3(sizemat, td->iloc); - mul_m3_m3m3(tmat, tmat, sizemat); - mat3_to_size(td->loc, tmat); - td->loc[1] = oldy; -} - -static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2])) -{ - float size[3], mat[3][3]; - float ratio = t->values[0]; - int i; - char str[UI_MAX_DRAW_STR]; - - copy_v3_fl(size, ratio); - - snapGridIncrement(t, size); - - if (applyNumInput(&t->num, size)) { - constraintNumInput(t, size); - } - - copy_v3_v3(t->values_final, size); - - size_to_mat3(mat, size); - - if (t->con.applySize) { - t->con.applySize(t, NULL, NULL, mat); - } - - copy_m3_m3(t->mat, mat); // used in gizmo - - headerBoneSize(t, size, str); - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - ElementBoneSize(t, tc, td, mat); - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Bone Envelope) */ - -/** \name Transform Bone Envelope - * \{ */ - -static void initBoneEnvelope(TransInfo *t) -{ - t->mode = TFM_BONE_ENVELOPE; - t->transform = applyBoneEnvelope; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - - t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; -} - -static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2])) -{ - float ratio; - int i; - char str[UI_MAX_DRAW_STR]; - - ratio = t->values[0]; - - snapGridIncrement(t, &ratio); - - applyNumInput(&t->num, &ratio); - - t->values_final[0] = ratio; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, sizeof(str), TIP_("Envelope: %s"), c); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Envelope: %3f"), ratio); - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (td->val) { - /* if the old/original value was 0.0f, then just use ratio */ - if (td->ival) { - *td->val = td->ival * ratio; - } - else { - *td->val = ratio; - } - } - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Edge Slide) */ - -/** \name Transform Edge Slide - * \{ */ - -/** - * Get the first valid EdgeSlideData. - * - * Note we cannot trust TRANS_DATA_CONTAINER_FIRST_OK because of multi-object that - * may leave items with invalid custom data in the transform data container. - */ -static EdgeSlideData *edgeSlideFirstGet(TransInfo *t) -{ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - EdgeSlideData *sld = tc->custom.mode.data; - if (sld == NULL) { - continue; - } - return sld; - } - BLI_assert(!"Should never happen, at least one EdgeSlideData should be valid"); - return NULL; -} - -static void calcEdgeSlideCustomPoints(struct TransInfo *t) -{ - EdgeSlideData *sld = edgeSlideFirstGet(t); - - setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start); - - /* setCustomPoints isn't normally changing as the mouse moves, - * in this case apply mouse input immediately so we don't refresh - * with the value from the previous points */ - applyMouseInput(t, &t->mouse, t->mval, t->values); -} - -static BMEdge *get_other_edge(BMVert *v, BMEdge *e) -{ - BMIter iter; - BMEdge *e_iter; - - BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT) && e_iter != e) { - return e_iter; - } - } - - return NULL; -} - -/* interpoaltes along a line made up of 2 segments (used for edge slide) */ -static void interp_line_v3_v3v3v3( - float p[3], const float v1[3], const float v2[3], const float v3[3], float t) -{ - float t_mid, t_delta; - - /* could be pre-calculated */ - t_mid = line_point_factor_v3(v2, v1, v3); - - t_delta = t - t_mid; - if (t_delta < 0.0f) { - if (UNLIKELY(fabsf(t_mid) < FLT_EPSILON)) { - copy_v3_v3(p, v2); - } - else { - interp_v3_v3v3(p, v1, v2, t / t_mid); - } - } - else { - t = t - t_mid; - t_mid = 1.0f - t_mid; - - if (UNLIKELY(fabsf(t_mid) < FLT_EPSILON)) { - copy_v3_v3(p, v3); - } - else { - interp_v3_v3v3(p, v2, v3, t / t_mid); - } - } -} - -/** - * Find the closest point on the ngon on the opposite side. - * used to set the edge slide distance for ngons. - */ -static bool bm_loop_calc_opposite_co(BMLoop *l_tmp, const float plane_no[3], float r_co[3]) -{ - /* skip adjacent edges */ - BMLoop *l_first = l_tmp->next; - BMLoop *l_last = l_tmp->prev; - BMLoop *l_iter; - float dist = FLT_MAX; - bool found = false; - - l_iter = l_first; - do { - float tvec[3]; - if (isect_line_plane_v3(tvec, l_iter->v->co, l_iter->next->v->co, l_tmp->v->co, plane_no)) { - const float fac = line_point_factor_v3(tvec, l_iter->v->co, l_iter->next->v->co); - /* allow some overlap to avoid missing the intersection because of float precision */ - if ((fac > -FLT_EPSILON) && (fac < 1.0f + FLT_EPSILON)) { - /* likelihood of multiple intersections per ngon is quite low, - * it would have to loop back on its self, but better support it - * so check for the closest opposite edge */ - const float tdist = len_v3v3(l_tmp->v->co, tvec); - if (tdist < dist) { - copy_v3_v3(r_co, tvec); - dist = tdist; - found = true; - } - } - } - } while ((l_iter = l_iter->next) != l_last); - - return found; -} - -/** - * Given 2 edges and a loop, step over the loops - * and calculate a direction to slide along. - * - * \param r_slide_vec: the direction to slide, - * the length of the vector defines the slide distance. - */ -static BMLoop *get_next_loop( - BMVert *v, BMLoop *l, BMEdge *e_prev, BMEdge *e_next, float r_slide_vec[3]) -{ - BMLoop *l_first; - float vec_accum[3] = {0.0f, 0.0f, 0.0f}; - float vec_accum_len = 0.0f; - int i = 0; - - BLI_assert(BM_edge_share_vert(e_prev, e_next) == v); - BLI_assert(BM_vert_in_edge(l->e, v)); - - l_first = l; - do { - l = BM_loop_other_edge_loop(l, v); - - if (l->e == e_next) { - if (i) { - normalize_v3_length(vec_accum, vec_accum_len / (float)i); - } - else { - /* When there is no edge to slide along, - * we must slide along the vector defined by the face we're attach to */ - BMLoop *l_tmp = BM_face_vert_share_loop(l_first->f, v); - - BLI_assert(ELEM(l_tmp->e, e_prev, e_next) && ELEM(l_tmp->prev->e, e_prev, e_next)); - - if (l_tmp->f->len == 4) { - /* we could use code below, but in this case - * sliding diagonally across the quad works well */ - sub_v3_v3v3(vec_accum, l_tmp->next->next->v->co, v->co); - } - else { - float tdir[3]; - BM_loop_calc_face_direction(l_tmp, tdir); - cross_v3_v3v3(vec_accum, l_tmp->f->no, tdir); -#if 0 - /* rough guess, we can do better! */ - normalize_v3_length(vec_accum, - (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f); -#else - /* be clever, check the opposite ngon edge to slide into. - * this gives best results */ - { - float tvec[3]; - float dist; - - if (bm_loop_calc_opposite_co(l_tmp, tdir, tvec)) { - dist = len_v3v3(l_tmp->v->co, tvec); - } - else { - dist = (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f; - } - - normalize_v3_length(vec_accum, dist); - } -#endif - } - } - - copy_v3_v3(r_slide_vec, vec_accum); - return l; - } - else { - /* accumulate the normalized edge vector, - * normalize so some edges don't skew the result */ - float tvec[3]; - sub_v3_v3v3(tvec, BM_edge_other_vert(l->e, v)->co, v->co); - vec_accum_len += normalize_v3(tvec); - add_v3_v3(vec_accum, tvec); - i += 1; - } - - if (BM_loop_other_edge_loop(l, v)->e == e_next) { - if (i) { - normalize_v3_length(vec_accum, vec_accum_len / (float)i); - } - - copy_v3_v3(r_slide_vec, vec_accum); - return BM_loop_other_edge_loop(l, v); - } - - } while ((l != l->radial_next) && ((l = l->radial_next) != l_first)); - - if (i) { - normalize_v3_length(vec_accum, vec_accum_len / (float)i); - } - - copy_v3_v3(r_slide_vec, vec_accum); - - return NULL; -} - -/** - * Calculate screenspace `mval_start` / `mval_end`, optionally slide direction. - */ -static void calcEdgeSlide_mval_range(TransInfo *t, - TransDataContainer *tc, - EdgeSlideData *sld, - const int *sv_table, - const int loop_nr, - const float mval[2], - const bool use_occlude_geometry, - const bool use_calc_direction) -{ - TransDataEdgeSlideVert *sv; - BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); - ARegion *ar = t->ar; - View3D *v3d = NULL; - RegionView3D *rv3d = NULL; - float projectMat[4][4]; - BMBVHTree *bmbvh; - - /* only for use_calc_direction */ - float(*loop_dir)[3] = NULL, *loop_maxdist = NULL; - - float mval_start[2], mval_end[2]; - float mval_dir[3], dist_best_sq; - - if (t->spacetype == SPACE_VIEW3D) { - /* background mode support */ - v3d = t->sa ? t->sa->spacedata.first : NULL; - rv3d = t->ar ? t->ar->regiondata : NULL; - } - - if (!rv3d) { - /* ok, let's try to survive this */ - unit_m4(projectMat); - } - else { - ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat); - } - - if (use_occlude_geometry) { - bmbvh = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false); - } - else { - bmbvh = NULL; - } - - /* find mouse vectors, the global one, and one per loop in case we have - * multiple loops selected, in case they are oriented different */ - zero_v3(mval_dir); - dist_best_sq = -1.0f; - - if (use_calc_direction) { - loop_dir = MEM_callocN(sizeof(float[3]) * loop_nr, "sv loop_dir"); - loop_maxdist = MEM_mallocN(sizeof(float) * loop_nr, "sv loop_maxdist"); - copy_vn_fl(loop_maxdist, loop_nr, -1.0f); - } - - sv = &sld->sv[0]; - for (int i = 0; i < sld->totsv; i++, sv++) { - BMIter iter_other; - BMEdge *e; - BMVert *v = sv->v; - - UNUSED_VARS_NDEBUG(sv_table); /* silence warning */ - BLI_assert(i == sv_table[BM_elem_index_get(v)]); - - /* search cross edges for visible edge to the mouse cursor, - * then use the shared vertex to calculate screen vector*/ - BM_ITER_ELEM (e, &iter_other, v, BM_EDGES_OF_VERT) { - /* screen-space coords */ - float sco_a[3], sco_b[3]; - float dist_sq; - int l_nr; - - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - continue; - } - - /* This test is only relevant if object is not wire-drawn! See [#32068]. */ - bool is_visible = !use_occlude_geometry || - BMBVH_EdgeVisible(bmbvh, e, t->depsgraph, ar, v3d, tc->obedit); - - if (!is_visible && !use_calc_direction) { - continue; - } - - if (sv->v_side[1]) { - ED_view3d_project_float_v3_m4(ar, sv->v_side[1]->co, sco_b, projectMat); - } - else { - add_v3_v3v3(sco_b, v->co, sv->dir_side[1]); - ED_view3d_project_float_v3_m4(ar, sco_b, sco_b, projectMat); - } - - if (sv->v_side[0]) { - ED_view3d_project_float_v3_m4(ar, sv->v_side[0]->co, sco_a, projectMat); - } - else { - add_v3_v3v3(sco_a, v->co, sv->dir_side[0]); - ED_view3d_project_float_v3_m4(ar, sco_a, sco_a, projectMat); - } - - /* global direction */ - dist_sq = dist_squared_to_line_segment_v2(mval, sco_b, sco_a); - if (is_visible) { - if ((dist_best_sq == -1.0f) || - /* intentionally use 2d size on 3d vector */ - (dist_sq < dist_best_sq && (len_squared_v2v2(sco_b, sco_a) > 0.1f))) { - dist_best_sq = dist_sq; - sub_v3_v3v3(mval_dir, sco_b, sco_a); - } - } - - if (use_calc_direction) { - /* per loop direction */ - l_nr = sv->loop_nr; - if (loop_maxdist[l_nr] == -1.0f || dist_sq < loop_maxdist[l_nr]) { - loop_maxdist[l_nr] = dist_sq; - sub_v3_v3v3(loop_dir[l_nr], sco_b, sco_a); - } - } - } - } - - if (use_calc_direction) { - int i; - sv = &sld->sv[0]; - for (i = 0; i < sld->totsv; i++, sv++) { - /* switch a/b if loop direction is different from global direction */ - int l_nr = sv->loop_nr; - if (dot_v3v3(loop_dir[l_nr], mval_dir) < 0.0f) { - swap_v3_v3(sv->dir_side[0], sv->dir_side[1]); - SWAP(BMVert *, sv->v_side[0], sv->v_side[1]); - } - } - - MEM_freeN(loop_dir); - MEM_freeN(loop_maxdist); - } - - /* possible all of the edge loops are pointing directly at the view */ - if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) { - mval_dir[0] = 0.0f; - mval_dir[1] = 100.0f; - } - - /* zero out start */ - zero_v2(mval_start); - - /* dir holds a vector along edge loop */ - copy_v2_v2(mval_end, mval_dir); - mul_v2_fl(mval_end, 0.5f); - - sld->mval_start[0] = t->mval[0] + mval_start[0]; - sld->mval_start[1] = t->mval[1] + mval_start[1]; - - sld->mval_end[0] = t->mval[0] + mval_end[0]; - sld->mval_end[1] = t->mval[1] + mval_end[1]; - - if (bmbvh) { - BKE_bmbvh_free(bmbvh); - } -} - -static void calcEdgeSlide_even(TransInfo *t, - TransDataContainer *tc, - EdgeSlideData *sld, - const float mval[2]) -{ - TransDataEdgeSlideVert *sv = sld->sv; - - if (sld->totsv > 0) { - ARegion *ar = t->ar; - RegionView3D *rv3d = NULL; - float projectMat[4][4]; - - int i = 0; - - float v_proj[2]; - float dist_sq = 0; - float dist_min_sq = FLT_MAX; - - if (t->spacetype == SPACE_VIEW3D) { - /* background mode support */ - rv3d = t->ar ? t->ar->regiondata : NULL; - } - - if (!rv3d) { - /* ok, let's try to survive this */ - unit_m4(projectMat); - } - else { - ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat); - } - - for (i = 0; i < sld->totsv; i++, sv++) { - /* Set length */ - sv->edge_len = len_v3v3(sv->dir_side[0], sv->dir_side[1]); - - ED_view3d_project_float_v2_m4(ar, sv->v->co, v_proj, projectMat); - dist_sq = len_squared_v2v2(mval, v_proj); - if (dist_sq < dist_min_sq) { - dist_min_sq = dist_sq; - sld->curr_sv_index = i; - } - } - } - else { - sld->curr_sv_index = 0; - } -} - -static bool createEdgeSlideVerts_double_side(TransInfo *t, TransDataContainer *tc) -{ - BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); - BMesh *bm = em->bm; - BMIter iter; - BMEdge *e; - BMVert *v; - TransDataEdgeSlideVert *sv_array; - int sv_tot; - int *sv_table; /* BMVert -> sv_array index */ - EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld"); - float mval[2] = {(float)t->mval[0], (float)t->mval[1]}; - int numsel, i, loop_nr; - bool use_occlude_geometry = false; - View3D *v3d = NULL; - RegionView3D *rv3d = NULL; - - sld->curr_sv_index = 0; - - /*ensure valid selection*/ - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { - BMIter iter2; - numsel = 0; - BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - /* BMESH_TODO: this is probably very evil, - * set v->e to a selected edge*/ - v->e = e; - - numsel++; - } - } - - if (numsel == 0 || numsel > 2) { - MEM_freeN(sld); - return false; /* invalid edge selection */ - } - } - } - - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - /* note, any edge with loops can work, but we won't get predictable results, so bail out */ - if (!BM_edge_is_manifold(e) && !BM_edge_is_boundary(e)) { - /* can edges with at least once face user */ - MEM_freeN(sld); - return false; - } - } - } - - sv_table = MEM_mallocN(sizeof(*sv_table) * bm->totvert, __func__); - -#define INDEX_UNSET -1 -#define INDEX_INVALID -2 - - { - int j = 0; - BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { - BM_elem_flag_enable(v, BM_ELEM_TAG); - sv_table[i] = INDEX_UNSET; - j += 1; - } - else { - BM_elem_flag_disable(v, BM_ELEM_TAG); - sv_table[i] = INDEX_INVALID; - } - BM_elem_index_set(v, i); /* set_inline */ - } - bm->elem_index_dirty &= ~BM_VERT; - - if (!j) { - MEM_freeN(sld); - MEM_freeN(sv_table); - return false; - } - sv_tot = j; - } - - sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * sv_tot, "sv_array"); - loop_nr = 0; - - STACK_DECLARE(sv_array); - STACK_INIT(sv_array, sv_tot); - - while (1) { - float vec_a[3], vec_b[3]; - BMLoop *l_a, *l_b; - BMLoop *l_a_prev, *l_b_prev; - BMVert *v_first; - /* If this succeeds call get_next_loop() - * which calculates the direction to slide based on clever checks. - * - * otherwise we simply use 'e_dir' as an edge-rail. - * (which is better when the attached edge is a boundary, see: T40422) - */ -#define EDGESLIDE_VERT_IS_INNER(v, e_dir) \ - ((BM_edge_is_boundary(e_dir) == false) && (BM_vert_edge_count_nonwire(v) == 2)) - - v = NULL; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - break; - } - } - - if (!v) { - break; - } - - if (!v->e) { - continue; - } - - v_first = v; - - /*walk along the edge loop*/ - e = v->e; - - /*first, rewind*/ - do { - e = get_other_edge(v, e); - if (!e) { - e = v->e; - break; - } - - if (!BM_elem_flag_test(BM_edge_other_vert(e, v), BM_ELEM_TAG)) { - break; - } - - v = BM_edge_other_vert(e, v); - } while (e != v_first->e); - - BM_elem_flag_disable(v, BM_ELEM_TAG); - - l_a = e->l; - l_b = e->l->radial_next; - - /* regarding e_next, use get_next_loop()'s improved interpolation where possible */ - { - BMEdge *e_next = get_other_edge(v, e); - if (e_next) { - get_next_loop(v, l_a, e, e_next, vec_a); - } - else { - BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v); - if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) { - get_next_loop(v, l_a, e, l_tmp->e, vec_a); - } - else { - sub_v3_v3v3(vec_a, BM_edge_other_vert(l_tmp->e, v)->co, v->co); - } - } - } - - /* !BM_edge_is_boundary(e); */ - if (l_b != l_a) { - BMEdge *e_next = get_other_edge(v, e); - if (e_next) { - get_next_loop(v, l_b, e, e_next, vec_b); - } - else { - BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v); - if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) { - get_next_loop(v, l_b, e, l_tmp->e, vec_b); - } - else { - sub_v3_v3v3(vec_b, BM_edge_other_vert(l_tmp->e, v)->co, v->co); - } - } - } - else { - l_b = NULL; - } - - l_a_prev = NULL; - l_b_prev = NULL; - -#define SV_FROM_VERT(v) \ - ((sv_table[BM_elem_index_get(v)] == INDEX_UNSET) ? \ - ((void)(sv_table[BM_elem_index_get(v)] = STACK_SIZE(sv_array)), \ - STACK_PUSH_RET_PTR(sv_array)) : \ - (&sv_array[sv_table[BM_elem_index_get(v)]])) - - /*iterate over the loop*/ - v_first = v; - do { - bool l_a_ok_prev; - bool l_b_ok_prev; - TransDataEdgeSlideVert *sv; - BMVert *v_prev; - BMEdge *e_prev; - - /* XXX, 'sv' will initialize multiple times, this is suspicious. see [#34024] */ - BLI_assert(v != NULL); - BLI_assert(sv_table[BM_elem_index_get(v)] != INDEX_INVALID); - sv = SV_FROM_VERT(v); - sv->v = v; - copy_v3_v3(sv->v_co_orig, v->co); - sv->loop_nr = loop_nr; - - if (l_a || l_a_prev) { - BMLoop *l_tmp = BM_loop_other_edge_loop(l_a ? l_a : l_a_prev, v); - sv->v_side[0] = BM_edge_other_vert(l_tmp->e, v); - copy_v3_v3(sv->dir_side[0], vec_a); - } - - if (l_b || l_b_prev) { - BMLoop *l_tmp = BM_loop_other_edge_loop(l_b ? l_b : l_b_prev, v); - sv->v_side[1] = BM_edge_other_vert(l_tmp->e, v); - copy_v3_v3(sv->dir_side[1], vec_b); - } - - v_prev = v; - v = BM_edge_other_vert(e, v); - - e_prev = e; - e = get_other_edge(v, e); - - if (!e) { - BLI_assert(v != NULL); - - BLI_assert(sv_table[BM_elem_index_get(v)] != INDEX_INVALID); - sv = SV_FROM_VERT(v); - - sv->v = v; - copy_v3_v3(sv->v_co_orig, v->co); - sv->loop_nr = loop_nr; - - if (l_a) { - BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v); - sv->v_side[0] = BM_edge_other_vert(l_tmp->e, v); - if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) { - get_next_loop(v, l_a, e_prev, l_tmp->e, sv->dir_side[0]); - } - else { - sub_v3_v3v3(sv->dir_side[0], sv->v_side[0]->co, v->co); - } - } - - if (l_b) { - BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v); - sv->v_side[1] = BM_edge_other_vert(l_tmp->e, v); - if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) { - get_next_loop(v, l_b, e_prev, l_tmp->e, sv->dir_side[1]); - } - else { - sub_v3_v3v3(sv->dir_side[1], sv->v_side[1]->co, v->co); - } - } - - BM_elem_flag_disable(v, BM_ELEM_TAG); - BM_elem_flag_disable(v_prev, BM_ELEM_TAG); - - break; - } - l_a_ok_prev = (l_a != NULL); - l_b_ok_prev = (l_b != NULL); - - l_a_prev = l_a; - l_b_prev = l_b; - - if (l_a) { - l_a = get_next_loop(v, l_a, e_prev, e, vec_a); - } - else { - zero_v3(vec_a); - } - - if (l_b) { - l_b = get_next_loop(v, l_b, e_prev, e, vec_b); - } - else { - zero_v3(vec_b); - } - - if (l_a && l_b) { - /* pass */ - } - else { - if (l_a || l_b) { - /* find the opposite loop if it was missing previously */ - if (l_a == NULL && l_b && (l_b->radial_next != l_b)) { - l_a = l_b->radial_next; - } - else if (l_b == NULL && l_a && (l_a->radial_next != l_a)) { - l_b = l_a->radial_next; - } - } - else if (e->l != NULL) { - /* if there are non-contiguous faces, we can still recover - * the loops of the new edges faces */ - - /* note!, the behavior in this case means edges may move in opposite directions, - * this could be made to work more usefully. */ - - if (l_a_ok_prev) { - l_a = e->l; - l_b = (l_a->radial_next != l_a) ? l_a->radial_next : NULL; - } - else if (l_b_ok_prev) { - l_b = e->l; - l_a = (l_b->radial_next != l_b) ? l_b->radial_next : NULL; - } - } - - if (!l_a_ok_prev && l_a) { - get_next_loop(v, l_a, e, e_prev, vec_a); - } - if (!l_b_ok_prev && l_b) { - get_next_loop(v, l_b, e, e_prev, vec_b); - } - } - - BM_elem_flag_disable(v, BM_ELEM_TAG); - BM_elem_flag_disable(v_prev, BM_ELEM_TAG); - } while ((e != v_first->e) && (l_a || l_b)); - -#undef SV_FROM_VERT -#undef INDEX_UNSET -#undef INDEX_INVALID - - loop_nr++; - -#undef EDGESLIDE_VERT_IS_INNER - } - - /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */ - - BLI_assert(STACK_SIZE(sv_array) == sv_tot); - - sld->sv = sv_array; - sld->totsv = sv_tot; - - /* use for visibility checks */ - if (t->spacetype == SPACE_VIEW3D) { - v3d = t->sa ? t->sa->spacedata.first : NULL; - rv3d = t->ar ? t->ar->regiondata : NULL; - use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE && - !XRAY_ENABLED(v3d)); - } - - calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, true); - - if (rv3d) { - calcEdgeSlide_even(t, tc, sld, mval); - } - - tc->custom.mode.data = sld; - - MEM_freeN(sv_table); - - return true; -} - -/** - * A simple version of #createEdgeSlideVerts_double_side - * Which assumes the longest unselected. - */ -static bool createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *tc) -{ - BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); - BMesh *bm = em->bm; - BMIter iter; - BMEdge *e; - TransDataEdgeSlideVert *sv_array; - int sv_tot; - int *sv_table; /* BMVert -> sv_array index */ - EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld"); - float mval[2] = {(float)t->mval[0], (float)t->mval[1]}; - int loop_nr; - bool use_occlude_geometry = false; - View3D *v3d = NULL; - RegionView3D *rv3d = NULL; - - if (t->spacetype == SPACE_VIEW3D) { - /* background mode support */ - v3d = t->sa ? t->sa->spacedata.first : NULL; - rv3d = t->ar ? t->ar->regiondata : NULL; - } - - sld->curr_sv_index = 0; - /* ensure valid selection */ - { - int i = 0, j = 0; - BMVert *v; - - BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { - float len_sq_max = -1.0f; - BMIter iter2; - BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) { - if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) { - float len_sq = BM_edge_calc_length_squared(e); - if (len_sq > len_sq_max) { - len_sq_max = len_sq; - v->e = e; - } - } - } - - if (len_sq_max != -1.0f) { - j++; - } - } - BM_elem_index_set(v, i); /* set_inline */ - } - bm->elem_index_dirty &= ~BM_VERT; - - if (!j) { - MEM_freeN(sld); - return false; - } - - sv_tot = j; - } - - BLI_assert(sv_tot != 0); - /* over alloc */ - sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * bm->totvertsel, "sv_array"); - - /* same loop for all loops, weak but we dont connect loops in this case */ - loop_nr = 1; - - sv_table = MEM_mallocN(sizeof(*sv_table) * bm->totvert, __func__); - - { - int i = 0, j = 0; - BMVert *v; - - BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { - sv_table[i] = -1; - if ((v->e != NULL) && (BM_elem_flag_test(v, BM_ELEM_SELECT))) { - if (BM_elem_flag_test(v->e, BM_ELEM_SELECT) == 0) { - TransDataEdgeSlideVert *sv; - sv = &sv_array[j]; - sv->v = v; - copy_v3_v3(sv->v_co_orig, v->co); - sv->v_side[0] = BM_edge_other_vert(v->e, v); - sub_v3_v3v3(sv->dir_side[0], sv->v_side[0]->co, v->co); - sv->loop_nr = 0; - sv_table[i] = j; - j += 1; - } - } - } - } - - /* check for wire vertices, - * interpolate the directions of wire verts between non-wire verts */ - if (sv_tot != bm->totvert) { - const int sv_tot_nowire = sv_tot; - TransDataEdgeSlideVert *sv_iter = sv_array; - - for (int i = 0; i < sv_tot_nowire; i++, sv_iter++) { - BMIter eiter; - BM_ITER_ELEM (e, &eiter, sv_iter->v, BM_EDGES_OF_VERT) { - /* walk over wire */ - TransDataEdgeSlideVert *sv_end = NULL; - BMEdge *e_step = e; - BMVert *v = sv_iter->v; - int j; - - j = sv_tot; - - while (1) { - BMVert *v_other = BM_edge_other_vert(e_step, v); - int endpoint = ((sv_table[BM_elem_index_get(v_other)] != -1) + - (BM_vert_is_edge_pair(v_other) == false)); - - if ((BM_elem_flag_test(e_step, BM_ELEM_SELECT) && - BM_elem_flag_test(v_other, BM_ELEM_SELECT)) && - (endpoint == 0)) { - /* scan down the list */ - TransDataEdgeSlideVert *sv; - BLI_assert(sv_table[BM_elem_index_get(v_other)] == -1); - sv_table[BM_elem_index_get(v_other)] = j; - sv = &sv_array[j]; - sv->v = v_other; - copy_v3_v3(sv->v_co_orig, v_other->co); - copy_v3_v3(sv->dir_side[0], sv_iter->dir_side[0]); - j++; - - /* advance! */ - v = v_other; - e_step = BM_DISK_EDGE_NEXT(e_step, v_other); - } - else { - if ((endpoint == 2) && (sv_tot != j)) { - BLI_assert(BM_elem_index_get(v_other) != -1); - sv_end = &sv_array[sv_table[BM_elem_index_get(v_other)]]; - } - break; - } - } - - if (sv_end) { - int sv_tot_prev = sv_tot; - const float *co_src = sv_iter->v->co; - const float *co_dst = sv_end->v->co; - const float *dir_src = sv_iter->dir_side[0]; - const float *dir_dst = sv_end->dir_side[0]; - sv_tot = j; - - while (j-- != sv_tot_prev) { - float factor; - factor = line_point_factor_v3(sv_array[j].v->co, co_src, co_dst); - interp_v3_v3v3(sv_array[j].dir_side[0], dir_src, dir_dst, factor); - } - } - } - } - } - - /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */ - - sld->sv = sv_array; - sld->totsv = sv_tot; - - /* use for visibility checks */ - if (t->spacetype == SPACE_VIEW3D) { - v3d = t->sa ? t->sa->spacedata.first : NULL; - rv3d = t->ar ? t->ar->regiondata : NULL; - use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE && - !XRAY_ENABLED(v3d)); - } - - calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, false); - - if (rv3d) { - calcEdgeSlide_even(t, tc, sld, mval); - } - - tc->custom.mode.data = sld; - - MEM_freeN(sv_table); - - return true; -} - -void projectEdgeSlideData(TransInfo *t, bool is_final) -{ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - EdgeSlideData *sld = tc->custom.mode.data; - - if (sld == NULL) { - continue; - } - - trans_mesh_customdata_correction_apply(tc, is_final); - } -} - -void freeEdgeSlideVerts(TransInfo *UNUSED(t), - TransDataContainer *UNUSED(tc), - TransCustomData *custom_data) -{ - EdgeSlideData *sld = custom_data->data; - - if (sld == NULL) { - return; - } - - MEM_freeN(sld->sv); - MEM_freeN(sld); - - custom_data->data = NULL; -} - -static void initEdgeSlide_ex( - TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp) -{ - EdgeSlideData *sld; - bool ok = false; - - t->mode = TFM_EDGE_SLIDE; - t->transform = applyEdgeSlide; - t->handleEvent = handleEventEdgeSlide; - - { - EdgeSlideParams *slp = MEM_callocN(sizeof(*slp), __func__); - slp->use_even = use_even; - slp->flipped = flipped; - /* happens to be best for single-sided */ - if (use_double_side == false) { - slp->flipped = !flipped; - } - slp->perc = 0.0f; - - if (!use_clamp) { - t->flag |= T_ALT_TRANSFORM; - } - - t->custom.mode.data = slp; - t->custom.mode.use_free = true; - } - - if (use_double_side) { - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - ok |= createEdgeSlideVerts_double_side(t, tc); - } - } - else { - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - ok |= createEdgeSlideVerts_single_side(t, tc); - } - } - - if (!ok) { - t->state = TRANS_CANCEL; - return; - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - sld = tc->custom.mode.data; - if (!sld) { - continue; - } - tc->custom.mode.free_cb = freeEdgeSlideVerts; - } - - trans_mesh_customdata_correction_init(t); - - /* set custom point first if you want value to be initialized by init */ - calcEdgeSlideCustomPoints(t); - initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO_FLIP); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - - t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; -} - -static void initEdgeSlide(TransInfo *t) -{ - initEdgeSlide_ex(t, true, false, false, true); -} - -static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event) -{ - if (t->mode == TFM_EDGE_SLIDE) { - EdgeSlideParams *slp = t->custom.mode.data; - - if (slp) { - switch (event->type) { - case EKEY: - if (event->val == KM_PRESS) { - slp->use_even = !slp->use_even; - calcEdgeSlideCustomPoints(t); - return TREDRAW_HARD; - } - break; - case FKEY: - if (event->val == KM_PRESS) { - slp->flipped = !slp->flipped; - calcEdgeSlideCustomPoints(t); - return TREDRAW_HARD; - } - break; - case CKEY: - /* use like a modifier key */ - if (event->val == KM_PRESS) { - t->flag ^= T_ALT_TRANSFORM; - calcEdgeSlideCustomPoints(t); - return TREDRAW_HARD; - } - break; - case EVT_MODAL_MAP: -#if 0 - switch (event->val) { - case TFM_MODAL_EDGESLIDE_DOWN: - sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv; - return TREDRAW_HARD; - case TFM_MODAL_EDGESLIDE_UP: - sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv; - return TREDRAW_HARD; - } -#endif - break; - case MOUSEMOVE: - calcEdgeSlideCustomPoints(t); - break; - default: - break; - } - } - } - return TREDRAW_NOTHING; -} - -static void drawEdgeSlide(TransInfo *t) -{ - if ((t->mode == TFM_EDGE_SLIDE) && edgeSlideFirstGet(t)) { - const EdgeSlideParams *slp = t->custom.mode.data; - EdgeSlideData *sld = edgeSlideFirstGet(t); - const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); - - /* Even mode */ - if ((slp->use_even == true) || (is_clamp == false)) { - const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f; - - GPU_depth_test(false); - - GPU_blend(true); - GPU_blend_set_func_separate( - GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - - GPU_matrix_push(); - GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); - - uint pos = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - - if (slp->use_even == true) { - float co_a[3], co_b[3], co_mark[3]; - TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; - const float fac = (slp->perc + 1.0f) / 2.0f; - const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f; - const float guide_size = ctrl_size - 0.5f; - const int alpha_shade = -30; - - add_v3_v3v3(co_a, curr_sv->v_co_orig, curr_sv->dir_side[0]); - add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_side[1]); - - GPU_line_width(line_size); - immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); - immBeginAtMost(GPU_PRIM_LINES, 4); - if (curr_sv->v_side[0]) { - immVertex3fv(pos, curr_sv->v_side[0]->co); - immVertex3fv(pos, curr_sv->v_co_orig); - } - if (curr_sv->v_side[1]) { - immVertex3fv(pos, curr_sv->v_side[1]->co); - immVertex3fv(pos, curr_sv->v_co_orig); - } - immEnd(); - - { - float *co_test = NULL; - if (slp->flipped) { - if (curr_sv->v_side[1]) { - co_test = curr_sv->v_side[1]->co; - } - } - else { - if (curr_sv->v_side[0]) { - co_test = curr_sv->v_side[0]->co; - } - } - - if (co_test != NULL) { - immUniformThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade); - GPU_point_size(ctrl_size); - immBegin(GPU_PRIM_POINTS, 1); - immVertex3fv(pos, co_test); - immEnd(); - } - } - - immUniformThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade); - GPU_point_size(guide_size); - immBegin(GPU_PRIM_POINTS, 1); - interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac); - immVertex3fv(pos, co_mark); - immEnd(); - } - else { - if (is_clamp == false) { - const int side_index = sld->curr_side_unclamp; - TransDataEdgeSlideVert *sv; - int i; - const int alpha_shade = -160; - - GPU_line_width(line_size); - immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); - immBegin(GPU_PRIM_LINES, sld->totsv * 2); - - /* TODO(campbell): Loop over all verts */ - sv = sld->sv; - for (i = 0; i < sld->totsv; i++, sv++) { - float a[3], b[3]; - - if (!is_zero_v3(sv->dir_side[side_index])) { - copy_v3_v3(a, sv->dir_side[side_index]); - } - else { - copy_v3_v3(a, sv->dir_side[!side_index]); - } - - mul_v3_fl(a, 100.0f); - negate_v3_v3(b, a); - add_v3_v3(a, sv->v_co_orig); - add_v3_v3(b, sv->v_co_orig); - - immVertex3fv(pos, a); - immVertex3fv(pos, b); - } - immEnd(); - } - else { - BLI_assert(0); - } - } - - immUnbindProgram(); - - GPU_matrix_pop(); - - GPU_blend(false); - - GPU_depth_test(true); - } - } -} - -static void doEdgeSlide(TransInfo *t, float perc) -{ - EdgeSlideParams *slp = t->custom.mode.data; - EdgeSlideData *sld_active = edgeSlideFirstGet(t); - - slp->perc = perc; - - if (slp->use_even == false) { - const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); - if (is_clamp) { - const int side_index = (perc < 0.0f); - const float perc_final = fabsf(perc); - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - EdgeSlideData *sld = tc->custom.mode.data; - - if (sld == NULL) { - continue; - } - - TransDataEdgeSlideVert *sv = sld->sv; - for (int i = 0; i < sld->totsv; i++, sv++) { - madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, sv->dir_side[side_index], perc_final); - } - sld->curr_side_unclamp = side_index; - } - } - else { - const float perc_init = fabsf(perc) * - ((sld_active->curr_side_unclamp == (perc < 0.0f)) ? 1 : -1); - const int side_index = sld_active->curr_side_unclamp; - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - EdgeSlideData *sld = tc->custom.mode.data; - - if (sld == NULL) { - continue; - } - - TransDataEdgeSlideVert *sv = sld->sv; - for (int i = 0; i < sld->totsv; i++, sv++) { - float dir_flip[3]; - float perc_final = perc_init; - if (!is_zero_v3(sv->dir_side[side_index])) { - copy_v3_v3(dir_flip, sv->dir_side[side_index]); - } - else { - copy_v3_v3(dir_flip, sv->dir_side[!side_index]); - perc_final *= -1; - } - madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, dir_flip, perc_final); - } - } - } - } - else { - /** - * Implementation note, even mode ignores the starting positions and uses - * only the a/b verts, this could be changed/improved so the distance is - * still met but the verts are moved along their original path (which may not be straight), - * however how it works now is OK and matches 2.4x - Campbell - * - * \note `len_v3v3(curr_sv->dir_side[0], curr_sv->dir_side[1])` - * is the same as the distance between the original vert locations, - * same goes for the lines below. - */ - TransDataEdgeSlideVert *curr_sv = &sld_active->sv[sld_active->curr_sv_index]; - const float curr_length_perc = curr_sv->edge_len * - (((slp->flipped ? perc : -perc) + 1.0f) / 2.0f); - - float co_a[3]; - float co_b[3]; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - EdgeSlideData *sld = tc->custom.mode.data; - - if (sld == NULL) { - continue; - } - - TransDataEdgeSlideVert *sv = sld->sv; - for (int i = 0; i < sld->totsv; i++, sv++) { - if (sv->edge_len > FLT_EPSILON) { - const float fac = min_ff(sv->edge_len, curr_length_perc) / sv->edge_len; - - add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_side[0]); - add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_side[1]); - - if (slp->flipped) { - interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac); - } - else { - interp_line_v3_v3v3v3(sv->v->co, co_a, sv->v_co_orig, co_b, fac); - } - } - } - } - } -} - -static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2])) -{ - char str[UI_MAX_DRAW_STR]; - size_t ofs = 0; - float final; - EdgeSlideParams *slp = t->custom.mode.data; - bool flipped = slp->flipped; - bool use_even = slp->use_even; - const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); - const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num)); - - final = t->values[0]; - - snapGridIncrement(t, &final); - - /* only do this so out of range values are not displayed */ - if (is_constrained) { - CLAMP(final, -1.0f, 1.0f); - } - - applyNumInput(&t->num, &final); - - t->values_final[0] = final; - - /* header string */ - ofs += BLI_strncpy_rlen(str + ofs, TIP_("Edge Slide: "), sizeof(str) - ofs); - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, &t->scene->unit); - 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( - str + ofs, sizeof(str) - ofs, TIP_("(E)ven: %s, "), WM_bool_as_string(use_even)); - if (use_even) { - ofs += BLI_snprintf( - str + ofs, sizeof(str) - ofs, TIP_("(F)lipped: %s, "), WM_bool_as_string(flipped)); - } - ofs += BLI_snprintf( - str + ofs, sizeof(str) - ofs, TIP_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp)); - /* done with header string */ - - /* do stuff here */ - doEdgeSlide(t, final); - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Vert Slide) */ - -/** \name Transform Vert Slide - * \{ */ - -static void calcVertSlideCustomPoints(struct TransInfo *t) -{ - VertSlideParams *slp = t->custom.mode.data; - VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; - TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index]; - - const float *co_orig_3d = sv->co_orig_3d; - const float *co_curr_3d = sv->co_link_orig_3d[sv->co_link_curr]; - - float co_curr_2d[2], co_orig_2d[2]; - - int mval_ofs[2], mval_start[2], mval_end[2]; - - ED_view3d_project_float_v2_m4(t->ar, co_orig_3d, co_orig_2d, sld->proj_mat); - ED_view3d_project_float_v2_m4(t->ar, co_curr_3d, co_curr_2d, sld->proj_mat); - - ARRAY_SET_ITEMS(mval_ofs, t->mouse.imval[0] - co_orig_2d[0], t->mouse.imval[1] - co_orig_2d[1]); - ARRAY_SET_ITEMS(mval_start, co_orig_2d[0] + mval_ofs[0], co_orig_2d[1] + mval_ofs[1]); - ARRAY_SET_ITEMS(mval_end, co_curr_2d[0] + mval_ofs[0], co_curr_2d[1] + mval_ofs[1]); - - if (slp->flipped && slp->use_even) { - setCustomPoints(t, &t->mouse, mval_start, mval_end); - } - else { - setCustomPoints(t, &t->mouse, mval_end, mval_start); - } - - /* setCustomPoints isn't normally changing as the mouse moves, - * in this case apply mouse input immediately so we don't refresh - * with the value from the previous points */ - applyMouseInput(t, &t->mouse, t->mval, t->values); -} - -/** - * Run once when initializing vert slide to find the reference edge - */ -static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2]) -{ - /* Active object may have no selected vertices. */ - VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; - float mval_fl[2] = {UNPACK2(mval)}; - TransDataVertSlideVert *sv; - - /* set the vertex to use as a reference for the mouse direction 'curr_sv_index' */ - float dist_sq = 0.0f; - float dist_min_sq = FLT_MAX; - int i; - - for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) { - float co_2d[2]; - - ED_view3d_project_float_v2_m4(t->ar, sv->co_orig_3d, co_2d, sld->proj_mat); - - dist_sq = len_squared_v2v2(mval_fl, co_2d); - if (dist_sq < dist_min_sq) { - dist_min_sq = dist_sq; - sld->curr_sv_index = i; - } - } -} - -/** - * Run while moving the mouse to slide along the edge matching the mouse direction - */ -static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2]) -{ - VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; - float imval_fl[2] = {UNPACK2(t->mouse.imval)}; - float mval_fl[2] = {UNPACK2(mval)}; - - float dir[3]; - TransDataVertSlideVert *sv; - int i; - - /* note: we could save a matrix-multiply for each vertex - * by finding the closest edge in local-space. - * However this skews the outcome with non-uniform-scale. */ - - /* first get the direction of the original mouse position */ - sub_v2_v2v2(dir, imval_fl, mval_fl); - ED_view3d_win_to_delta(t->ar, dir, dir, t->zfac); - normalize_v3(dir); - - for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) { - if (sv->co_link_tot > 1) { - float dir_dot_best = -FLT_MAX; - int co_link_curr_best = -1; - int j; - - for (j = 0; j < sv->co_link_tot; j++) { - float tdir[3]; - float dir_dot; - - sub_v3_v3v3(tdir, sv->co_orig_3d, sv->co_link_orig_3d[j]); - mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, tdir); - project_plane_v3_v3v3(tdir, tdir, t->viewinv[2]); - - normalize_v3(tdir); - dir_dot = dot_v3v3(dir, tdir); - if (dir_dot > dir_dot_best) { - dir_dot_best = dir_dot; - co_link_curr_best = j; - } - } - - if (co_link_curr_best != -1) { - sv->co_link_curr = co_link_curr_best; - } - } - } -} - -static bool createVertSlideVerts(TransInfo *t, TransDataContainer *tc) -{ - BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); - BMesh *bm = em->bm; - BMIter iter; - BMIter eiter; - BMEdge *e; - BMVert *v; - TransDataVertSlideVert *sv_array; - VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld"); - int j; - - sld->curr_sv_index = 0; - - j = 0; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - bool ok = false; - if (BM_elem_flag_test(v, BM_ELEM_SELECT) && v->e) { - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { - ok = true; - break; - } - } - } - - if (ok) { - BM_elem_flag_enable(v, BM_ELEM_TAG); - j += 1; - } - else { - BM_elem_flag_disable(v, BM_ELEM_TAG); - } - } - - if (!j) { - MEM_freeN(sld); - return false; - } - - sv_array = MEM_callocN(sizeof(TransDataVertSlideVert) * j, "sv_array"); - - j = 0; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - int k; - sv_array[j].v = v; - copy_v3_v3(sv_array[j].co_orig_3d, v->co); - - k = 0; - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { - k++; - } - } - - sv_array[j].co_link_orig_3d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_3d) * k, - __func__); - sv_array[j].co_link_tot = k; - - k = 0; - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { - BMVert *v_other = BM_edge_other_vert(e, v); - copy_v3_v3(sv_array[j].co_link_orig_3d[k], v_other->co); - k++; - } - } - j++; - } - } - - sld->sv = sv_array; - sld->totsv = j; - - tc->custom.mode.data = sld; - - /* most likely will be set below */ - unit_m4(sld->proj_mat); - - if (t->spacetype == SPACE_VIEW3D) { - /* view vars */ - RegionView3D *rv3d = NULL; - ARegion *ar = t->ar; - - rv3d = ar ? ar->regiondata : NULL; - if (rv3d) { - ED_view3d_ob_project_mat_get(rv3d, tc->obedit, sld->proj_mat); - } - } - - /* XXX, calc vert slide across all objects */ - if (tc == t->data_container) { - calcVertSlideMouseActiveVert(t, t->mval); - calcVertSlideMouseActiveEdges(t, t->mval); - } - - return true; -} - -void projectVertSlideData(TransInfo *t, bool is_final) -{ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - trans_mesh_customdata_correction_apply(tc, is_final); - } -} - -void freeVertSlideVerts(TransInfo *UNUSED(t), - TransDataContainer *UNUSED(tc), - TransCustomData *custom_data) -{ - VertSlideData *sld = custom_data->data; - - if (!sld) { - return; - } - - if (sld->totsv > 0) { - TransDataVertSlideVert *sv = sld->sv; - int i = 0; - for (i = 0; i < sld->totsv; i++, sv++) { - MEM_freeN(sv->co_link_orig_3d); - } - } - - MEM_freeN(sld->sv); - MEM_freeN(sld); - - custom_data->data = NULL; -} - -static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp) -{ - - t->mode = TFM_VERT_SLIDE; - t->transform = applyVertSlide; - t->handleEvent = handleEventVertSlide; - - { - VertSlideParams *slp = MEM_callocN(sizeof(*slp), __func__); - slp->use_even = use_even; - slp->flipped = flipped; - slp->perc = 0.0f; - - if (!use_clamp) { - t->flag |= T_ALT_TRANSFORM; - } - - t->custom.mode.data = slp; - t->custom.mode.use_free = true; - } - - bool ok = false; - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - ok |= createVertSlideVerts(t, tc); - VertSlideData *sld = tc->custom.mode.data; - if (sld) { - tc->custom.mode.free_cb = freeVertSlideVerts; - } - } - - if (ok == false) { - t->state = TRANS_CANCEL; - return; - } - - trans_mesh_customdata_correction_init(t); - - /* set custom point first if you want value to be initialized by init */ - calcVertSlideCustomPoints(t); - initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - - t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; -} - -static void initVertSlide(TransInfo *t) -{ - initVertSlide_ex(t, false, false, true); -} - -static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event) -{ - if (t->mode == TFM_VERT_SLIDE) { - VertSlideParams *slp = t->custom.mode.data; - - if (slp) { - switch (event->type) { - case EKEY: - if (event->val == KM_PRESS) { - slp->use_even = !slp->use_even; - if (slp->flipped) { - calcVertSlideCustomPoints(t); - } - return TREDRAW_HARD; - } - break; - case FKEY: - if (event->val == KM_PRESS) { - slp->flipped = !slp->flipped; - calcVertSlideCustomPoints(t); - return TREDRAW_HARD; - } - break; - case CKEY: - /* use like a modifier key */ - if (event->val == KM_PRESS) { - t->flag ^= T_ALT_TRANSFORM; - calcVertSlideCustomPoints(t); - return TREDRAW_HARD; - } - break; -#if 0 - case EVT_MODAL_MAP: - switch (event->val) { - case TFM_MODAL_EDGESLIDE_DOWN: - sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv; - break; - case TFM_MODAL_EDGESLIDE_UP: - sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv; - break; - } - break; -#endif - case MOUSEMOVE: { - /* don't recalculate the best edge */ - const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); - if (is_clamp) { - calcVertSlideMouseActiveEdges(t, event->mval); - } - calcVertSlideCustomPoints(t); - break; - } - default: - break; - } - } - } - return TREDRAW_NOTHING; -} - -static void drawVertSlide(TransInfo *t) -{ - if ((t->mode == TFM_VERT_SLIDE) && TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data) { - const VertSlideParams *slp = t->custom.mode.data; - VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; - const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); - - /* Non-Prop mode */ - { - TransDataVertSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; - TransDataVertSlideVert *sv; - const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f; - const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f; - const int alpha_shade = -160; - int i; - - GPU_depth_test(false); - - GPU_blend(true); - GPU_blend_set_func_separate( - GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - - GPU_matrix_push(); - GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); - - GPU_line_width(line_size); - - const uint shdr_pos = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); - - immBegin(GPU_PRIM_LINES, sld->totsv * 2); - if (is_clamp) { - sv = sld->sv; - for (i = 0; i < sld->totsv; i++, sv++) { - immVertex3fv(shdr_pos, sv->co_orig_3d); - immVertex3fv(shdr_pos, sv->co_link_orig_3d[sv->co_link_curr]); - } - } - else { - sv = sld->sv; - for (i = 0; i < sld->totsv; i++, sv++) { - float a[3], b[3]; - sub_v3_v3v3(a, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d); - mul_v3_fl(a, 100.0f); - negate_v3_v3(b, a); - add_v3_v3(a, sv->co_orig_3d); - add_v3_v3(b, sv->co_orig_3d); - - immVertex3fv(shdr_pos, a); - immVertex3fv(shdr_pos, b); - } - } - immEnd(); - - GPU_point_size(ctrl_size); - - immBegin(GPU_PRIM_POINTS, 1); - immVertex3fv(shdr_pos, - (slp->flipped && slp->use_even) ? - curr_sv->co_link_orig_3d[curr_sv->co_link_curr] : - curr_sv->co_orig_3d); - immEnd(); - - immUnbindProgram(); - - /* direction from active vertex! */ - if ((t->mval[0] != t->mouse.imval[0]) || (t->mval[1] != t->mouse.imval[1])) { - float zfac; - float mval_ofs[2]; - float co_orig_3d[3]; - float co_dest_3d[3]; - - mval_ofs[0] = t->mval[0] - t->mouse.imval[0]; - mval_ofs[1] = t->mval[1] - t->mouse.imval[1]; - - mul_v3_m4v3( - co_orig_3d, TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, curr_sv->co_orig_3d); - zfac = ED_view3d_calc_zfac(t->ar->regiondata, co_orig_3d, NULL); - - ED_view3d_win_to_delta(t->ar, mval_ofs, co_dest_3d, zfac); - - invert_m4_m4(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, - TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); - mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, co_dest_3d); - - add_v3_v3(co_dest_3d, curr_sv->co_orig_3d); - - GPU_line_width(1.0f); - - immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); - - float viewport_size[4]; - GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); - - immUniform1i("colors_len", 0); /* "simple" mode */ - immUniformColor4f(1.0f, 1.0f, 1.0f, 1.0f); - immUniform1f("dash_width", 6.0f); - immUniform1f("dash_factor", 0.5f); - - immBegin(GPU_PRIM_LINES, 2); - immVertex3fv(shdr_pos, curr_sv->co_orig_3d); - immVertex3fv(shdr_pos, co_dest_3d); - immEnd(); - - immUnbindProgram(); - } - - GPU_matrix_pop(); - - GPU_depth_test(true); - } - } -} - -static void doVertSlide(TransInfo *t, float perc) -{ - VertSlideParams *slp = t->custom.mode.data; - - slp->perc = perc; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - VertSlideData *sld = tc->custom.mode.data; - TransDataVertSlideVert *svlist = sld->sv, *sv; - int i; - - sv = svlist; - - if (slp->use_even == false) { - for (i = 0; i < sld->totsv; i++, sv++) { - interp_v3_v3v3(sv->v->co, sv->co_orig_3d, sv->co_link_orig_3d[sv->co_link_curr], perc); - } - } - else { - TransDataVertSlideVert *sv_curr = &sld->sv[sld->curr_sv_index]; - const float edge_len_curr = len_v3v3(sv_curr->co_orig_3d, - sv_curr->co_link_orig_3d[sv_curr->co_link_curr]); - const float tperc = perc * edge_len_curr; - - for (i = 0; i < sld->totsv; i++, sv++) { - float edge_len; - float dir[3]; - - sub_v3_v3v3(dir, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d); - edge_len = normalize_v3(dir); - - if (edge_len > FLT_EPSILON) { - if (slp->flipped) { - madd_v3_v3v3fl(sv->v->co, sv->co_link_orig_3d[sv->co_link_curr], dir, -tperc); - } - else { - madd_v3_v3v3fl(sv->v->co, sv->co_orig_3d, dir, tperc); - } - } - else { - copy_v3_v3(sv->v->co, sv->co_orig_3d); - } - } - } - } -} - -static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2])) -{ - char str[UI_MAX_DRAW_STR]; - size_t ofs = 0; - float final; - VertSlideParams *slp = t->custom.mode.data; - const bool flipped = slp->flipped; - const bool use_even = slp->use_even; - const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); - const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num)); - - final = t->values[0]; - - snapGridIncrement(t, &final); - - /* only do this so out of range values are not displayed */ - if (is_constrained) { - CLAMP(final, 0.0f, 1.0f); - } - - applyNumInput(&t->num, &final); - - t->values_final[0] = final; - - /* header string */ - ofs += BLI_strncpy_rlen(str + ofs, TIP_("Vert Slide: "), sizeof(str) - ofs); - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, &t->scene->unit); - 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( - str + ofs, sizeof(str) - ofs, TIP_("(E)ven: %s, "), WM_bool_as_string(use_even)); - if (use_even) { - ofs += BLI_snprintf( - str + ofs, sizeof(str) - ofs, TIP_("(F)lipped: %s, "), WM_bool_as_string(flipped)); - } - ofs += BLI_snprintf( - str + ofs, sizeof(str) - ofs, TIP_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp)); - /* done with header string */ - - /* do stuff here */ - doVertSlide(t, final); - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (EditBone Roll) */ - -/** \name Transform EditBone Roll - * \{ */ - -static void initBoneRoll(TransInfo *t) -{ - t->mode = TFM_BONE_ROLL; - t->transform = applyBoneRoll; - - initMouseInputMode(t, &t->mouse, INPUT_ANGLE); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = DEG2RAD(5.0); - t->snap[2] = DEG2RAD(1.0); - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); - t->num.unit_type[0] = B_UNIT_ROTATION; - - t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; -} - -static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2])) -{ - int i; - char str[UI_MAX_DRAW_STR]; - - float final; - - final = t->values[0]; - - snapGridIncrement(t, &final); - - applyNumInput(&t->num, &final); - - t->values_final[0] = final; - - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - BLI_snprintf(str, sizeof(str), TIP_("Roll: %s"), &c[0]); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Roll: %.2f"), RAD2DEGF(final)); - } - - /* set roll values */ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - *(td->val) = td->ival - final; - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Bake-Time) */ - -/** \name Transform Bake-Time - * \{ */ - -static void initBakeTime(TransInfo *t) -{ - t->transform = applyBakeTime; - initMouseInputMode(t, &t->mouse, INPUT_NONE); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 1.0f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; /* Don't think this uses units? */ -} - -static void applyBakeTime(TransInfo *t, const int mval[2]) -{ - float time; - int i; - char str[UI_MAX_DRAW_STR]; - - float fac = 0.1f; - - /* XXX, disable precision for now, - * this isn't even accessible by the user */ -#if 0 - if (t->mouse.precision) { - /* calculate ratio for shiftkey pos, and for total, and blend these for precision */ - time = (float)(t->center2d[0] - t->mouse.precision_mval[0]) * fac; - time += 0.1f * ((float)(t->center2d[0] * fac - mval[0]) - time); - } - else -#endif - { - time = (float)(t->center2d[0] - mval[0]) * fac; - } - - snapGridIncrement(t, &time); - - applyNumInput(&t->num, &time); - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - if (time >= 0.0f) { - BLI_snprintf(str, sizeof(str), TIP_("Time: +%s %s"), c, t->proptext); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Time: %s %s"), c, t->proptext); - } - } - else { - /* default header print */ - if (time >= 0.0f) { - BLI_snprintf(str, sizeof(str), TIP_("Time: +%.3f %s"), time, t->proptext); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Time: %.3f %s"), time, t->proptext); - } - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (td->val) { - *td->val = td->ival + time * td->factor; - if (td->ext->size && *td->val < *td->ext->size) { - *td->val = *td->ext->size; - } - if (td->ext->quat && *td->val > *td->ext->quat) { - *td->val = *td->ext->quat; - } - } - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Mirror) */ - -/** \name Transform Mirror - * \{ */ - -static void initMirror(TransInfo *t) -{ - t->transform = applyMirror; - initMouseInputMode(t, &t->mouse, INPUT_NONE); - - t->flag |= T_NULL_ONE; - if ((t->flag & T_EDIT) == 0) { - t->flag |= T_NO_ZERO; - } -} - -static void applyMirror(TransInfo *t, const int UNUSED(mval[2])) -{ - float size[3], mat[3][3]; - int i; - char str[UI_MAX_DRAW_STR]; - copy_v3_v3(t->values_final, t->values); - - /* - * OPTIMIZATION: - * This still recalcs transformation on mouse move - * while it should only recalc on constraint change - * */ - - /* if an axis has been selected */ - if (t->con.mode & CON_APPLY) { - size[0] = size[1] = size[2] = -1; - - size_to_mat3(mat, size); - - if (t->con.applySize) { - t->con.applySize(t, NULL, NULL, mat); - } - - BLI_snprintf(str, sizeof(str), TIP_("Mirror%s"), t->con.text); - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - ElementResize(t, tc, td, mat); - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); - } - else { - size[0] = size[1] = size[2] = 1; - - size_to_mat3(mat, size); - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - ElementResize(t, tc, td, mat); - } - } - - recalcData(t); - - if (t->flag & T_2D_EDIT) { - ED_area_status_text(t->sa, TIP_("Select a mirror axis (X, Y)")); - } - else { - ED_area_status_text(t->sa, TIP_("Select a mirror axis (X, Y, Z)")); - } - } -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Align) */ - -/** \name Transform Align - * \{ */ - -static void initAlign(TransInfo *t) -{ - t->flag |= T_NO_CONSTRAINT; - - t->transform = applyAlign; - - initMouseInputMode(t, &t->mouse, INPUT_NONE); -} - -static void applyAlign(TransInfo *t, const int UNUSED(mval[2])) -{ - float center[3]; - int i; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - /* saving original center */ - copy_v3_v3(center, tc->center_local); - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - float mat[3][3], invmat[3][3]; - - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - /* around local centers */ - if (t->flag & (T_OBJECT | T_POSE)) { - copy_v3_v3(tc->center_local, td->center); - } - else { - if (t->settings->selectmode & SCE_SELECT_FACE) { - copy_v3_v3(tc->center_local, td->center); - } - } - - invert_m3_m3(invmat, td->axismtx); - - mul_m3_m3m3(mat, t->spacemtx, invmat); - - ElementRotation(t, tc, td, mat, t->around); - } - /* restoring original center */ - copy_v3_v3(tc->center_local, center); - } - - recalcData(t); - - ED_area_status_text(t->sa, TIP_("Align")); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Sequencer Slide) */ - -/** \name Transform Sequencer Slide - * \{ */ - -static void initSeqSlide(TransInfo *t) -{ - t->transform = applySeqSlide; - - initMouseInputMode(t, &t->mouse, INPUT_VECTOR); - - t->idx_max = 1; - t->num.flag = 0; - t->num.idx_max = t->idx_max; - - t->snap[0] = 0.0f; - t->snap[1] = floorf(t->scene->r.frs_sec / t->scene->r.frs_sec_base); - t->snap[2] = 10.0f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - /* Would be nice to have a time handling in units as well - * (supporting frames in addition to "natural" time...). */ - t->num.unit_type[0] = B_UNIT_NONE; - t->num.unit_type[1] = B_UNIT_NONE; -} - -static void headerSeqSlide(TransInfo *t, const float val[2], char str[UI_MAX_DRAW_STR]) -{ - char tvec[NUM_STR_REP_LEN * 3]; - size_t ofs = 0; - - if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, &t->scene->unit); - } - else { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.0f, %.0f", val[0], val[1]); - } - - ofs += BLI_snprintf( - str + ofs, UI_MAX_DRAW_STR - ofs, TIP_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text); - - if (t->keymap) { - wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE); - if (kmi) { - 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)); -} - -static void applySeqSlideValue(TransInfo *t, const float val[2]) -{ - int i; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - madd_v2_v2v2fl(td->loc, td->iloc, val, td->factor); - } - } -} - -static void applySeqSlide(TransInfo *t, const int mval[2]) -{ - char str[UI_MAX_DRAW_STR]; - - snapSequenceBounds(t, mval); - - if (t->con.mode & CON_APPLY) { - float pvec[3] = {0.0f, 0.0f, 0.0f}; - float tvec[3]; - t->con.applyVec(t, NULL, NULL, t->values, tvec, pvec); - copy_v3_v3(t->values_final, tvec); - } - else { - // snapGridIncrement(t, t->values); - applyNumInput(&t->num, t->values); - copy_v3_v3(t->values_final, t->values); - } - - t->values_final[0] = floorf(t->values_final[0] + 0.5f); - t->values_final[1] = floorf(t->values_final[1] + 0.5f); - - headerSeqSlide(t, t->values_final, str); - applySeqSlideValue(t, t->values_final); - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Animation Editors - Transform Utils - * - * Special Helpers for Various Settings - */ - -/** \name Animation Editor Utils - * \{ */ - -/* This function returns the snapping 'mode' for Animation Editors only - * We cannot use the standard snapping due to NLA-strip scaling complexities. - */ -// XXX these modifier checks should be keymappable -static short getAnimEdit_SnapMode(TransInfo *t) -{ - short autosnap = SACTSNAP_OFF; - - if (t->spacetype == SPACE_ACTION) { - SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first; - - if (saction) { - autosnap = saction->autosnap; - } - } - else if (t->spacetype == SPACE_GRAPH) { - SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first; - - if (sipo) { - autosnap = sipo->autosnap; - } - } - else if (t->spacetype == SPACE_NLA) { - SpaceNla *snla = (SpaceNla *)t->sa->spacedata.first; - - if (snla) { - autosnap = snla->autosnap; - } - } - else { - autosnap = SACTSNAP_OFF; - } - - /* toggle autosnap on/off - * - when toggling on, prefer nearest frame over 1.0 frame increments - */ - if (t->modifiers & MOD_SNAP_INVERT) { - if (autosnap) { - autosnap = SACTSNAP_OFF; - } - else { - autosnap = SACTSNAP_FRAME; - } - } - - return autosnap; -} - -/* This function is used by Animation Editor specific transform functions to do - * the Snap Keyframe to Nearest Frame/Marker - */ -static void doAnimEdit_SnapFrame( - TransInfo *t, TransData *td, TransData2D *td2d, AnimData *adt, short autosnap) -{ - if (ELEM(autosnap, SACTSNAP_FRAME, SACTSNAP_SECOND, SACTSNAP_MARKER)) { - float val; - - /* convert frame to nla-action time (if needed) */ - if (adt) { - val = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_MAP); - } - else { - val = *(td->val); - } - - snapFrameTransform(t, autosnap, true, val, &val); - - /* convert frame out of nla-action time */ - if (adt) { - *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP); - } - else { - *(td->val) = val; - } - } - - /* If the handles are to be moved too - * (as side-effect of keyframes moving, to keep the general effect) - * offset them by the same amount so that the general angles are maintained - * (i.e. won't change while handles are free-to-roam and keyframes are snap-locked). - */ - if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) { - td2d->h1[0] = td2d->ih1[0] + *td->val - td->ival; - } - if ((td->flag & TD_MOVEHANDLE2) && td2d->h2) { - td2d->h2[0] = td2d->ih2[0] + *td->val - td->ival; - } -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Animation Translation) */ - -/** \name Transform Animation Translation - * \{ */ - -static void initTimeTranslate(TransInfo *t) -{ - /* this tool is only really available in the Action Editor... */ - if (!ELEM(t->spacetype, SPACE_ACTION, SPACE_SEQ)) { - t->state = TRANS_CANCEL; - } - - t->mode = TFM_TIME_TRANSLATE; - t->transform = applyTimeTranslate; - - initMouseInputMode(t, &t->mouse, INPUT_NONE); - - /* num-input has max of (n-1) */ - t->idx_max = 0; - t->num.flag = 0; - t->num.idx_max = t->idx_max; - - /* initialize snap like for everything else */ - t->snap[0] = 0.0f; - t->snap[1] = t->snap[2] = 1.0f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - /* No time unit supporting frames currently... */ - t->num.unit_type[0] = B_UNIT_NONE; -} - -static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR]) -{ - char tvec[NUM_STR_REP_LEN * 3]; - int ofs = 0; - - /* if numeric input is active, use results from that, otherwise apply snapping to result */ - if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, &t->scene->unit); - } - else { - const short autosnap = getAnimEdit_SnapMode(t); - float val = t->values_final[0]; - - float snap_val; - snapFrameTransform(t, autosnap, false, val, &snap_val); - - if (autosnap == SACTSNAP_FRAME) { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", snap_val, val); - } - else if (autosnap == SACTSNAP_SECOND) { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", snap_val, val); - } - else if (autosnap == SACTSNAP_TSTEP) { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", snap_val); - } - else { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", snap_val); - } - } - - ofs += BLI_snprintf(str, UI_MAX_DRAW_STR, TIP_("DeltaX: %s"), &tvec[0]); - - if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf( - str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); - } -} - -static void applyTimeTranslateValue(TransInfo *t, float value) -{ - Scene *scene = t->scene; - int i; - - const short autosnap = getAnimEdit_SnapMode(t); - const double secf = FPS; - - float deltax, val /* , valprev */; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - TransData2D *td2d = tc->data_2d; - /* It doesn't matter whether we apply to t->data or - * t->data2d, but t->data2d is more convenient. */ - for (i = 0; i < tc->data_len; i++, td++, td2d++) { - /* It is assumed that td->extra is a pointer to the AnimData, - * whose active action is where this keyframe comes from. - * (this is only valid when not in NLA) - * (also: masks and gpencil dont have animadata) - */ - AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; - - /* valprev = *td->val; */ /* UNUSED */ - - /* check if any need to apply nla-mapping */ - if (adt && (t->spacetype != SPACE_SEQ)) { - deltax = value; - - if (autosnap == SACTSNAP_TSTEP) { - deltax = (float)(floor(((double)deltax / secf) + 0.5) * secf); - } - else if (autosnap == SACTSNAP_STEP) { - deltax = floorf(deltax + 0.5f); - } - - val = BKE_nla_tweakedit_remap(adt, td->ival, NLATIME_CONVERT_MAP); - val += deltax * td->factor; - *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP); - } - else { - deltax = val = t->values_final[0]; - - if (autosnap == SACTSNAP_TSTEP) { - val = (float)(floor(((double)deltax / secf) + 0.5) * secf); - } - else if (autosnap == SACTSNAP_STEP) { - val = floorf(val + 0.5f); - } - - *(td->val) = td->ival + val * td->factor; - } - - /* apply nearest snapping */ - doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap); - } - } -} - -static void applyTimeTranslate(TransInfo *t, const int mval[2]) -{ - View2D *v2d = (View2D *)t->view; - char str[UI_MAX_DRAW_STR]; - - /* calculate translation amount from mouse movement - in 'time-grid space' */ - if (t->flag & T_MODAL) { - float cval[2], sval[2]; - UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]); - UI_view2d_region_to_view(v2d, t->mouse.imval[0], t->mouse.imval[0], &sval[0], &sval[1]); - - /* we only need to calculate effect for time (applyTimeTranslate only needs that) */ - t->values[0] = cval[0] - sval[0]; - } - - /* handle numeric-input stuff */ - t->vec[0] = t->values[0]; - applyNumInput(&t->num, &t->vec[0]); - t->values_final[0] = t->vec[0]; - headerTimeTranslate(t, str); - - applyTimeTranslateValue(t, t->values_final[0]); - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Animation Time Slide) */ - -/** \name Transform Animation Time Slide - * \{ */ - -static void initTimeSlide(TransInfo *t) -{ - /* this tool is only really available in the Action Editor... */ - if (t->spacetype == SPACE_ACTION) { - SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first; - - /* set flag for drawing stuff */ - saction->flag |= SACTION_MOVING; - } - else { - t->state = TRANS_CANCEL; - } - - t->mode = TFM_TIME_SLIDE; - t->transform = applyTimeSlide; - - initMouseInputMode(t, &t->mouse, INPUT_NONE); - - { - Scene *scene = t->scene; - float *range; - t->custom.mode.data = range = MEM_mallocN(sizeof(float[2]), "TimeSlide Min/Max"); - t->custom.mode.use_free = true; - - float min = 999999999.0f, max = -999999999.0f; - int i; - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; - float val = *(td->val); - - /* strip/action time to global (mapped) time */ - if (adt) { - val = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_MAP); - } - - if (min > val) { - min = val; - } - if (max < val) { - max = val; - } - } - } - - if (min == max) { - /* just use the current frame ranges */ - min = (float)PSFRA; - max = (float)PEFRA; - } - - range[0] = min; - range[1] = max; - } - - /* num-input has max of (n-1) */ - t->idx_max = 0; - t->num.flag = 0; - t->num.idx_max = t->idx_max; - - /* initialize snap like for everything else */ - t->snap[0] = 0.0f; - t->snap[1] = t->snap[2] = 1.0f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - /* No time unit supporting frames currently... */ - t->num.unit_type[0] = B_UNIT_NONE; -} - -static void headerTimeSlide(TransInfo *t, const float sval, char str[UI_MAX_DRAW_STR]) -{ - char tvec[NUM_STR_REP_LEN * 3]; - - if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, &t->scene->unit); - } - else { - const float *range = t->custom.mode.data; - float minx = range[0]; - float maxx = range[1]; - float cval = t->values_final[0]; - float val; - - val = 2.0f * (cval - sval) / (maxx - minx); - CLAMP(val, -1.0f, 1.0f); - - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val); - } - - BLI_snprintf(str, UI_MAX_DRAW_STR, TIP_("TimeSlide: %s"), &tvec[0]); -} - -static void applyTimeSlideValue(TransInfo *t, float sval, float cval) -{ - int i; - const float *range = t->custom.mode.data; - float minx = range[0]; - float maxx = range[1]; - - /* set value for drawing black line */ - if (t->spacetype == SPACE_ACTION) { - SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first; - saction->timeslide = cval; - } - - /* It doesn't matter whether we apply to t->data or - * t->data2d, but t->data2d is more convenient. */ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - /* it is assumed that td->extra is a pointer to the AnimData, - * whose active action is where this keyframe comes from - * (this is only valid when not in NLA) - */ - AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; - - /* only apply to data if in range */ - if ((sval > minx) && (sval < maxx)) { - float cvalc = CLAMPIS(cval, minx, maxx); - float ival = td->ival; - float timefac; - - /* NLA mapping magic here works as follows: - * - "ival" goes from strip time to global time - * - calculation is performed into td->val in global time - * (since sval and min/max are all in global time) - * - "td->val" then gets put back into strip time - */ - if (adt) { - /* strip to global */ - ival = BKE_nla_tweakedit_remap(adt, ival, NLATIME_CONVERT_MAP); - } - - /* left half? */ - if (ival < sval) { - timefac = (sval - ival) / (sval - minx); - *(td->val) = cvalc - timefac * (cvalc - minx); - } - else { - timefac = (ival - sval) / (maxx - sval); - *(td->val) = cvalc + timefac * (maxx - cvalc); - } - - if (adt) { - /* global to strip */ - *(td->val) = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_UNMAP); - } - } - } - } -} - -static void applyTimeSlide(TransInfo *t, const int mval[2]) -{ - View2D *v2d = (View2D *)t->view; - float cval[2], sval[2]; - const float *range = t->custom.mode.data; - float minx = range[0]; - float maxx = range[1]; - char str[UI_MAX_DRAW_STR]; - - /* calculate mouse co-ordinates */ - UI_view2d_region_to_view(v2d, mval[0], mval[1], &cval[0], &cval[1]); - UI_view2d_region_to_view(v2d, t->mouse.imval[0], t->mouse.imval[1], &sval[0], &sval[1]); - - /* t->values_final[0] stores cval[0], which is the current mouse-pointer location (in frames) */ - // XXX Need to be able to repeat this - /* t->values_final[0] = cval[0]; */ /* UNUSED (reset again later). */ - - /* handle numeric-input stuff */ - t->vec[0] = 2.0f * (cval[0] - sval[0]) / (maxx - minx); - applyNumInput(&t->num, &t->vec[0]); - t->values_final[0] = (maxx - minx) * t->vec[0] / 2.0f + sval[0]; - - headerTimeSlide(t, sval[0], str); - applyTimeSlideValue(t, sval[0], t->values_final[0]); - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Animation Time Scale) */ - -/** \name Transform Animation Time Scale - * \{ */ - -static void initTimeScale(TransInfo *t) -{ - float center[2]; - - /* this tool is only really available in the Action Editor - * AND NLA Editor (for strip scaling) - */ - if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA) == 0) { - t->state = TRANS_CANCEL; - } - - t->mode = TFM_TIME_SCALE; - t->transform = applyTimeScale; - - /* recalculate center2d to use CFRA and mouse Y, since that's - * what is used in time scale */ - if ((t->flag & T_OVERRIDE_CENTER) == 0) { - t->center_global[0] = t->scene->r.cfra; - projectFloatView(t, t->center_global, center); - center[1] = t->mouse.imval[1]; - } - - /* force a reinit with the center2d used here */ - initMouseInput(t, &t->mouse, center, t->mouse.imval, false); - - initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP); - - t->flag |= T_NULL_ONE; - t->num.val_flag[0] |= NUM_NULL_ONE; - - /* num-input has max of (n-1) */ - t->idx_max = 0; - t->num.flag = 0; - t->num.idx_max = t->idx_max; - - /* initialize snap like for everything else */ - t->snap[0] = 0.0f; - t->snap[1] = t->snap[2] = 1.0f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; -} - -static void headerTimeScale(TransInfo *t, char str[UI_MAX_DRAW_STR]) -{ - char tvec[NUM_STR_REP_LEN * 3]; - - if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, &t->scene->unit); - } - else { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", t->values_final[0]); - } - - BLI_snprintf(str, UI_MAX_DRAW_STR, TIP_("ScaleX: %s"), &tvec[0]); -} - -static void applyTimeScaleValue(TransInfo *t, float value) -{ - Scene *scene = t->scene; - int i; - - const short autosnap = getAnimEdit_SnapMode(t); - const double secf = FPS; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - TransData2D *td2d = tc->data_2d; - for (i = 0; i < tc->data_len; i++, td++, td2d++) { - /* it is assumed that td->extra is a pointer to the AnimData, - * whose active action is where this keyframe comes from - * (this is only valid when not in NLA) - */ - AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; - float startx = CFRA; - float fac = value; - - if (autosnap == SACTSNAP_TSTEP) { - fac = (float)(floor((double)fac / secf + 0.5) * secf); - } - else if (autosnap == SACTSNAP_STEP) { - fac = floorf(fac + 0.5f); - } - - /* take proportional editing into account */ - fac = ((fac - 1.0f) * td->factor) + 1; - - /* check if any need to apply nla-mapping */ - if (adt) { - startx = BKE_nla_tweakedit_remap(adt, startx, NLATIME_CONVERT_UNMAP); - } - - /* now, calculate the new value */ - *(td->val) = ((td->ival - startx) * fac) + startx; - - /* apply nearest snapping */ - doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap); - } - } -} - -static void applyTimeScale(TransInfo *t, const int UNUSED(mval[2])) -{ - char str[UI_MAX_DRAW_STR]; - - /* handle numeric-input stuff */ - t->vec[0] = t->values[0]; - applyNumInput(&t->num, &t->vec[0]); - t->values_final[0] = t->vec[0]; - headerTimeScale(t, str); - - applyTimeScaleValue(t, t->values_final[0]); - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - /* TODO, move to: transform_query.c */ bool checkUseAxisMatrix(TransInfo *t) { |