diff options
Diffstat (limited to 'source/blender/editors/transform')
24 files changed, 1224 insertions, 1009 deletions
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index b02b1814c67..eb60273fc79 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -526,8 +526,11 @@ static void viewRedrawPost(bContext *C, TransInfo *t) } /* redraw UV editor */ - if (ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE) && - (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) { + const char uvcalc_correct_flag = ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE) ? + UVCALC_TRANSFORM_CORRECT_SLIDE : + UVCALC_TRANSFORM_CORRECT; + + if ((t->data_type == TC_MESH_VERTS) && (t->settings->uvcalc_flag & uvcalc_correct_flag)) { WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); } @@ -1591,17 +1594,24 @@ static void drawTransformPixel(const struct bContext *C, ARegion *region, void * void saveTransform(bContext *C, TransInfo *t, wmOperator *op) { ToolSettings *ts = CTX_data_tool_settings(C); - int proportional = 0; PropertyRNA *prop; if (!(t->con.mode & CON_APPLY) && (t->flag & T_MODAL) && ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE)) { /* When redoing these modes the first time, it's more convenient to save - * the Global orientation. */ - mul_m3_v3(t->spacemtx, t->values_final); - unit_m3(t->spacemtx); + * in the Global orientation. */ + if (t->mode == TFM_TRANSLATION) { + mul_m3_v3(t->spacemtx, t->values_final); + } + else { + float tmat[3][3], sizemat[3][3]; + size_to_mat3(sizemat, t->values_final); + mul_m3_m3m3(tmat, t->spacemtx, sizemat); + mat3_to_size(t->values_final, tmat); + } BLI_assert(t->orient_curr == 0); + unit_m3(t->spacemtx); t->orient[0].type = V3D_ORIENT_GLOBAL; } @@ -1619,15 +1629,17 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } } + bool use_prop_edit = false; + int prop_edit_flag = 0; if (t->flag & T_PROP_EDIT_ALL) { if (t->flag & T_PROP_EDIT) { - proportional |= PROP_EDIT_USE; + use_prop_edit = true; } if (t->flag & T_PROP_CONNECTED) { - proportional |= PROP_EDIT_CONNECTED; + prop_edit_flag |= PROP_EDIT_CONNECTED; } if (t->flag & T_PROP_PROJECTED) { - proportional |= PROP_EDIT_PROJECTED; + prop_edit_flag |= PROP_EDIT_PROJECTED; } } @@ -1639,20 +1651,27 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) if (!(t->options & CTX_NO_PET)) { if ((prop = RNA_struct_find_property(op->ptr, "use_proportional_edit")) && !RNA_property_is_set(op->ptr, prop)) { + const Object *obact = OBACT(t->view_layer); + if (t->spacetype == SPACE_GRAPH) { - ts->proportional_fcurve = proportional; + ts->proportional_fcurve = use_prop_edit; } else if (t->spacetype == SPACE_ACTION) { - ts->proportional_action = proportional; - } - else if (t->obedit_type != -1) { - ts->proportional_edit = proportional; + ts->proportional_action = use_prop_edit; } else if (t->options & CTX_MASK) { - ts->proportional_mask = proportional != 0; + ts->proportional_mask = use_prop_edit; } - else if ((t->options & CTX_CURSOR) == 0) { - ts->proportional_objects = proportional != 0; + else if (obact && obact->mode == OB_MODE_OBJECT) { + ts->proportional_objects = use_prop_edit; + } + else { + if (use_prop_edit) { + ts->proportional_edit |= PROP_EDIT_USE; + } + else { + ts->proportional_edit &= ~PROP_EDIT_USE; + } } } @@ -1685,9 +1704,9 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } if ((prop = RNA_struct_find_property(op->ptr, "use_proportional_edit"))) { - RNA_property_boolean_set(op->ptr, prop, proportional & PROP_EDIT_USE); - RNA_boolean_set(op->ptr, "use_proportional_connected", proportional & PROP_EDIT_CONNECTED); - RNA_boolean_set(op->ptr, "use_proportional_projected", proportional & PROP_EDIT_PROJECTED); + RNA_property_boolean_set(op->ptr, prop, use_prop_edit); + RNA_boolean_set(op->ptr, "use_proportional_connected", prop_edit_flag & PROP_EDIT_CONNECTED); + RNA_boolean_set(op->ptr, "use_proportional_projected", prop_edit_flag & PROP_EDIT_PROJECTED); RNA_enum_set(op->ptr, "proportional_edit_falloff", t->prop_mode); RNA_float_set(op->ptr, "proportional_size", t->prop_size); } @@ -1768,7 +1787,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) if ((prop = RNA_struct_find_property(op->ptr, "correct_uv"))) { RNA_property_boolean_set( - op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) != 0); + op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT_SLIDE) != 0); } } @@ -1819,6 +1838,8 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve int options = 0; PropertyRNA *prop; + mode = transform_mode_really_used(C, mode); + t->context = C; /* added initialize, for external calls to set stuff in TransInfo, like undo string */ diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 838c1880881..66b90eb159f 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -79,6 +79,27 @@ static void projection_matrix_calc(const TransInfo *t, float r_pmtx[3][3]) } /* ************************** CONSTRAINTS ************************* */ +#define CONSTRAIN_EPSILON 0.0001f + +static void constraint_plane_calc(TransInfo *t, float r_plane[4]) +{ + const float *constraint_vector[2]; + int n = 0; + for (int i = 0; i < 3; i++) { + if (t->con.mode & (CON_AXIS0 << i)) { + constraint_vector[n++] = t->spacemtx[i]; + if (n == 2) { + break; + } + } + } + BLI_assert(n == 2); + + cross_v3_v3v3(r_plane, constraint_vector[0], constraint_vector[1]); + normalize_v3(r_plane); + r_plane[3] = -dot_v3v3(r_plane, t->center_global); +} + static void constraintValuesFinal(TransInfo *t, float vec[3]) { int mode = t->con.mode; @@ -297,32 +318,83 @@ static void axisProjection(const TransInfo *t, } /** - * Return true if the 2x axis are both aligned when projected into the view. - * In this case, we can't usefully project the cursor onto the plane. + * Snap to the intersection between the edge direction and the constraint plane. */ -static bool isPlaneProjectionViewAligned(const TransInfo *t) +static void constraint_snap_plane_to_edge(const TransInfo *t, const float plane[4], float r_out[3]) { - const float eps = 0.001f; - const float *constraint_vector[2]; - int n = 0; - for (int i = 0; i < 3; i++) { - if (t->con.mode & (CON_AXIS0 << i)) { - constraint_vector[n++] = t->spacemtx[i]; - if (n == 2) { - break; - } - } + float lambda; + const float *edge_snap_point = t->tsnap.snapPoint; + const float *edge_dir = t->tsnap.snapNormal; + bool is_aligned = fabsf(dot_v3v3(edge_dir, plane)) < CONSTRAIN_EPSILON; + if (!is_aligned && isect_ray_plane_v3(edge_snap_point, edge_dir, plane, &lambda, false)) { + madd_v3_v3v3fl(r_out, edge_snap_point, edge_dir, lambda); + sub_v3_v3(r_out, t->tsnap.snapTarget); } - BLI_assert(n == 2); +} + +/** + * Snap to the nearest point between the snap point and the line that + * intersects the face plane with the constraint plane. + */ +static void constraint_snap_plane_to_face(const TransInfo *t, const float plane[4], float r_out[3]) +{ + float face_plane[4], isect_orig[3], isect_dir[3]; + const float *face_snap_point = t->tsnap.snapPoint; + const float *face_normal = t->tsnap.snapNormal; + plane_from_point_normal_v3(face_plane, face_snap_point, face_normal); + bool is_aligned = fabsf(dot_v3v3(plane, face_plane)) > (1.0f - CONSTRAIN_EPSILON); + if (!is_aligned && isect_plane_plane_v3(plane, face_plane, isect_orig, isect_dir)) { + closest_to_ray_v3(r_out, face_snap_point, isect_orig, isect_dir); + sub_v3_v3(r_out, t->tsnap.snapTarget); + } +} - float view_to_plane[3], plane_normal[3]; +/** + * Snap to the nearest point on the axis to the edge/line element. + */ +void transform_constraint_snap_axis_to_edge(const TransInfo *t, + const float axis[3], + float r_out[3]) +{ + float lambda; + const float *edge_snap_point = t->tsnap.snapPoint; + const float *edge_dir = t->tsnap.snapNormal; + bool is_aligned = fabsf(dot_v3v3(axis, edge_dir)) > (1.0f - CONSTRAIN_EPSILON); + if (!is_aligned && + isect_ray_ray_v3(t->tsnap.snapTarget, axis, edge_snap_point, edge_dir, &lambda, NULL)) { + mul_v3_v3fl(r_out, axis, lambda); + } +} - getViewVector(t, t->center_global, view_to_plane); +/** + * Snap to the intersection of the axis and the plane defined by the face. + */ +void transform_constraint_snap_axis_to_face(const TransInfo *t, + const float axis[3], + float r_out[3]) +{ + float lambda; + float face_plane[4]; + const float *face_snap_point = t->tsnap.snapPoint; + const float *face_normal = t->tsnap.snapNormal; + plane_from_point_normal_v3(face_plane, face_snap_point, face_normal); + bool is_aligned = fabsf(dot_v3v3(axis, face_plane)) < CONSTRAIN_EPSILON; + if (!is_aligned && isect_ray_plane_v3(t->tsnap.snapTarget, axis, face_plane, &lambda, false)) { + mul_v3_v3fl(r_out, axis, lambda); + } +} - cross_v3_v3v3(plane_normal, constraint_vector[0], constraint_vector[1]); - normalize_v3(plane_normal); +/** + * Return true if the 2x axis are both aligned when projected into the view. + * In this case, we can't usefully project the cursor onto the plane. + */ +static bool isPlaneProjectionViewAligned(const TransInfo *t, float plane[4]) +{ + const float eps = 0.001f; + float view_to_plane[3]; + getViewVector(t, t->center_global, view_to_plane); - float factor = dot_v3v3(plane_normal, view_to_plane); + float factor = dot_v3v3(plane, view_to_plane); return fabsf(factor) < eps; } @@ -361,14 +433,31 @@ static void applyAxisConstraintVec( copy_v3_v3(out, in); if (!td && t->con.mode & CON_APPLY) { mul_m3_v3(t->con.pmtx, out); + bool is_snap_to_edge = false, is_snap_to_face = false; + if (activeSnap(t)) { + is_snap_to_edge = (t->tsnap.snapElem & SCE_SNAP_MODE_EDGE) != 0; + is_snap_to_face = (t->tsnap.snapElem & SCE_SNAP_MODE_FACE) != 0; + } - // With snap, a projection is alright, no need to correct for view alignment - if (!validSnap(t)) { + /* With snap points, a projection is alright, no adjustments needed. */ + if (!validSnap(t) || is_snap_to_edge || is_snap_to_face) { const int dims = getConstraintSpaceDimension(t); if (dims == 2) { if (!is_zero_v3(out)) { - if (!isPlaneProjectionViewAligned(t)) { - planeProjection(t, in, out); + float plane[4]; + constraint_plane_calc(t, plane); + + if (is_snap_to_edge) { + constraint_snap_plane_to_edge(t, plane, out); + } + else if (is_snap_to_face) { + constraint_snap_plane_to_face(t, plane, out); + } + else { + /* View alignment correction. */ + if (!isPlaneProjectionViewAligned(t, plane)) { + planeProjection(t, in, out); + } } } } @@ -384,7 +473,17 @@ static void applyAxisConstraintVec( else if (t->con.mode & CON_AXIS2) { copy_v3_v3(c, t->spacemtx[2]); } - axisProjection(t, c, in, out); + + if (is_snap_to_edge) { + transform_constraint_snap_axis_to_edge(t, c, out); + } + else if (is_snap_to_face) { + transform_constraint_snap_axis_to_face(t, c, out); + } + else { + /* View alignment correction. */ + axisProjection(t, c, in, out); + } } } postConstraintChecks(t, out); @@ -779,12 +878,21 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - immUniformThemeColor(TH_GRID); + immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); + + float viewport[4]; + GPU_viewport_size_get_f(viewport); + GPU_blend(true); + + immUniform2fv("viewportSize", &viewport[2]); + immUniform1f("lineWidth", 3.0f * U.pixelsize); + + immUniformThemeColorShadeAlpha(TH_GRID, -20, 255); + imm_drawcircball(t->center_global, t->prop_size, imat, pos); - GPU_logic_op_invert_set(true); + immUniform1f("lineWidth", 1.0f * U.pixelsize); + immUniformThemeColorShadeAlpha(TH_GRID, 20, 255); imm_drawcircball(t->center_global, t->prop_size, imat, pos); - GPU_logic_op_invert_set(false); immUnbindProgram(); diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h index c41b9361ca4..282060af2c3 100644 --- a/source/blender/editors/transform/transform_constraints.h +++ b/source/blender/editors/transform/transform_constraints.h @@ -27,6 +27,12 @@ struct TransInfo; void constraintNumInput(TransInfo *t, float vec[3]); +void transform_constraint_snap_axis_to_edge(const TransInfo *t, + const float axis[3], + float r_out[3]); +void transform_constraint_snap_axis_to_face(const TransInfo *t, + const float axis[3], + float r_out[3]); void setConstraint(TransInfo *t, int mode, const char text[]); void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]); void setLocalConstraint(TransInfo *t, int mode, const char text[]); diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 064057990e0..5d1fd1543df 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -774,7 +774,7 @@ bool constraints_list_needinv(TransInfo *t, ListBase *list) bConstraint *con; /* loop through constraints, checking if there's one of the mentioned - * constraints needing special crazyspace corrections + * constraints needing special crazy-space corrections */ if (list) { for (con = list->first; con; con = con->next) { @@ -1148,21 +1148,6 @@ void createTransData(bContext *C, TransInfo *t) } t->flag |= T_OBJECT; - - /* Check if we're transforming the camera from the camera */ - if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { - View3D *v3d = t->view; - RegionView3D *rv3d = t->region->regiondata; - if ((rv3d->persp == RV3D_CAMOB) && v3d->camera) { - /* we could have a flag to easily check an object is being transformed */ - if (v3d->camera->id.tag & LIB_TAG_DOIT) { - t->flag |= T_CAMERA; - } - } - else if (v3d->ob_center && v3d->ob_center->id.tag & LIB_TAG_DOIT) { - t->flag |= T_CAMERA; - } - } convert_type = TC_OBJECT; } @@ -1175,6 +1160,7 @@ void createTransData(bContext *C, TransInfo *t) break; case TC_POSE: createTransPose(t); + /* Disable PET, its not usable in pose mode yet [#32444] */ init_prop_edit = false; break; case TC_ARMATURE_VERTS: @@ -1224,6 +1210,20 @@ void createTransData(bContext *C, TransInfo *t) break; case TC_OBJECT: createTransObject(C, t); + /* Check if we're transforming the camera from the camera */ + if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { + View3D *v3d = t->view; + RegionView3D *rv3d = t->region->regiondata; + if ((rv3d->persp == RV3D_CAMOB) && v3d->camera) { + /* we could have a flag to easily check an object is being transformed */ + if (v3d->camera->id.tag & LIB_TAG_DOIT) { + t->flag |= T_CAMERA; + } + } + else if (v3d->ob_center && v3d->ob_center->id.tag & LIB_TAG_DOIT) { + t->flag |= T_CAMERA; + } + } break; case TC_OBJECT_TEXSPACE: createTransTexspace(t); @@ -1292,18 +1292,9 @@ void createTransData(bContext *C, TransInfo *t) * and are still added into transform data. */ sort_trans_data_selected_first(t); } - } - - /* exception... hackish, we want bonesize to use bone orientation matrix (ton) */ - if (t->mode == TFM_BONESIZE) { - t->flag &= ~(T_EDIT | T_POINTS); - t->flag |= T_POSE; - t->obedit_type = -1; - t->data_type = TC_NONE; - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - tc->poseobj = tc->obedit; - tc->obedit = NULL; + if (!init_prop_edit) { + t->flag &= ~T_PROP_EDIT_ALL; } } diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index a94bd609d94..f7eea286983 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -47,7 +47,7 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize); void clipUVData(TransInfo *t); /* transform_convert_mesh.c */ -void trans_mesh_customdata_correction_init(TransInfo *t, struct TransDataContainer *tc); +void trans_mesh_customdata_correction_init(TransInfo *t); /* transform_convert_sequencer.c */ int transform_convert_sequencer_get_snap_bound(TransInfo *t); diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index 75b51b3d2c4..f721ed0b866 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -553,8 +553,7 @@ static void pose_mirror_info_init(PoseInitData_Mirror *pid, /** \name Convert Armature * \{ */ -static void add_pose_transdata( - TransInfo *t, bPoseChannel *pchan, Object *ob, TransDataContainer *tc, TransData *td) +static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, TransData *td) { Bone *bone = pchan->bone; float pmat[3][3], omat[3][3]; @@ -667,20 +666,16 @@ static void add_pose_transdata( mul_m3_m3m3(td->axismtx, omat, pmat); normalize_m3(td->axismtx); - if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) { - bArmature *arm = tc->poseobj->data; - - if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) { - td->loc = NULL; - td->val = &bone->dist; - td->ival = bone->dist; - } - else { - // abusive storage of scale in the loc pointer :) - td->loc = &bone->xwidth; - copy_v3_v3(td->iloc, td->loc); - td->val = NULL; - } + if (t->mode == TFM_BONE_ENVELOPE_DIST) { + td->loc = NULL; + td->val = &bone->dist; + td->ival = bone->dist; + } + else if (t->mode == TFM_BONESIZE) { + // abusive storage of scale in the loc pointer :) + td->loc = &bone->xwidth; + copy_v3_v3(td->iloc, td->loc); + td->val = NULL; } /* in this case we can do target-less IK grabbing */ @@ -836,7 +831,7 @@ void createTransPose(TransInfo *t) td = tc->data; LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { if (pchan->bone->flag & BONE_TRANSFORM) { - add_pose_transdata(t, pchan, ob, tc, td); + add_pose_transdata(t, pchan, ob, td); td++; } } @@ -862,8 +857,6 @@ void createTransPose(TransInfo *t) } t->flag |= T_POSE; - /* disable PET, its not usable in pose mode yet [#32444] */ - t->flag &= ~T_PROP_EDIT_ALL; } void createTransArmatureVerts(TransInfo *t) @@ -988,7 +981,7 @@ void createTransArmatureVerts(TransInfo *t) } else if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) { if (ebo->flag & BONE_SELECTED) { - if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) { + if (t->mode == TFM_BONE_ENVELOPE_DIST) { td->loc = NULL; td->val = &ebo->dist; td->ival = ebo->dist; diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c index 6c03f86f883..37e37072ed7 100644 --- a/source/blender/editors/transform/transform_convert_curve.c +++ b/source/blender/editors/transform/transform_convert_curve.c @@ -87,7 +87,7 @@ void createTransCurveVerts(TransInfo *t) t->data_len_all = 0; - /* Count control points (one per bez-triple) if any number of handles are selected. + /* Count control points (one per #BezTriple) if any number of handles are selected. * Needed for #transform_around_single_fallback_ex. */ int data_len_all_pt = 0; diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c index 66c27bca207..6f34c49bdac 100644 --- a/source/blender/editors/transform/transform_convert_mask.c +++ b/source/blender/editors/transform/transform_convert_mask.c @@ -149,7 +149,7 @@ static void MaskPointToTransData(Scene *scene, /* CV coords are scaled by aspects. this is needed for rotations and * proportional editing to be consistent with the stretched CV coords - * that are displayed. this also means that for display and numinput, + * that are displayed. this also means that for display and number-input, * and when the CV coords are flushed, these are converted each time */ mul_v2_m3v2(td2d->loc, parent_matrix, bezt->vec[i]); td2d->loc[0] *= asp[0]; diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index 27ddad262f7..1c286415ea6 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -50,10 +50,11 @@ /* Own include. */ #include "transform_convert.h" -/* Used for both mirror epsilon and TD_MIRROR_EDGE_ */ -#define TRANSFORM_MAXDIST_MIRROR 0.00002f +/* -------------------------------------------------------------------- */ +/** \name Island Creation + * + * \{ */ -/* when transforming islands */ struct TransIslandData { float (*center)[3]; float (*axismtx)[3][3]; @@ -61,8 +62,186 @@ struct TransIslandData { int *island_vert_map; }; +static void editmesh_islands_info_calc(BMEditMesh *em, + const bool calc_single_islands, + const bool calc_island_center, + const bool calc_island_axismtx, + struct TransIslandData *r_island_data) +{ + BMesh *bm = em->bm; + char htype; + char itype; + int i; + + /* group vars */ + float(*center)[3] = NULL; + float(*axismtx)[3][3] = NULL; + int *groups_array; + int(*group_index)[2]; + int group_tot; + void **ele_array; + + int *vert_map; + + if (em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) { + groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totedgesel, __func__); + group_tot = BM_mesh_calc_edge_groups( + bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT); + + htype = BM_EDGE; + itype = BM_VERTS_OF_EDGE; + } + else { /* (bm->selectmode & SCE_SELECT_FACE) */ + groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__); + group_tot = BM_mesh_calc_face_groups( + bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT, BM_VERT); + + htype = BM_FACE; + itype = BM_VERTS_OF_FACE; + } + + if (calc_island_center) { + center = MEM_mallocN(sizeof(*center) * group_tot, __func__); + } + + if (calc_island_axismtx) { + axismtx = MEM_mallocN(sizeof(*axismtx) * group_tot, __func__); + } + + vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__); + /* we shouldn't need this, but with incorrect selection flushing + * its possible we have a selected vertex that's not in a face, + * for now best not crash in that case. */ + copy_vn_i(vert_map, bm->totvert, -1); + + BM_mesh_elem_table_ensure(bm, htype); + ele_array = (htype == BM_FACE) ? (void **)bm->ftable : (void **)bm->etable; + + BM_mesh_elem_index_ensure(bm, BM_VERT); + + /* may be an edge OR a face array */ + for (i = 0; i < group_tot; i++) { + BMEditSelection ese = {NULL}; + + const int fg_sta = group_index[i][0]; + const int fg_len = group_index[i][1]; + float co[3], no[3], tangent[3]; + int j; + + zero_v3(co); + zero_v3(no); + zero_v3(tangent); + + ese.htype = htype; + + /* loop on each face or edge in this group: + * - assign r_vert_map + * - calculate (co, no) + */ + for (j = 0; j < fg_len; j++) { + ese.ele = ele_array[groups_array[fg_sta + j]]; + + if (center) { + float tmp_co[3]; + BM_editselection_center(&ese, tmp_co); + add_v3_v3(co, tmp_co); + } + + if (axismtx) { + float tmp_no[3], tmp_tangent[3]; + BM_editselection_normal(&ese, tmp_no); + BM_editselection_plane(&ese, tmp_tangent); + add_v3_v3(no, tmp_no); + add_v3_v3(tangent, tmp_tangent); + } + + { + /* setup vertex map */ + BMIter iter; + BMVert *v; + + /* connected edge-verts */ + BM_ITER_ELEM (v, &iter, ese.ele, itype) { + vert_map[BM_elem_index_get(v)] = i; + } + } + } + + if (center) { + mul_v3_v3fl(center[i], co, 1.0f / (float)fg_len); + } + + if (axismtx) { + if (createSpaceNormalTangent(axismtx[i], no, tangent)) { + /* pass */ + } + else { + if (normalize_v3(no) != 0.0f) { + axis_dominant_v3_to_m3(axismtx[i], no); + invert_m3(axismtx[i]); + } + else { + unit_m3(axismtx[i]); + } + } + } + } + + MEM_freeN(groups_array); + MEM_freeN(group_index); + + /* for PET we need islands of 1 so connected vertices can use it with V3D_AROUND_LOCAL_ORIGINS */ + if (calc_single_islands) { + BMIter viter; + BMVert *v; + int group_tot_single = 0; + + BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) { + group_tot_single += 1; + } + } + + if (group_tot_single != 0) { + if (center) { + center = MEM_reallocN(center, sizeof(*center) * (group_tot + group_tot_single)); + } + if (axismtx) { + axismtx = MEM_reallocN(axismtx, sizeof(*axismtx) * (group_tot + group_tot_single)); + } + + BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) { + vert_map[i] = group_tot; + if (center) { + copy_v3_v3(center[group_tot], v->co); + } + if (axismtx) { + if (is_zero_v3(v->no) != 0.0f) { + axis_dominant_v3_to_m3(axismtx[group_tot], v->no); + invert_m3(axismtx[group_tot]); + } + else { + unit_m3(axismtx[group_tot]); + } + } + + group_tot += 1; + } + } + } + } + + r_island_data->axismtx = axismtx; + r_island_data->center = center; + r_island_data->island_tot = group_tot; + r_island_data->island_vert_map = vert_map; +} + +/** \} */ + /* -------------------------------------------------------------------- */ -/** \name Edit Mesh Verts Transform Creation +/** \name Connectivity Distance for Proportional Editing * * \{ */ @@ -243,171 +422,25 @@ static void editmesh_set_connectivity_distance(BMesh *bm, } } -static void editmesh_islands_info_calc(BMEditMesh *em, - const bool calc_single_islands, - const bool calc_island_axismtx, - struct TransIslandData *r_island_data) -{ - BMesh *bm = em->bm; - char htype; - char itype; - int i; - - /* group vars */ - float(*center)[3]; - float(*axismtx)[3][3] = NULL; - int *groups_array; - int(*group_index)[2]; - int group_tot; - void **ele_array; - - int *vert_map; - - if (em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) { - groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totedgesel, __func__); - group_tot = BM_mesh_calc_edge_groups( - bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT); - - htype = BM_EDGE; - itype = BM_VERTS_OF_EDGE; - } - else { /* (bm->selectmode & SCE_SELECT_FACE) */ - groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__); - group_tot = BM_mesh_calc_face_groups( - bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT, BM_VERT); - - htype = BM_FACE; - itype = BM_VERTS_OF_FACE; - } - - center = MEM_mallocN(sizeof(*center) * group_tot, __func__); - - if (calc_island_axismtx) { - axismtx = MEM_mallocN(sizeof(*axismtx) * group_tot, __func__); - } - - vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__); - /* we shouldn't need this, but with incorrect selection flushing - * its possible we have a selected vertex that's not in a face, - * for now best not crash in that case. */ - copy_vn_i(vert_map, bm->totvert, -1); - - BM_mesh_elem_table_ensure(bm, htype); - ele_array = (htype == BM_FACE) ? (void **)bm->ftable : (void **)bm->etable; - - BM_mesh_elem_index_ensure(bm, BM_VERT); - - /* may be an edge OR a face array */ - for (i = 0; i < group_tot; i++) { - BMEditSelection ese = {NULL}; - - const int fg_sta = group_index[i][0]; - const int fg_len = group_index[i][1]; - float co[3], no[3], tangent[3]; - int j; - - zero_v3(co); - zero_v3(no); - zero_v3(tangent); - - ese.htype = htype; - - /* loop on each face or edge in this group: - * - assign r_vert_map - * - calculate (co, no) - */ - for (j = 0; j < fg_len; j++) { - float tmp_co[3], tmp_no[3], tmp_tangent[3]; - - ese.ele = ele_array[groups_array[fg_sta + j]]; - - BM_editselection_center(&ese, tmp_co); - add_v3_v3(co, tmp_co); - - if (axismtx) { - BM_editselection_normal(&ese, tmp_no); - BM_editselection_plane(&ese, tmp_tangent); - add_v3_v3(no, tmp_no); - add_v3_v3(tangent, tmp_tangent); - } - - { - /* setup vertex map */ - BMIter iter; - BMVert *v; - - /* connected edge-verts */ - BM_ITER_ELEM (v, &iter, ese.ele, itype) { - vert_map[BM_elem_index_get(v)] = i; - } - } - } - - mul_v3_v3fl(center[i], co, 1.0f / (float)fg_len); - - if (axismtx) { - if (createSpaceNormalTangent(axismtx[i], no, tangent)) { - /* pass */ - } - else { - if (normalize_v3(no) != 0.0f) { - axis_dominant_v3_to_m3(axismtx[i], no); - invert_m3(axismtx[i]); - } - else { - unit_m3(axismtx[i]); - } - } - } - } - - MEM_freeN(groups_array); - MEM_freeN(group_index); - - /* for PET we need islands of 1 so connected vertices can use it with V3D_AROUND_LOCAL_ORIGINS */ - if (calc_single_islands) { - BMIter viter; - BMVert *v; - int group_tot_single = 0; - - BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) { - group_tot_single += 1; - } - } - - if (group_tot_single != 0) { - center = MEM_reallocN(center, sizeof(*center) * (group_tot + group_tot_single)); - if (axismtx) { - axismtx = MEM_reallocN(axismtx, sizeof(*axismtx) * (group_tot + group_tot_single)); - } +/** \} */ - BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) { - vert_map[i] = group_tot; - copy_v3_v3(center[group_tot], v->co); +/* -------------------------------------------------------------------- */ +/** \name TransDataMirror Creation + * + * \{ */ - if (axismtx) { - if (is_zero_v3(v->no) != 0.0f) { - axis_dominant_v3_to_m3(axismtx[group_tot], v->no); - invert_m3(axismtx[group_tot]); - } - else { - unit_m3(axismtx[group_tot]); - } - } +/* Used for both mirror epsilon and TD_MIRROR_EDGE_ */ +#define TRANSFORM_MAXDIST_MIRROR 0.00002f - group_tot += 1; - } - } - } - } +struct MirrorDataVert { + int index; + int flag; +}; - r_island_data->axismtx = axismtx; - r_island_data->center = center; - r_island_data->island_tot = group_tot; - r_island_data->island_vert_map = vert_map; -} +struct TransMirrorData { + struct MirrorDataVert *vert_map; + int mirror_elem_len; +}; static bool is_in_quadrant_v3(const float co[3], const int quadrant[3], const float epsilon) { @@ -423,172 +456,124 @@ static bool is_in_quadrant_v3(const float co[3], const int quadrant[3], const fl return true; } -static TransDataMirror *editmesh_mirror_data_calc(BMEditMesh *em, - bool use_select, - const bool use_topology, - const bool mirror_axis[3], - int *r_mirror_data_len, - BLI_bitmap **r_mirror_bitmap) +static void editmesh_mirror_data_calc(BMEditMesh *em, + const bool use_select, + const bool use_topology, + const bool mirror_axis[3], + struct TransMirrorData *r_mirror_data) { - BMesh *bm = em->bm; - int *index[3] = {NULL}; - int i; - - bool test_selected_only = use_select && (mirror_axis[0] + mirror_axis[1] + mirror_axis[2]) == 1; - for (i = 0; i < 3; i++) { - if (mirror_axis[i]) { - index[i] = MEM_mallocN(bm->totvert * sizeof(int), __func__); - EDBM_verts_mirror_cache_begin_ex( - em, i, false, test_selected_only, use_topology, TRANSFORM_MAXDIST_MIRROR, index[i]); - } - } + struct MirrorDataVert *vert_map; + BMesh *bm = em->bm; BMVert *eve; BMIter iter; + int i, flag, totvert = bm->totvert; - int quadrant[3]; - { - float select_sum[3] = {0}; - BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - continue; - } - if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - add_v3_v3(select_sum, eve->co); - } - } - - for (i = 0; i < 3; i++) { - if (mirror_axis[i]) { - quadrant[i] = select_sum[i] >= 0.0f ? 1 : -1; - } - else { - quadrant[i] = 0; - } - } - } + vert_map = MEM_mallocN(totvert * sizeof(*vert_map), __func__); - /* Tag only elements that will be transformed within the quadrant. */ + float select_sum[3] = {0}; BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { + vert_map[i] = (struct MirrorDataVert){-1, 0}; if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { continue; } - if ((!use_select || BM_elem_flag_test(eve, BM_ELEM_SELECT)) && - is_in_quadrant_v3(eve->co, quadrant, TRANSFORM_MAXDIST_MIRROR)) { - BM_elem_flag_enable(eve, BM_ELEM_TAG); - BM_elem_index_set(eve, i); + if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + add_v3_v3(select_sum, eve->co); + } + } + + /* Tag only elements that will be transformed within the quadrant. */ + int quadrant[3]; + for (int a = 0; a < 3; a++) { + if (mirror_axis[a]) { + quadrant[a] = select_sum[a] >= 0.0f ? 1 : -1; } else { - BM_elem_flag_disable(eve, BM_ELEM_TAG); - BM_elem_index_set(eve, -1); + quadrant[a] = 0; } } + uint mirror_elem_len = 0; + int *index[3] = {NULL, NULL, NULL}; + bool test_selected_only = use_select && (mirror_axis[0] + mirror_axis[1] + mirror_axis[2]) == 1; for (int a = 0; a < 3; a++) { - int *index_iter = index[a]; - if (index_iter == NULL) { + if (!mirror_axis[a]) { continue; } + + index[a] = MEM_mallocN(totvert * sizeof(*index[a]), __func__); + EDBM_verts_mirror_cache_begin_ex( + em, a, false, test_selected_only, use_topology, TRANSFORM_MAXDIST_MIRROR, index[a]); + + flag = TD_MIRROR_X << a; BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { + int i_mirr = index[a][i]; + if (i_mirr < 0) { + continue; + } if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { continue; } - if (test_selected_only && !BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + if (use_select && !BM_elem_flag_test(eve, BM_ELEM_SELECT)) { continue; } - int elem_index = BM_elem_index_get(eve); - if (elem_index != -1) { - int i_mirr = index_iter[i]; - if (i_mirr >= 0) { - BMVert *vmir = BM_vert_at_index(bm, i_mirr); - BM_elem_index_set(vmir, elem_index); - - /* The slot of this element in the index array no longer needs to be read. - * Use to set the mirror sign. */ - if (index[0] && a > 0) { - index[0][i_mirr] = index[0][i]; - } - if (index[1] && a > 1) { - index[1][i_mirr] = index[1][i]; - } - /* Use -2 to differ from -1, but both can work. */ - index_iter[i_mirr] = -2; - } + if (!is_in_quadrant_v3(eve->co, quadrant, TRANSFORM_MAXDIST_MIRROR)) { + continue; } - } - } - /* Count mirror elements. */ - uint mirror_elem_len = 0; - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN | BM_ELEM_TAG)) { - /* Not a mirror element. */ - BM_elem_index_set(eve, -1); - continue; - } - int elem_index = BM_elem_index_get(eve); - if (elem_index != -1) { + vert_map[i_mirr] = (struct MirrorDataVert){i, flag}; mirror_elem_len++; } } - TransDataMirror *td_mirror_iter, *td_mirror = NULL; - if (mirror_elem_len != 0) { - td_mirror = MEM_mallocN(mirror_elem_len * sizeof(*td_mirror), __func__); - td_mirror_iter = &td_mirror[0]; - - *r_mirror_bitmap = BLI_BITMAP_NEW(bm->totvert, __func__); - - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - int elem_index = BM_elem_index_get(eve); - if (elem_index != -1) { - BMVert *v_src = BM_vert_at_index(bm, elem_index); + if (mirror_elem_len) { + for (int a = 0; a < 3; a++) { + if (!mirror_axis[a]) { + continue; + } - int flag = 0; - if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - flag |= TD_SELECTED; - } - if (index[0] && index[0][i] == -2) { - flag |= TD_MIRROR_X; - } - if (index[1] && index[1][i] == -2) { - flag |= TD_MIRROR_Y; + flag = TD_MIRROR_X << a; + for (i = 0; i < totvert; i++) { + int i_mirr = index[a][i]; + if (i_mirr < 0) { + continue; } - if (index[2] && index[2][i] == -2) { - flag |= TD_MIRROR_Z; + if (vert_map[i].index != -1 && !(vert_map[i].flag & flag)) { + if (vert_map[i_mirr].index == -1) { + mirror_elem_len++; + } + vert_map[i_mirr].index = vert_map[i].index; + vert_map[i_mirr].flag |= vert_map[i].flag | flag; } - - td_mirror_iter->extra = eve; - td_mirror_iter->loc = eve->co; - copy_v3_v3(td_mirror_iter->iloc, eve->co); - td_mirror_iter->flag = flag; - td_mirror_iter->loc_src = v_src->co; - /** `center` will be set in the main createTransEditVerts loop. - * copy_v3_v3(td_mirror_iter->center, eve->co); */ - - td_mirror_iter++; - - BLI_BITMAP_ENABLE(*r_mirror_bitmap, i); } } } + else { + MEM_freeN(vert_map); + vert_map = NULL; + } MEM_SAFE_FREE(index[0]); MEM_SAFE_FREE(index[1]); MEM_SAFE_FREE(index[2]); - bm->elem_index_dirty |= BM_VERT; - *r_mirror_data_len = mirror_elem_len; - return td_mirror; + r_mirror_data->vert_map = vert_map; + r_mirror_data->mirror_elem_len = mirror_elem_len; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Edit Mesh Verts Transform Creation + * + * \{ */ + static void transdata_center_get(const struct TransIslandData *island_data, const int island_index, - const bool no_island_center, const float iloc[3], float r_center[3]) { - if (island_index != -1 && !no_island_center) { + if (island_data->center && island_index != -1) { copy_v3_v3(r_center, island_data->center[island_index]); } else { @@ -604,8 +589,7 @@ static void VertsToTransData(TransInfo *t, BMVert *eve, float *bweight, const struct TransIslandData *island_data, - const int island_index, - const bool no_island_center) + const int island_index) { float *no, _no[3]; BLI_assert(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) == 0); @@ -626,7 +610,7 @@ static void VertsToTransData(TransInfo *t, no = eve->no; } - transdata_center_get(island_data, island_index, no_island_center, td->iloc, td->center); + transdata_center_get(island_data, island_index, td->iloc, td->center); if ((island_index != -1) && island_data->axismtx) { copy_m3_m3(td->axismtx, island_data->axismtx[island_index]); @@ -676,31 +660,12 @@ void createTransEditVerts(TransInfo *t) BMesh *bm = em->bm; BMVert *eve; BMIter iter; - float(*mappedcos)[3] = NULL, (*quats)[4] = NULL; - float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL; - float *dists = NULL; + float mtx[3][3], smtx[3][3]; int a; const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0; - int cd_vert_bweight_offset = -1; struct TransIslandData island_data = {NULL}; - - /* Snap rotation along normal needs a common axis for whole islands, - * otherwise one get random crazy results, see T59104. - * However, we do not want to use the island center for the pivot/translation reference. */ - const bool is_snap_rotate = ((t->mode == TFM_TRANSLATION) && - /* There is not guarantee that snapping - * is initialized yet at this point... */ - (usingSnappingNormal(t) || - (t->settings->snap_flag & SCE_SNAP_ROTATE) != 0) && - (t->around != V3D_AROUND_LOCAL_ORIGINS)); - /* Even for translation this is needed because of island-orientation, see: T51651. */ - const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS) || is_snap_rotate; - /* Original index of our connected vertex when connected distances are calculated. - * Optional, allocate if needed. */ - int *dists_index = NULL; - - BLI_bitmap *mirror_bitmap = NULL; + struct TransMirrorData mirror_data = {NULL}; /** * Quick check if we can transform. @@ -711,20 +676,7 @@ void createTransEditVerts(TransInfo *t) /* Support other objects using PET to adjust these, unless connected is enabled. */ if ((!prop_mode || (prop_mode & T_PROP_CONNECTED)) && (bm->totvertsel == 0)) { - goto cleanup; - } - - if (t->mode == TFM_BWEIGHT) { - BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT); - cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); - } - - if (tc->use_mirror_axis_any) { - bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; - bool use_select = (t->flag & T_PROP_EDIT) == 0; - bool mirror_axis[3] = {tc->use_mirror_axis_x, tc->use_mirror_axis_y, tc->use_mirror_axis_z}; - tc->data_mirror = editmesh_mirror_data_calc( - em, use_select, use_topology, mirror_axis, &tc->data_mirror_len, &mirror_bitmap); + continue; } int data_len = 0; @@ -734,44 +686,41 @@ void createTransEditVerts(TransInfo *t) data_len++; } } - - if (data_len == 0) { - goto cleanup; - } - - /* allocating scratch arrays */ - if (prop_mode & T_PROP_CONNECTED) { - dists = MEM_mallocN(em->bm->totvert * sizeof(float), __func__); - if (is_island_center) { - dists_index = MEM_mallocN(em->bm->totvert * sizeof(int), __func__); - } - } } else { data_len = bm->totvertsel; } - if (mirror_bitmap) { - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) { - if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - if (BLI_BITMAP_TEST(mirror_bitmap, a)) { - data_len--; - } - } - } + if (data_len == 0) { + continue; } - BLI_assert(data_len != 0); + /* Snap rotation along normal needs a common axis for whole islands, + * otherwise one get random crazy results, see T59104. + * However, we do not want to use the island center for the pivot/translation reference. */ + const bool is_snap_rotate = ((t->mode == TFM_TRANSLATION) && + /* There is not guarantee that snapping + * is initialized yet at this point... */ + (usingSnappingNormal(t) || + (t->settings->snap_flag & SCE_SNAP_ROTATE) != 0) && + (t->around != V3D_AROUND_LOCAL_ORIGINS)); - tc->data_len = data_len; - tc->data = MEM_callocN(data_len * sizeof(TransData), "TransObData(Mesh EditMode)"); - if (ELEM(t->mode, TFM_SKIN_RESIZE, TFM_SHRINKFATTEN)) { - /* warning, this is overkill, we only need 2 extra floats, - * but this stores loads of extra stuff, for TFM_SHRINKFATTEN its even more overkill - * since we may not use the 'alt' transform mode to maintain shell thickness, - * but with generic transform code its hard to lazy init vars */ - tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), - "TransObData ext"); + /* Even for translation this is needed because of island-orientation, see: T51651. */ + const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS) || is_snap_rotate; + if (is_island_center) { + /* In this specific case, near-by vertices will need to know + * the island of the nearest connected vertex. */ + const bool calc_single_islands = ((prop_mode & T_PROP_CONNECTED) && + (t->around == V3D_AROUND_LOCAL_ORIGINS) && + (em->selectmode & SCE_SELECT_VERTEX)); + + const bool calc_island_center = !is_snap_rotate; + /* The island axismtx is only necessary in some modes. + * TODO(Germano): Extend the list to exclude other modes. */ + const bool calc_island_axismtx = !ELEM(t->mode, TFM_SHRINKFATTEN); + + editmesh_islands_info_calc( + em, calc_single_islands, calc_island_center, calc_island_axismtx, &island_data); } copy_m3_m4(mtx, tc->obedit->obmat); @@ -779,26 +728,58 @@ void createTransEditVerts(TransInfo *t) * matrix inversion still works and we can still moving along the other */ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); + /* Original index of our connected vertex when connected distances are calculated. + * Optional, allocate if needed. */ + int *dists_index = NULL; + float *dists = NULL; if (prop_mode & T_PROP_CONNECTED) { + dists = MEM_mallocN(bm->totvert * sizeof(float), __func__); + if (is_island_center) { + dists_index = MEM_mallocN(bm->totvert * sizeof(int), __func__); + } editmesh_set_connectivity_distance(em->bm, mtx, dists, dists_index); } - if (is_island_center) { - /* In this specific case, near-by vertices will need to know - * the island of the nearest connected vertex. */ - const bool calc_single_islands = ((prop_mode & T_PROP_CONNECTED) && - (t->around == V3D_AROUND_LOCAL_ORIGINS) && - (em->selectmode & SCE_SELECT_VERTEX)); + /* Create TransDataMirror. */ + if (tc->use_mirror_axis_any) { + bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; + bool use_select = (t->flag & T_PROP_EDIT) == 0; + bool mirror_axis[3] = {tc->use_mirror_axis_x, tc->use_mirror_axis_y, tc->use_mirror_axis_z}; + editmesh_mirror_data_calc(em, use_select, use_topology, mirror_axis, &mirror_data); - /* The island axismtx is only necessary in some modes. - * TODO(Germano): Extend the list to exclude other modes. */ - const bool calc_island_axismtx = !ELEM(t->mode, TFM_SHRINKFATTEN); + if (mirror_data.vert_map) { + tc->data_mirror_len = mirror_data.mirror_elem_len; + tc->data_mirror = MEM_mallocN(mirror_data.mirror_elem_len * sizeof(*tc->data_mirror), + __func__); + + BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) { + if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + if (mirror_data.vert_map[a].index != -1) { + data_len--; + } + } + } + } + } - editmesh_islands_info_calc(em, calc_single_islands, calc_island_axismtx, &island_data); + /* Create TransData. */ + BLI_assert(data_len >= 1); + tc->data_len = data_len; + tc->data = MEM_callocN(data_len * sizeof(TransData), "TransObData(Mesh EditMode)"); + if (ELEM(t->mode, TFM_SKIN_RESIZE, TFM_SHRINKFATTEN)) { + /* warning, this is overkill, we only need 2 extra floats, + * but this stores loads of extra stuff, for TFM_SHRINKFATTEN its even more overkill + * since we may not use the 'alt' transform mode to maintain shell thickness, + * but with generic transform code its hard to lazy init vars */ + tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), + "TransObData ext"); } /* detect CrazySpace [tm] */ + float(*quats)[4] = NULL; + float(*defmats)[3][3] = NULL; if (BKE_modifiers_get_cage_index(t->scene, tc->obedit, NULL, 1) != -1) { + float(*defcos)[3] = NULL; int totleft = -1; if (BKE_modifiers_is_correctable_deformed(t->scene, tc->obedit)) { BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context)); @@ -813,16 +794,17 @@ void createTransEditVerts(TransInfo *t) t->depsgraph, scene_eval, obedit_eval, em_eval, &defmats, &defcos); } - /* if we still have more modifiers, also do crazyspace - * correction with quats, relative to the coordinates after - * the modifiers that support deform matrices (defcos) */ + /* If we still have more modifiers, also do crazy-space + * correction with \a quats, relative to the coordinates after + * the modifiers that support deform matrices \a defcos. */ -#if 0 /* TODO, fix crazyspace+extrude so it can be enabled for general use - campbell */ +#if 0 /* TODO, fix crazy-space & extrude so it can be enabled for general use - campbell */ if ((totleft > 0) || (totleft == -1)) #else if (totleft > 0) #endif { + float(*mappedcos)[3] = NULL; mappedcos = BKE_crazyspace_get_mapped_editverts(t->depsgraph, tc->obedit); quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats"); BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode); @@ -836,6 +818,12 @@ void createTransEditVerts(TransInfo *t) } } + int cd_vert_bweight_offset = -1; + if (t->mode == TFM_BWEIGHT) { + BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT); + cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); + } + TransData *tob = tc->data; TransDataMirror *td_mirror = tc->data_mirror; BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) { @@ -849,9 +837,20 @@ void createTransEditVerts(TransInfo *t) island_index = island_data.island_vert_map[connected_index]; } - if (mirror_bitmap && BLI_BITMAP_TEST(mirror_bitmap, a)) { - transdata_center_get( - &island_data, island_index, is_snap_rotate, td_mirror->iloc, td_mirror->center); + if (mirror_data.vert_map && mirror_data.vert_map[a].index != -1) { + int elem_index = mirror_data.vert_map[a].index; + BMVert *v_src = BM_vert_at_index(bm, elem_index); + + if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + mirror_data.vert_map[a].flag |= TD_SELECTED; + } + + td_mirror->extra = eve; + td_mirror->loc = eve->co; + copy_v3_v3(td_mirror->iloc, eve->co); + td_mirror->flag = mirror_data.vert_map[a].flag; + td_mirror->loc_src = v_src->co; + transdata_center_get(&island_data, island_index, td_mirror->iloc, td_mirror->center); td_mirror++; } @@ -862,8 +861,7 @@ void createTransEditVerts(TransInfo *t) /* Do not use the island center in case we are using islands * only to get axis for snap/rotate to normal... */ - VertsToTransData( - t, tob, tx, em, eve, bweight, &island_data, island_index, is_snap_rotate); + VertsToTransData(t, tob, tx, em, eve, bweight, &island_data, island_index); if (tx) { tx++; } @@ -933,17 +931,15 @@ void createTransEditVerts(TransInfo *t) if (island_data.center) { MEM_freeN(island_data.center); } - if (island_data.axismtx) { MEM_freeN(island_data.axismtx); } - if (island_data.island_vert_map) { MEM_freeN(island_data.island_vert_map); } - - cleanup: - /* crazy space free */ + if (mirror_data.vert_map) { + MEM_freeN(mirror_data.vert_map); + } if (quats) { MEM_freeN(quats); } @@ -956,9 +952,6 @@ void createTransEditVerts(TransInfo *t) if (dists_index) { MEM_freeN(dists_index); } - if (mirror_bitmap) { - MEM_freeN(mirror_bitmap); - } } } @@ -1075,99 +1068,118 @@ static void create_trans_vert_customdata_layer(BMVert *v, BLI_ghash_insert(tcld->origverts, v, r_tcld_vert); } -void trans_mesh_customdata_correction_init(TransInfo *t, TransDataContainer *tc) +static void trans_mesh_customdata_correction_init_container(TransInfo *t, TransDataContainer *tc) { if (tc->custom.type.data) { /* Custom data correction has initiated before. */ BLI_assert(tc->custom.type.free_cb == trans_mesh_customdata_free_cb); return; } - int i; + + if (!ELEM(t->mode, + TFM_TRANSLATION, + TFM_ROTATION, + TFM_RESIZE, + TFM_TOSPHERE, + TFM_SHEAR, + TFM_BEND, + TFM_SHRINKFATTEN, + TFM_TRACKBALL, + TFM_PUSHPULL, + TFM_ALIGN)) { + /* Currently only modes that change the position of vertices are supported. */ + return; + } BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); BMesh *bm = em->bm; - bool use_origfaces; - int cd_loop_mdisp_offset; - { - const bool has_layer_math = CustomData_has_math(&bm->ldata); - cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); - if ((t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) && - /* don't do this at all for non-basis shape keys, too easy to - * accidentally break uv maps or vertex colors then */ - (bm->shapenr <= 1) && (has_layer_math || (cd_loop_mdisp_offset != -1))) { - use_origfaces = true; - } - else { - use_origfaces = false; - cd_loop_mdisp_offset = -1; - } + if (bm->shapenr > 1) { + /* Don't do this at all for non-basis shape keys, too easy to + * accidentally break uv maps or vertex colors then */ + /* create copies of faces for customdata projection. */ + return; } - if (use_origfaces) { - /* create copies of faces for customdata projection */ - bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES); - - struct GHash *origfaces = BLI_ghash_ptr_new(__func__); - struct BMesh *bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default, - &((struct BMeshCreateParams){ - .use_toolflags = false, - })); - - /* we need to have matching customdata */ - BM_mesh_copy_init_customdata(bm_origfaces, bm, NULL); - - int *layer_math_map = NULL; - int layer_index_dst = 0; - { - /* TODO: We don't need `sod->layer_math_map` when there are no loops linked - * to one of the sliding vertices. */ - if (CustomData_has_math(&bm->ldata)) { - /* over alloc, only 'math' layers are indexed */ - layer_math_map = MEM_mallocN(bm->ldata.totlayer * sizeof(int), __func__); - for (i = 0; i < bm->ldata.totlayer; i++) { - if (CustomData_layer_has_math(&bm->ldata, i)) { - layer_math_map[layer_index_dst++] = i; - } + const bool has_layer_math = CustomData_has_math(&bm->ldata); + const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); + if (!has_layer_math && (cd_loop_mdisp_offset == -1)) { + return; + } + + bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES); + + struct GHash *origfaces = BLI_ghash_ptr_new(__func__); + struct BMesh *bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default, + &((struct BMeshCreateParams){ + .use_toolflags = false, + })); + + /* we need to have matching customdata */ + BM_mesh_copy_init_customdata(bm_origfaces, bm, NULL); + + int *layer_math_map = NULL; + int layer_math_map_len = 0; + { + /* TODO: We don't need `sod->layer_math_map` when there are no loops linked + * to one of the sliding vertices. */ + if (has_layer_math) { + /* over alloc, only 'math' layers are indexed */ + layer_math_map = MEM_mallocN(bm->ldata.totlayer * sizeof(int), __func__); + for (int i = 0; i < bm->ldata.totlayer; i++) { + if (CustomData_layer_has_math(&bm->ldata, i)) { + layer_math_map[layer_math_map_len++] = i; } - BLI_assert(layer_index_dst != 0); } + BLI_assert(layer_math_map_len != 0); } + } - struct TransCustomDataLayer *tcld; - tc->custom.type.data = tcld = MEM_mallocN(sizeof(*tcld), __func__); - tc->custom.type.free_cb = trans_mesh_customdata_free_cb; - - tcld->bm = bm; - tcld->origfaces = origfaces; - tcld->bm_origfaces = bm_origfaces; - tcld->cd_loop_mdisp_offset = cd_loop_mdisp_offset; - tcld->layer_math_map = layer_math_map; - tcld->layer_math_map_num = layer_index_dst; - tcld->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + struct TransCustomDataLayer *tcld = MEM_mallocN(sizeof(*tcld), __func__); + int data_len = tc->data_len + tc->data_mirror_len; - int data_len = tc->data_len + tc->data_mirror_len; - struct GHash *origverts = BLI_ghash_ptr_new_ex(__func__, data_len); - tcld->origverts = origverts; + tcld->bm = bm; + tcld->origfaces = origfaces; + tcld->bm_origfaces = bm_origfaces; + tcld->cd_loop_mdisp_offset = cd_loop_mdisp_offset; + tcld->layer_math_map = layer_math_map; + tcld->layer_math_map_num = layer_math_map_len; + tcld->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + tcld->origverts = BLI_ghash_ptr_new_ex(__func__, data_len); + tcld->data = BLI_memarena_alloc(tcld->arena, data_len * sizeof(*tcld->data)); + tcld->data_len = data_len; - struct TransCustomDataLayerVert *tcld_vert, *tcld_vert_iter; - tcld_vert = BLI_memarena_alloc(tcld->arena, data_len * sizeof(*tcld_vert)); - tcld_vert_iter = &tcld_vert[0]; + { + /* Setup Verts. */ + struct TransCustomDataLayerVert *tcld_vert_iter = &tcld->data[0]; - TransData *tob; - for (i = tc->data_len, tob = tc->data; i--; tob++, tcld_vert_iter++) { + TransData *tob = tc->data; + for (int i = tc->data_len; i--; tob++, tcld_vert_iter++) { BMVert *v = tob->extra; create_trans_vert_customdata_layer(v, tcld, tcld_vert_iter); } TransDataMirror *td_mirror = tc->data_mirror; - for (i = tc->data_mirror_len; i--; td_mirror++, tcld_vert_iter++) { + for (int i = tc->data_mirror_len; i--; td_mirror++, tcld_vert_iter++) { BMVert *v = td_mirror->extra; create_trans_vert_customdata_layer(v, tcld, tcld_vert_iter); } + } + + tc->custom.type.data = tcld; + tc->custom.type.free_cb = trans_mesh_customdata_free_cb; +} + +void trans_mesh_customdata_correction_init(TransInfo *t) +{ + const char uvcalc_correct_flag = ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE) ? + UVCALC_TRANSFORM_CORRECT_SLIDE : + UVCALC_TRANSFORM_CORRECT; - tcld->data = tcld_vert; - tcld->data_len = data_len; + if (t->settings->uvcalc_flag & uvcalc_correct_flag) { + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + trans_mesh_customdata_correction_init_container(t, tc); + } } } @@ -1187,19 +1199,17 @@ static void trans_mesh_customdata_correction_apply_vert(struct TransCustomDataLa BMesh *bm = tcld->bm; BMVert *v = tcld_vert->v; const float *co_orig_3d = tcld_vert->co_orig_3d; - struct LinkNode **cd_loop_groups = tcld_vert->cd_loop_groups; BMIter liter; int j, l_num; float *loop_weights; const bool is_moved = (len_squared_v3v3(v->co, co_orig_3d) > FLT_EPSILON); - const bool do_loop_weight = tcld->layer_math_map_num && is_moved; - const bool do_loop_mdisps = is_final && is_moved && (tcld->cd_loop_mdisp_offset != -1); + const bool do_loop_weight = is_moved && tcld->layer_math_map_num; const float *v_proj_axis = v->no; /* original (l->prev, l, l->next) projections for each loop ('l' remains unchanged) */ float v_proj[3][3]; - if (do_loop_weight || do_loop_mdisps) { + if (do_loop_weight) { project_plane_normalized_v3_v3v3(v_proj[1], co_orig_3d, v_proj_axis); } @@ -1264,6 +1274,7 @@ static void trans_mesh_customdata_correction_apply_vert(struct TransCustomDataLa } } + struct LinkNode **cd_loop_groups = tcld_vert->cd_loop_groups; if (tcld->layer_math_map_num && cd_loop_groups) { if (do_loop_weight) { for (j = 0; j < tcld->layer_math_map_num; j++) { @@ -1283,6 +1294,7 @@ static void trans_mesh_customdata_correction_apply_vert(struct TransCustomDataLa * Interpolate from every other loop (not ideal) * However values will only be taken from loops which overlap other mdisps. * */ + const bool do_loop_mdisps = is_moved && is_final && (tcld->cd_loop_mdisp_offset != -1); if (do_loop_mdisps) { float(*faces_center)[3] = BLI_array_alloca(faces_center, l_num); BMLoop *l; @@ -1386,13 +1398,9 @@ void recalcData_mesh(TransInfo *t) } } - if (ELEM(t->mode, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - trans_mesh_customdata_correction_apply(tc, false); - } - } - FOREACH_TRANS_DATA_CONTAINER (t, tc) { + trans_mesh_customdata_correction_apply(tc, false); + DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); EDBM_mesh_normals_update(em); @@ -1408,18 +1416,9 @@ void recalcData_mesh(TransInfo *t) void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) { const bool canceled = (t->state == TRANS_CANCEL); + const bool use_automerge = !canceled && (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0; - if (canceled) { - /* Exception, edge slide transformed UVs too. */ - if (t->mode == TFM_EDGE_SLIDE) { - doEdgeSlide(t, 0.0f); - } - else if (t->mode == TFM_VERT_SLIDE) { - doVertSlide(t, 0.0f); - } - } - - if (ELEM(t->mode, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { + if (TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.type.data != NULL) { /* Handle multires re-projection, done * on transform completion since it's * really slow -joeedh. */ @@ -1428,10 +1427,8 @@ void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) } } - bool use_automerge = !canceled && (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0; if (use_automerge) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { - BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); BMesh *bm = em->bm; char hflag; diff --git a/source/blender/editors/transform/transform_data.h b/source/blender/editors/transform/transform_data.h index bc95fdad59c..48ed9ecf34b 100644 --- a/source/blender/editors/transform/transform_data.h +++ b/source/blender/editors/transform/transform_data.h @@ -88,8 +88,8 @@ typedef struct TransDataExtension { * It is the same but without the #Bone.bone_mat, see #TD_PBONE_LOCAL_MTX_C. */ float l_smtx[3][3]; /** The rotscale matrix of pose bone, to allow using snap-align in translation mode, - * when td->mtx is the loc pose bone matrix (and hence can't be used to apply - * rotation in some cases, namely when a bone is in "NoLocal" or "Hinge" mode)... */ + * when #TransData.mtx is the loc pose bone matrix (and hence can't be used to apply + * rotation in some cases, namely when a bone is in "No-Local" or "Hinge" mode)... */ float r_mtx[3][3]; /** Inverse of previous one. */ float r_smtx[3][3]; diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 78c47014d62..cce6ef1f3bd 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -131,21 +131,6 @@ void resetTransRestrictions(TransInfo *t) t->flag &= ~T_ALL_RESTRICTIONS; } -static int initTransInfo_edit_pet_to_flag(const int proportional) -{ - int flag = 0; - if (proportional & PROP_EDIT_USE) { - flag |= T_PROP_EDIT; - } - if (proportional & PROP_EDIT_CONNECTED) { - flag |= T_PROP_CONNECTED; - } - if (proportional & PROP_EDIT_PROJECTED) { - flag |= T_PROP_PROJECTED; - } - return flag; -} - void initTransDataContainers_FromObjectData(TransInfo *t, Object *obact, Object **objects, @@ -390,15 +375,15 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve if (op && ((prop = RNA_struct_find_property(op->ptr, "correct_uv")))) { if (RNA_property_is_set(op->ptr, prop)) { if (RNA_property_boolean_get(op->ptr, prop)) { - t->settings->uvcalc_flag |= UVCALC_TRANSFORM_CORRECT; + t->settings->uvcalc_flag |= UVCALC_TRANSFORM_CORRECT_SLIDE; } else { - t->settings->uvcalc_flag &= ~UVCALC_TRANSFORM_CORRECT; + t->settings->uvcalc_flag &= ~UVCALC_TRANSFORM_CORRECT_SLIDE; } } else { RNA_property_boolean_set( - op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) != 0); + op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT_SLIDE) != 0); } } } @@ -550,7 +535,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve orient_types[2] = orient_type_scene; } else { - if ((t->flag & T_MODAL) && (use_orient_axis || transform_mode_is_changeable(t->mode))) { + if ((t->flag & T_MODAL) && (use_orient_axis || transform_mode_is_changeable(t->mode)) && + (t->mode != TFM_ALIGN)) { orient_types[0] = V3D_ORIENT_VIEW; } else { @@ -636,45 +622,45 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve /* setting PET flag only if property exist in operator. Otherwise, assume it's not supported */ if (op && (prop = RNA_struct_find_property(op->ptr, "use_proportional_edit"))) { if (RNA_property_is_set(op->ptr, prop)) { - int proportional = 0; if (RNA_property_boolean_get(op->ptr, prop)) { - proportional |= PROP_EDIT_USE; + t->flag |= T_PROP_EDIT; if (RNA_boolean_get(op->ptr, "use_proportional_connected")) { - proportional |= PROP_EDIT_CONNECTED; + t->flag |= T_PROP_CONNECTED; } if (RNA_boolean_get(op->ptr, "use_proportional_projected")) { - proportional |= PROP_EDIT_PROJECTED; + t->flag |= T_PROP_PROJECTED; } } - t->flag |= initTransInfo_edit_pet_to_flag(proportional); } else { /* use settings from scene only if modal */ if (t->flag & T_MODAL) { if ((t->options & CTX_NO_PET) == 0) { + bool use_prop_edit = false; if (t->spacetype == SPACE_GRAPH) { - t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_fcurve); + use_prop_edit = ts->proportional_fcurve; } else if (t->spacetype == SPACE_ACTION) { - t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_action); + use_prop_edit = ts->proportional_action; } - else if (t->obedit_type != -1) { - t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_edit); + else if (t->options & CTX_MASK) { + use_prop_edit = ts->proportional_mask; } - else if (t->options & CTX_GPENCIL_STROKES) { - t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_edit); + else if (obact && obact->mode == OB_MODE_OBJECT) { + use_prop_edit = ts->proportional_objects; } - else if (t->options & CTX_MASK) { - if (ts->proportional_mask) { - t->flag |= T_PROP_EDIT; - - if (ts->proportional_edit & PROP_EDIT_CONNECTED) { - t->flag |= T_PROP_CONNECTED; - } - } + else { + use_prop_edit = (ts->proportional_edit & PROP_EDIT_USE) != 0; } - else if (!(t->options & CTX_CURSOR) && ts->proportional_objects) { + + if (use_prop_edit) { t->flag |= T_PROP_EDIT; + if (ts->proportional_edit & PROP_EDIT_CONNECTED) { + t->flag |= T_PROP_CONNECTED; + } + if (ts->proportional_edit & PROP_EDIT_PROJECTED) { + t->flag |= T_PROP_PROJECTED; + } } } } diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index f028044809f..831ea90b4e4 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -50,6 +50,23 @@ /* Own include. */ #include "transform_mode.h" +int transform_mode_really_used(bContext *C, int mode) +{ + if (mode == TFM_BONESIZE) { + Object *ob = CTX_data_active_object(C); + BLI_assert(ob); + if (ob->type != OB_ARMATURE) { + return TFM_RESIZE; + } + bArmature *arm = ob->data; + if (arm->drawtype == ARM_ENVELOPE) { + return TFM_BONE_ENVELOPE_DIST; + } + } + + return mode; +} + bool transdata_check_local_center(TransInfo *t, short around) { return ((around == V3D_AROUND_LOCAL_ORIGINS) && @@ -1174,25 +1191,12 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode) case TFM_CREASE: initCrease(t); break; - case TFM_BONESIZE: { /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */ - /* Note: we have to pick one, use the active object. */ - TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t); - bArmature *arm = tc->poseobj->data; - if (arm->drawtype == ARM_ENVELOPE) { - initBoneEnvelope(t); - t->mode = TFM_BONE_ENVELOPE_DIST; - } - else { - initBoneSize(t); - } + case TFM_BONESIZE: + initBoneSize(t); break; - } case TFM_BONE_ENVELOPE: - initBoneEnvelope(t); - break; case TFM_BONE_ENVELOPE_DIST: initBoneEnvelope(t); - t->mode = TFM_BONE_ENVELOPE_DIST; break; case TFM_EDGE_SLIDE: case TFM_VERT_SLIDE: { @@ -1267,6 +1271,12 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode) break; } + if (t->data_type == TC_MESH_VERTS) { + /* Init Custom Data correction. + * Ideally this should be called when creating the TransData. */ + trans_mesh_customdata_correction_init(t); + } + /* TODO(germano): Some of these operations change the `t->mode`. * This can be bad for Redo. * BLI_assert(t->mode == mode); */ diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h index 464deff983b..5cda8e3063a 100644 --- a/source/blender/editors/transform/transform_mode.h +++ b/source/blender/editors/transform/transform_mode.h @@ -26,6 +26,7 @@ #define __TRANSFORM_MODE_H__ struct AnimData; +struct bContext; struct LinkNode; struct TransData; struct TransDataContainer; @@ -40,6 +41,7 @@ typedef struct TransDataGenericSlideVert { } TransDataGenericSlideVert; /* transform_mode.c */ +int transform_mode_really_used(struct bContext *C, int mode); bool transdata_check_local_center(TransInfo *t, short around); bool transform_mode_is_changeable(const int mode); void protectedTransBits(short protectflag, float vec[3]); @@ -95,7 +97,6 @@ void initSeqSlide(TransInfo *t); /* transform_mode_edge_slide.c */ void drawEdgeSlide(TransInfo *t); -void doEdgeSlide(TransInfo *t, float perc); void initEdgeSlide_ex( TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp); void initEdgeSlide(TransInfo *t); @@ -153,7 +154,6 @@ void initTranslation(TransInfo *t); /* transform_mode_vert_slide.c */ void drawVertSlide(TransInfo *t); -void doVertSlide(TransInfo *t, float perc); void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp); void initVertSlide(TransInfo *t); #endif diff --git a/source/blender/editors/transform/transform_mode_bbone_resize.c b/source/blender/editors/transform/transform_mode_bbone_resize.c index 77850e74785..2c2253630c0 100644 --- a/source/blender/editors/transform/transform_mode_bbone_resize.c +++ b/source/blender/editors/transform/transform_mode_bbone_resize.c @@ -132,6 +132,11 @@ static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2])) if (t->con.applySize) { t->con.applySize(t, NULL, NULL, mat); + for (i = 0; i < 3; i++) { + if (!(t->con.mode & (CON_AXIS0 << i))) { + t->values_final[i] = 1.0f; + } + } } copy_m3_m3(t->mat, mat); // used in gizmo diff --git a/source/blender/editors/transform/transform_mode_boneenvelope.c b/source/blender/editors/transform/transform_mode_boneenvelope.c index 7045d190478..b7a34769f5a 100644 --- a/source/blender/editors/transform/transform_mode_boneenvelope.c +++ b/source/blender/editors/transform/transform_mode_boneenvelope.c @@ -96,7 +96,6 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2])) void initBoneEnvelope(TransInfo *t) { - t->mode = TFM_BONE_ENVELOPE; t->transform = applyBoneEnvelope; initMouseInputMode(t, &t->mouse, INPUT_SPRING); diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c index 42f75f041b9..ed22afc404e 100644 --- a/source/blender/editors/transform/transform_mode_edge_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_slide.c @@ -50,6 +50,7 @@ #include "BLT_translation.h" #include "transform.h" +#include "transform_constraints.h" #include "transform_convert.h" #include "transform_mode.h" #include "transform_snap.h" @@ -96,24 +97,28 @@ typedef struct EdgeSlideParams { } EdgeSlideParams; /** - * Get the first valid EdgeSlideData. + * Get the first valid TransDataContainer *. * * 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) +static TransDataContainer *edge_slide_container_first_ok(TransInfo *t) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { - EdgeSlideData *sld = tc->custom.mode.data; - if (sld == NULL) { - continue; + if (tc->custom.mode.data) { + return tc; } - return sld; } BLI_assert(!"Should never happen, at least one EdgeSlideData should be valid"); return NULL; } +static EdgeSlideData *edgeSlideFirstGet(TransInfo *t) +{ + TransDataContainer *tc = edge_slide_container_first_ok(t); + return tc->custom.mode.data; +} + static void calcEdgeSlideCustomPoints(struct TransInfo *t) { EdgeSlideData *sld = edgeSlideFirstGet(t); @@ -1129,132 +1134,226 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven 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); + if (t->mode != TFM_EDGE_SLIDE) { + return; + } - /* Even mode */ - if ((slp->use_even == true) || (is_clamp == false)) { - const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f; + EdgeSlideData *sld = edgeSlideFirstGet(t); + if (sld == NULL) { + return; + } - GPU_depth_test(false); + const EdgeSlideParams *slp = t->custom.mode.data; + const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); - GPU_blend(true); - GPU_blend_set_func_separate( - GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f; - GPU_matrix_push(); - GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); + GPU_depth_test(false); - uint pos = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + GPU_blend(true); + GPU_blend_set_func_separate( + GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + GPU_matrix_push(); + GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); - 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; + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - 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]); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - 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 (slp->use_even == true) { + /* Even mode */ + 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]) { - immVertex3fv(pos, curr_sv->v_side[1]->co); - immVertex3fv(pos, curr_sv->v_co_orig); + co_test = curr_sv->v_side[1]->co; } - 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(); - } + } + else { + if (curr_sv->v_side[0]) { + co_test = curr_sv->v_side[0]->co; } + } - immUniformThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade); - GPU_point_size(guide_size); + if (co_test != NULL) { + immUniformThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade); + GPU_point_size(ctrl_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); + 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 { - if (is_clamp == false) { - const int side_index = sld->curr_side_unclamp; - TransDataEdgeSlideVert *sv; - int i; - const int alpha_shade = -160; + copy_v3_v3(a, sv->dir_side[!side_index]); + } - GPU_line_width(line_size); - immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); - immBegin(GPU_PRIM_LINES, sld->totsv * 2); + 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); - /* TODO(campbell): Loop over all verts */ - sv = sld->sv; - for (i = 0; i < sld->totsv; i++, sv++) { - float a[3], b[3]; + immVertex3fv(pos, a); + immVertex3fv(pos, b); + } + immEnd(); + } + else { + /* Common case. */ + TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; + const int alpha_shade = -160; + + float co_dir[3]; + add_v3_v3v3(co_dir, curr_sv->v_co_orig, curr_sv->dir_side[sld->curr_side_unclamp]); + + GPU_line_width(line_size); + immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); + immBeginAtMost(GPU_PRIM_LINES, 2); + immVertex3fv(pos, curr_sv->v_co_orig); + immVertex3fv(pos, co_dir); + immEnd(); + } - 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]); - } + immUnbindProgram(); - 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); + GPU_matrix_pop(); - immVertex3fv(pos, a); - immVertex3fv(pos, b); - } - immEnd(); - } - else { - BLI_assert(0); - } - } + GPU_blend(false); - immUnbindProgram(); + GPU_depth_test(true); +} - GPU_matrix_pop(); +static void edge_slide_snap_apply(TransInfo *t, float *value) +{ + TransDataContainer *tc = edge_slide_container_first_ok(t); + EdgeSlideParams *slp = t->custom.mode.data; + EdgeSlideData *sld_active = tc->custom.mode.data; + TransDataEdgeSlideVert *sv = &sld_active->sv[sld_active->curr_sv_index]; + float snap_point[3], co_orig[3], co_dest[2][3], dvec[3]; + + copy_v3_v3(co_orig, sv->v_co_orig); + add_v3_v3v3(co_dest[0], co_orig, sv->dir_side[0]); + add_v3_v3v3(co_dest[1], co_orig, sv->dir_side[1]); + if (tc->use_local_mat) { + mul_m4_v3(tc->mat, co_orig); + mul_m4_v3(tc->mat, co_dest[0]); + mul_m4_v3(tc->mat, co_dest[1]); + } - GPU_blend(false); + getSnapPoint(t, dvec); + sub_v3_v3(dvec, t->tsnap.snapTarget); + add_v3_v3v3(snap_point, co_orig, dvec); - GPU_depth_test(true); + float perc = *value; + int side_index; + float t_mid; + if (slp->use_even == false) { + const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); + if (is_clamp) { + side_index = perc < 0.0f; + } + else { + side_index = sld_active->curr_side_unclamp; } } + else { + /* Could be pre-calculated. */ + t_mid = line_point_factor_v3((float[3]){0.0f, 0.0f, 0.0f}, sv->dir_side[0], sv->dir_side[1]); + + float t_snap = line_point_factor_v3(snap_point, co_dest[0], co_dest[1]); + side_index = t_snap >= t_mid; + } + + if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE)) { + float co_dir[3]; + sub_v3_v3v3(co_dir, co_dest[side_index], co_orig); + if (t->tsnap.snapElem & SCE_SNAP_MODE_EDGE) { + transform_constraint_snap_axis_to_edge(t, co_dir, dvec); + } + else { + transform_constraint_snap_axis_to_face(t, co_dir, dvec); + } + add_v3_v3v3(snap_point, co_orig, dvec); + } + + perc = line_point_factor_v3(snap_point, co_orig, co_dest[side_index]); + if (slp->use_even == false) { + if (side_index) { + perc *= -1; + } + } + else { + if (!side_index) { + perc = (1.0f - perc) * t_mid; + } + else { + perc = perc * (1.0f - t_mid) + t_mid; + } + + if (slp->flipped) { + perc = 1.0f - perc; + } + + perc = (2 * perc) - 1.0f; + + if (!slp->flipped) { + perc *= -1; + } + } + + *value = perc; } -void doEdgeSlide(TransInfo *t, float perc) +static void doEdgeSlide(TransInfo *t, float perc) { EdgeSlideParams *slp = t->custom.mode.data; EdgeSlideData *sld_active = edgeSlideFirstGet(t); @@ -1365,6 +1464,7 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2])) final = t->values[0]; + applySnapping(t, &final); snapGridIncrement(t, &final); /* only do this so out of range values are not displayed */ @@ -1413,6 +1513,8 @@ void initEdgeSlide_ex( t->mode = TFM_EDGE_SLIDE; t->transform = applyEdgeSlide; t->handleEvent = handleEventEdgeSlide; + t->tsnap.applySnap = edge_slide_snap_apply; + t->tsnap.distance = transform_snap_distance_len_squared_fn; { EdgeSlideParams *slp = MEM_callocN(sizeof(*slp), __func__); @@ -1432,16 +1534,13 @@ void initEdgeSlide_ex( t->custom.mode.use_free = true; } - if (use_double_side) { - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - sld = use_double_side ? createEdgeSlideVerts_double_side(t, tc) : - createEdgeSlideVerts_single_side(t, tc); - if (sld) { - tc->custom.mode.data = sld; - tc->custom.mode.free_cb = freeEdgeSlideVerts; - trans_mesh_customdata_correction_init(t, tc); - ok = true; - } + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + sld = use_double_side ? createEdgeSlideVerts_double_side(t, tc) : + createEdgeSlideVerts_single_side(t, tc); + if (sld) { + tc->custom.mode.data = sld; + tc->custom.mode.free_cb = freeEdgeSlideVerts; + ok = true; } } diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c index ebce32a598e..5fb46b30e0d 100644 --- a/source/blender/editors/transform/transform_mode_resize.c +++ b/source/blender/editors/transform/transform_mode_resize.c @@ -44,6 +44,39 @@ /** \name Transform Resize * \{ */ +static float ResizeBetween(TransInfo *t, const float p1[3], const float p2[3]) +{ + float d1[3], d2[3], len_d1; + + sub_v3_v3v3(d1, p1, t->center_global); + sub_v3_v3v3(d2, p2, t->center_global); + + if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) { + mul_m3_v3(t->con.pmtx, d1); + mul_m3_v3(t->con.pmtx, d2); + } + + project_v3_v3v3(d1, d1, d2); + + len_d1 = len_v3(d1); + + /* Use 'invalid' dist when `center == p1` (after projecting), + * in this case scale will _never_ move the point in relation to the center, + * so it makes no sense to take it into account when scaling. see: T46503 */ + return len_d1 != 0.0f ? len_v3(d2) / len_d1 : TRANSFORM_DIST_INVALID; +} + +static void ApplySnapResize(TransInfo *t, float vec[3]) +{ + float point[3]; + getSnapPoint(t, point); + + float dist = ResizeBetween(t, t->tsnap.snapTarget, point); + if (dist != TRANSFORM_DIST_INVALID) { + copy_v3_fl(vec, dist); + } +} + static void applyResize(TransInfo *t, const int UNUSED(mval[2])) { float mat[3][3]; @@ -134,6 +167,8 @@ void initResize(TransInfo *t) { t->mode = TFM_RESIZE; t->transform = applyResize; + t->tsnap.applySnap = ApplySnapResize; + t->tsnap.distance = ResizeBetween; initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP); diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c index 6480cb6c30e..4fa5dffc473 100644 --- a/source/blender/editors/transform/transform_mode_rotate.c +++ b/source/blender/editors/transform/transform_mode_rotate.c @@ -42,6 +42,67 @@ /** \name Transform Rotation * \{ */ +static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3]) +{ + float angle, start[3], end[3]; + + sub_v3_v3v3(start, p1, t->center_global); + sub_v3_v3v3(end, p2, t->center_global); + + // Angle around a constraint axis (error prone, will need debug) + if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) { + float axis[3], tmp[3]; + + t->con.applyRot(t, NULL, NULL, axis, NULL); + + project_v3_v3v3(tmp, end, axis); + sub_v3_v3v3(end, end, tmp); + + project_v3_v3v3(tmp, start, axis); + sub_v3_v3v3(start, start, tmp); + + normalize_v3(end); + normalize_v3(start); + + cross_v3_v3v3(tmp, start, end); + + if (dot_v3v3(tmp, axis) < 0.0f) { + angle = -acosf(dot_v3v3(start, end)); + } + else { + angle = acosf(dot_v3v3(start, end)); + } + } + else { + float mtx[3][3]; + + copy_m3_m4(mtx, t->viewmat); + + mul_m3_v3(mtx, end); + mul_m3_v3(mtx, start); + + angle = atan2f(start[1], start[0]) - atan2f(end[1], end[0]); + } + + if (angle > (float)M_PI) { + angle = angle - 2 * (float)M_PI; + } + else if (angle < -((float)M_PI)) { + angle = 2.0f * (float)M_PI + angle; + } + + return angle; +} + +static void ApplySnapRotation(TransInfo *t, float *value) +{ + float point[3]; + getSnapPoint(t, point); + + float dist = RotationBetween(t, t->tsnap.snapTarget, point); + *value = dist; +} + static float large_rotation_limit(float angle) { /* Limit rotation to 1001 turns max @@ -173,6 +234,8 @@ void initRotation(TransInfo *t) { t->mode = TFM_ROTATION; t->transform = applyRotation; + t->tsnap.applySnap = ApplySnapRotation; + t->tsnap.distance = RotationBetween; setInputPostFct(&t->mouse, postInputRotation); initMouseInputMode(t, &t->mouse, INPUT_ANGLE); diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 60caa257a40..aee05197f10 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -34,6 +34,7 @@ #include "BKE_report.h" #include "BKE_unit.h" +#include "ED_node.h" #include "ED_screen.h" #include "WM_api.h" @@ -214,6 +215,34 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_ } } +static void ApplySnapTranslation(TransInfo *t, float vec[3]) +{ + float point[3]; + getSnapPoint(t, point); + + if (t->spacetype == SPACE_NODE) { + char border = t->tsnap.snapNodeBorder; + if (border & (NODE_LEFT | NODE_RIGHT)) { + vec[0] = point[0] - t->tsnap.snapTarget[0]; + } + if (border & (NODE_BOTTOM | NODE_TOP)) { + vec[1] = point[1] - t->tsnap.snapTarget[1]; + } + } + else { + if (t->spacetype == SPACE_VIEW3D) { + if (t->options & CTX_PAINT_CURVE) { + if (ED_view3d_project_float_global(t->region, point, point, V3D_PROJ_TEST_NOP) != + V3D_PROJ_RET_OK) { + zero_v3(point); /* no good answer here... */ + } + } + } + + sub_v3_v3v3(vec, point, t->tsnap.snapTarget); + } +} + static void applyTranslationValue(TransInfo *t, const float vec[3]) { const bool apply_snap_align_rotation = usingSnappingNormal( @@ -376,6 +405,8 @@ void initTranslation(TransInfo *t) } t->transform = applyTranslation; + t->tsnap.applySnap = ApplySnapTranslation; + t->tsnap.distance = transform_snap_distance_len_squared_fn; initMouseInputMode(t, &t->mouse, INPUT_VECTOR); diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c index 62415b1ddc6..4b75c362da9 100644 --- a/source/blender/editors/transform/transform_mode_vert_slide.c +++ b/source/blender/editors/transform/transform_mode_vert_slide.c @@ -47,6 +47,7 @@ #include "BLT_translation.h" #include "transform.h" +#include "transform_constraints.h" #include "transform_convert.h" #include "transform_mode.h" #include "transform_snap.h" @@ -491,7 +492,7 @@ void drawVertSlide(TransInfo *t) } } -void doVertSlide(TransInfo *t, float perc) +static void doVertSlide(TransInfo *t, float perc) { VertSlideParams *slp = t->custom.mode.data; @@ -538,6 +539,37 @@ void doVertSlide(TransInfo *t, float perc) } } +static void vert_slide_snap_apply(TransInfo *t, float *value) +{ + TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t); + VertSlideData *sld = tc->custom.mode.data; + TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index]; + + float snap_point[3], co_orig_3d[3], co_curr_3d[3], dvec[3]; + copy_v3_v3(co_orig_3d, sv->co_orig_3d); + copy_v3_v3(co_curr_3d, sv->co_link_orig_3d[sv->co_link_curr]); + if (tc->use_local_mat) { + mul_m4_v3(tc->mat, co_orig_3d); + mul_m4_v3(tc->mat, co_curr_3d); + } + + getSnapPoint(t, dvec); + sub_v3_v3(dvec, t->tsnap.snapTarget); + if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE)) { + float co_dir_3d[3]; + sub_v3_v3v3(co_dir_3d, co_curr_3d, co_orig_3d); + if (t->tsnap.snapElem & SCE_SNAP_MODE_EDGE) { + transform_constraint_snap_axis_to_edge(t, co_dir_3d, dvec); + } + else { + transform_constraint_snap_axis_to_face(t, co_dir_3d, dvec); + } + } + + add_v3_v3v3(snap_point, co_orig_3d, dvec); + *value = line_point_factor_v3(snap_point, co_orig_3d, co_curr_3d); +} + static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2])) { char str[UI_MAX_DRAW_STR]; @@ -551,6 +583,7 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2])) final = t->values[0]; + applySnapping(t, &final); snapGridIncrement(t, &final); /* only do this so out of range values are not displayed */ @@ -596,6 +629,8 @@ void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp) t->mode = TFM_VERT_SLIDE; t->transform = applyVertSlide; t->handleEvent = handleEventVertSlide; + t->tsnap.applySnap = vert_slide_snap_apply; + t->tsnap.distance = transform_snap_distance_len_squared_fn; { VertSlideParams *slp = MEM_callocN(sizeof(*slp), __func__); @@ -617,7 +652,6 @@ void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp) if (sld) { tc->custom.mode.data = sld; tc->custom.mode.free_cb = freeVertSlideVerts; - trans_mesh_customdata_correction_init(t, tc); ok = true; } } diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 95249f4d17b..f86bcc41bee 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -1049,11 +1049,11 @@ static void TRANSFORM_OT_bbone_resize(struct wmOperatorType *ot) ot->exec = transform_exec; ot->modal = transform_modal; ot->cancel = transform_cancel; - ot->poll = ED_operator_editarmature; + ot->poll = ED_operator_object_active; ot->poll_property = transform_poll_property; RNA_def_float_translation( - ot->srna, "value", 2, VecOne, -FLT_MAX, FLT_MAX, "Display Size", "", -FLT_MAX, FLT_MAX); + ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Display Size", "", -FLT_MAX, FLT_MAX); WM_operatortype_props_advanced_begin(ot); diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index b508507cd4e..2943c3cb8ea 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -22,23 +22,13 @@ */ #include <float.h> -#include <math.h> -#include <stdio.h> -#include <stdlib.h> #include "PIL_time.h" -#include "DNA_node_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_screen_types.h" -#include "DNA_space_types.h" -#include "DNA_view3d_types.h" #include "DNA_windowmanager_types.h" #include "BLI_blenlib.h" #include "BLI_math.h" -#include "BLI_utildefines.h" #include "GPU_immediate.h" #include "GPU_state.h" @@ -58,7 +48,6 @@ #include "ED_node.h" #include "ED_transform_snap_object_context.h" #include "ED_uvedit.h" -#include "ED_view3d.h" #include "UI_resources.h" #include "UI_view2d.h" @@ -80,10 +69,6 @@ static void setSnappingCallback(TransInfo *t); -static void ApplySnapTranslation(TransInfo *t, float vec[3]); -static void ApplySnapRotation(TransInfo *t, float *vec); -static void ApplySnapResize(TransInfo *t, float vec[2]); - /* static void CalcSnapGrid(TransInfo *t, float *vec); */ static void CalcSnapGeometry(TransInfo *t, float *vec); @@ -92,10 +77,6 @@ static void TargetSnapCenter(TransInfo *t); static void TargetSnapClosest(TransInfo *t); static void TargetSnapActive(TransInfo *t); -static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3]); -static float TranslationBetween(TransInfo *t, const float p1[3], const float p2[3]); -static float ResizeBetween(TransInfo *t, const float p1[3], const float p2[3]); - /** \} */ /* -------------------------------------------------------------------- */ @@ -143,6 +124,12 @@ bool transformModeUseSnap(const TransInfo *t) if (t->mode == TFM_RESIZE) { return (ts->snap_transform_mode_flag & SCE_SNAP_TRANSFORM_MODE_SCALE) != 0; } + if (t->mode == TFM_VERT_SLIDE) { + return true; + } + if (t->mode == TFM_EDGE_SLIDE) { + return true; + } return false; } @@ -476,7 +463,6 @@ void resetSnapping(TransInfo *t) t->tsnap.modeSelect = 0; t->tsnap.target = 0; t->tsnap.last = 0; - t->tsnap.applySnap = NULL; t->tsnap.snapNormal[0] = 0; t->tsnap.snapNormal[1] = 0; @@ -557,35 +543,32 @@ static void initSnappingMode(TransInfo *t) t->tsnap.mode = ts->snap_mode; } - if ((t->spacetype == SPACE_VIEW3D || t->spacetype == SPACE_IMAGE) && /* Only 3D view or UV */ - (t->flag & T_CAMERA) == 0) /* Not with camera selected in camera view */ - { + if ((t->spacetype == SPACE_VIEW3D || t->spacetype == SPACE_IMAGE) && (t->flag & T_CAMERA) == 0) { + /* Only 3D view or UV. */ + /* Not with camera selected in camera view. */ + setSnappingCallback(t); - /* Edit mode */ - if (t->tsnap.applySnap != NULL && // A snapping function actually exist - ((obedit_type != -1) && - /* Temporary limited to edit mode meshes, armature, curves, metaballs. */ - ELEM(obedit_type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL))) { - /* Exclude editmesh if using proportional edit */ + if ((obedit_type != -1) && + ELEM(obedit_type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) { + /* Edit mode */ + /* Temporary limited to edit mode meshes, armature, curves, metaballs. */ + if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) { + /* Exclude editmesh if using proportional edit */ t->tsnap.modeSelect = SNAP_NOT_ACTIVE; } else { t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_ACTIVE; } } - /* Particles edit mode*/ - else if (t->tsnap.applySnap != NULL && // A snapping function actually exist - ((obedit_type == -1) && base_act && base_act->object && - base_act->object->mode & OB_MODE_PARTICLE_EDIT)) { + else if ((obedit_type == -1) && base_act && base_act->object && + (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) { + /* Particles edit mode. */ t->tsnap.modeSelect = SNAP_ALL; } - /* Object mode */ - else if (t->tsnap.applySnap != NULL && // A snapping function actually exist - (obedit_type == -1)) // Object Mode - { - + else if (obedit_type == -1) { + /* Object mode */ if (t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR | CTX_OBMODE_XFORM_OBDATA)) { /* In "Edit Strokes" mode, * snap tool can perform snap to selected or active objects (see T49632) @@ -605,14 +588,7 @@ static void initSnappingMode(TransInfo *t) } else if (t->spacetype == SPACE_NODE) { setSnappingCallback(t); - - if (t->tsnap.applySnap != NULL) { - t->tsnap.modeSelect = SNAP_NOT_SELECTED; - } - else { - /* Grid if snap is not possible */ - t->tsnap.mode = SCE_SNAP_MODE_INCREMENT; - } + t->tsnap.modeSelect = SNAP_NOT_SELECTED; } else if (t->spacetype == SPACE_SEQ) { /* We do our own snapping currently, so nothing here */ @@ -720,8 +696,13 @@ static void setSnappingCallback(TransInfo *t) t->tsnap.targetSnap = TargetSnapClosest; break; case SCE_SNAP_TARGET_CENTER: - t->tsnap.targetSnap = TargetSnapCenter; - break; + if (!ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) { + t->tsnap.targetSnap = TargetSnapCenter; + break; + } + /* Can't do TARGET_CENTER with these modes, + * use TARGET_MEDIAN instead. */ + ATTR_FALLTHROUGH; case SCE_SNAP_TARGET_MEDIAN: t->tsnap.targetSnap = TargetSnapMedian; break; @@ -729,36 +710,6 @@ static void setSnappingCallback(TransInfo *t) t->tsnap.targetSnap = TargetSnapActive; break; } - - switch (t->mode) { - case TFM_TRANSLATION: - t->tsnap.applySnap = ApplySnapTranslation; - t->tsnap.distance = TranslationBetween; - break; - case TFM_ROTATION: - t->tsnap.applySnap = ApplySnapRotation; - t->tsnap.distance = RotationBetween; - - // Can't do TARGET_CENTER with rotation, use TARGET_MEDIAN instead - if (t->tsnap.target == SCE_SNAP_TARGET_CENTER) { - t->tsnap.target = SCE_SNAP_TARGET_MEDIAN; - t->tsnap.targetSnap = TargetSnapMedian; - } - break; - case TFM_RESIZE: - t->tsnap.applySnap = ApplySnapResize; - t->tsnap.distance = ResizeBetween; - - // Can't do TARGET_CENTER with resize, use TARGET_MEDIAN instead - if (t->tsnap.target == SCE_SNAP_TARGET_CENTER) { - t->tsnap.target = SCE_SNAP_TARGET_MEDIAN; - t->tsnap.targetSnap = TargetSnapMedian; - } - break; - default: - t->tsnap.applySnap = NULL; - break; - } } void addSnapPoint(TransInfo *t) @@ -859,145 +810,6 @@ void getSnapPoint(const TransInfo *t, float vec[3]) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Apply Snap - * \{ */ - -static void ApplySnapTranslation(TransInfo *t, float vec[3]) -{ - float point[3]; - getSnapPoint(t, point); - - if (t->spacetype == SPACE_NODE) { - char border = t->tsnap.snapNodeBorder; - if (border & (NODE_LEFT | NODE_RIGHT)) { - vec[0] = point[0] - t->tsnap.snapTarget[0]; - } - if (border & (NODE_BOTTOM | NODE_TOP)) { - vec[1] = point[1] - t->tsnap.snapTarget[1]; - } - } - else { - if (t->spacetype == SPACE_VIEW3D) { - if (t->options & CTX_PAINT_CURVE) { - if (ED_view3d_project_float_global(t->region, point, point, V3D_PROJ_TEST_NOP) != - V3D_PROJ_RET_OK) { - zero_v3(point); /* no good answer here... */ - } - } - } - - sub_v3_v3v3(vec, point, t->tsnap.snapTarget); - } -} - -static void ApplySnapRotation(TransInfo *t, float *value) -{ - float point[3]; - getSnapPoint(t, point); - - float dist = RotationBetween(t, t->tsnap.snapTarget, point); - *value = dist; -} - -static void ApplySnapResize(TransInfo *t, float vec[3]) -{ - float point[3]; - getSnapPoint(t, point); - - float dist = ResizeBetween(t, t->tsnap.snapTarget, point); - if (dist != TRANSFORM_DIST_INVALID) { - copy_v3_fl(vec, dist); - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Distance - * \{ */ - -static float TranslationBetween(TransInfo *UNUSED(t), const float p1[3], const float p2[3]) -{ - return len_squared_v3v3(p1, p2); -} - -static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3]) -{ - float angle, start[3], end[3]; - - sub_v3_v3v3(start, p1, t->center_global); - sub_v3_v3v3(end, p2, t->center_global); - - // Angle around a constraint axis (error prone, will need debug) - if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) { - float axis[3], tmp[3]; - - t->con.applyRot(t, NULL, NULL, axis, NULL); - - project_v3_v3v3(tmp, end, axis); - sub_v3_v3v3(end, end, tmp); - - project_v3_v3v3(tmp, start, axis); - sub_v3_v3v3(start, start, tmp); - - normalize_v3(end); - normalize_v3(start); - - cross_v3_v3v3(tmp, start, end); - - if (dot_v3v3(tmp, axis) < 0.0f) { - angle = -acosf(dot_v3v3(start, end)); - } - else { - angle = acosf(dot_v3v3(start, end)); - } - } - else { - float mtx[3][3]; - - copy_m3_m4(mtx, t->viewmat); - - mul_m3_v3(mtx, end); - mul_m3_v3(mtx, start); - - angle = atan2f(start[1], start[0]) - atan2f(end[1], end[0]); - } - - if (angle > (float)M_PI) { - angle = angle - 2 * (float)M_PI; - } - else if (angle < -((float)M_PI)) { - angle = 2.0f * (float)M_PI + angle; - } - - return angle; -} - -static float ResizeBetween(TransInfo *t, const float p1[3], const float p2[3]) -{ - float d1[3], d2[3], len_d1; - - sub_v3_v3v3(d1, p1, t->center_global); - sub_v3_v3v3(d2, p2, t->center_global); - - if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) { - mul_m3_v3(t->con.pmtx, d1); - mul_m3_v3(t->con.pmtx, d2); - } - - project_v3_v3v3(d1, d1, d2); - - len_d1 = len_v3(d1); - - /* Use 'invalid' dist when `center == p1` (after projecting), - * in this case scale will _never_ move the point in relation to the center, - * so it makes no sense to take it into account when scaling. see: T46503 */ - return len_d1 != 0.0f ? len_v3(d2) / len_d1 : TRANSFORM_DIST_INVALID; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Calc Snap (Generic) * \{ */ @@ -1734,3 +1546,16 @@ static void applyGridIncrement( } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generic callbacks + * \{ */ + +float transform_snap_distance_len_squared_fn(TransInfo *UNUSED(t), + const float p1[3], + const float p2[3]) +{ + return len_squared_v3v3(p1, p2); +} + +/** \} */ diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h index c088cf80f0d..688661bc2cb 100644 --- a/source/blender/editors/transform/transform_snap.h +++ b/source/blender/editors/transform/transform_snap.h @@ -87,4 +87,6 @@ void addSnapPoint(TransInfo *t); eRedrawFlag updateSelectedSnapPoint(TransInfo *t); void removeSnapPoint(TransInfo *t); +float transform_snap_distance_len_squared_fn(TransInfo *t, const float p1[3], const float p2[3]); + #endif /* __TRANSFORM_SNAP_H__ */ diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 08ef5109a74..4198b4c02a3 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -367,17 +367,15 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx, * \{ */ typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx, - bool use_obedit, - bool use_backface_culling, Object *ob, float obmat[4][4], + bool use_obedit, + bool use_backface_culling, + bool is_object_active, void *data); /** * Walks through all objects in the scene to create the list of objects to snap. - * - * \param sctx: Snap context to store data. - * \param snap_select: from enum #eSnapSelect. */ static void iter_snap_objects(SnapObjectContext *sctx, Depsgraph *depsgraph, @@ -393,7 +391,6 @@ static void iter_snap_objects(SnapObjectContext *sctx, Base *base_act = view_layer->basact; for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) { - if (!BASE_VISIBLE(v3d, base)) { continue; } @@ -405,13 +402,14 @@ static void iter_snap_objects(SnapObjectContext *sctx, continue; } + const bool is_object_active = (base == base_act); if (snap_select == SNAP_NOT_SELECTED) { if ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)) { continue; } } else if (snap_select == SNAP_NOT_ACTIVE) { - if (base == base_act) { + if (is_object_active) { continue; } } @@ -421,14 +419,24 @@ static void iter_snap_objects(SnapObjectContext *sctx, DupliObject *dupli_ob; ListBase *lb = object_duplilist(depsgraph, sctx->scene, obj_eval); for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { - sob_callback( - sctx, use_object_edit_cage, use_backface_culling, dupli_ob->ob, dupli_ob->mat, data); + sob_callback(sctx, + dupli_ob->ob, + dupli_ob->mat, + use_object_edit_cage, + use_backface_culling, + is_object_active, + data); } free_object_duplilist(lb); } - sob_callback( - sctx, use_object_edit_cage, use_backface_culling, obj_eval, obj_eval->obmat, data); + sob_callback(sctx, + obj_eval, + obj_eval->obmat, + use_object_edit_cage, + use_backface_culling, + is_object_active, + data); } } @@ -956,10 +964,11 @@ struct RaycastObjUserData { * \note Duplicate args here are documented at #snapObjectsRay */ static void raycast_obj_fn(SnapObjectContext *sctx, - bool use_obedit, - bool use_backface_culling, Object *ob, float obmat[4][4], + bool use_obedit, + bool use_backface_culling, + bool is_object_active, void *data) { struct RaycastObjUserData *dt = data; @@ -1032,24 +1041,26 @@ static void raycast_obj_fn(SnapObjectContext *sctx, case OB_CURVE: case OB_SURF: case OB_FONT: { - Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); - if (mesh_eval) { - retval = raycastMesh(sctx, - dt->ray_start, - dt->ray_dir, - ob, - mesh_eval, - obmat, - ob_index, - false, - use_backface_culling, - ray_depth, - dt->r_loc, - dt->r_no, - dt->r_index, - dt->r_hit_list); - break; + if (!is_object_active) { + Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); + if (mesh_eval) { + retval = raycastMesh(sctx, + dt->ray_start, + dt->ray_dir, + ob, + mesh_eval, + obmat, + ob_index, + false, + use_backface_culling, + ray_depth, + dt->r_loc, + dt->r_no, + dt->r_index, + dt->r_hit_list); + } } + break; } } @@ -1071,9 +1082,7 @@ static void raycast_obj_fn(SnapObjectContext *sctx, * Walks through all objects in the scene to find the `hit` on object surface. * * \param sctx: Snap context to store data. - * \param snap_select: from enum eSnapSelect. - * \param use_object_edit_cage: Uses the coordinates of BMesh(if any) to do the snapping. - * \param obj_list: List with objects to snap (created in `create_object_list`). + * \param params: Snapping behavior. * * Read/Write Args * --------------- @@ -2054,15 +2063,15 @@ static short snapCurve(SnapData *snapdata, } /* may extend later (for now just snaps to empty center) */ -static short snapEmpty(SnapData *snapdata, - Object *ob, - const float obmat[4][4], - /* read/write args */ - float *dist_px, - /* return args */ - float r_loc[3], - float *UNUSED(r_no), - int *r_index) +static short snap_object_center(SnapData *snapdata, + Object *ob, + const float obmat[4][4], + /* read/write args */ + float *dist_px, + /* return args */ + float r_loc[3], + float *UNUSED(r_no), + int *r_index) { short retval = 0; @@ -2117,7 +2126,7 @@ static short snapCamera(const SnapObjectContext *sctx, float *dist_px, /* return args */ float r_loc[3], - float *UNUSED(r_no), + float *r_no, int *r_index) { short retval = 0; @@ -2132,7 +2141,7 @@ static short snapCamera(const SnapObjectContext *sctx, MovieTracking *tracking; if (clip == NULL) { - return retval; + return snap_object_center(snapdata, object, obmat, dist_px, r_loc, r_no, r_index); } if (object->transflag & OB_DUPLI) { return retval; @@ -2650,11 +2659,12 @@ struct SnapObjUserData { * * \note Duplicate args here are documented at #snapObjectsRay */ -static void sanp_obj_fn(SnapObjectContext *sctx, - bool use_obedit, - bool use_backface_culling, +static void snap_obj_fn(SnapObjectContext *sctx, Object *ob, float obmat[4][4], + bool use_obedit, + bool use_backface_culling, + bool UNUSED(is_object_active), void *data) { struct SnapObjUserData *dt = data; @@ -2729,10 +2739,10 @@ static void sanp_obj_fn(SnapObjectContext *sctx, break; } case OB_EMPTY: - retval = snapEmpty(dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); - break; case OB_GPENCIL: - retval = snapEmpty(dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); + case OB_LAMP: + retval = snap_object_center( + dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); break; case OB_CAMERA: retval = snapCamera( @@ -2800,7 +2810,7 @@ static short snapObjectsRay(SnapObjectContext *sctx, .ret = 0, }; - iter_snap_objects(sctx, depsgraph, params, sanp_obj_fn, &data); + iter_snap_objects(sctx, depsgraph, params, snap_obj_fn, &data); return data.ret; } @@ -3205,7 +3215,7 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx, * \param mval: Screenspace coordinate. * \param prev_co: Coordinate for perpendicular point calculation (optional). * \param dist_px: Maximum distance to snap (in pixels). - * \param r_co: hit location. + * \param r_loc: hit location. * \param r_no: hit normal (optional). * \return Snap success */ |