diff options
Diffstat (limited to 'source/blender/editors/transform')
-rw-r--r-- | source/blender/editors/transform/transform.c | 92 | ||||
-rw-r--r-- | source/blender/editors/transform/transform.h | 5 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_constraints.c | 9 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_conversions.c | 240 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_generics.c | 30 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_manipulator.c | 555 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_manipulator2d.c | 147 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_ops.c | 29 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_orientations.c | 48 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_snap.c | 19 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_snap_object.c | 1454 |
11 files changed, 1598 insertions, 1030 deletions
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 81d8f64045f..4745631e85c 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -52,7 +52,7 @@ #include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_ghash.h" -#include "BLI_stackdefines.h" +#include "BLI_utildefines_stack.h" #include "BLI_memarena.h" #include "BKE_nla.h" @@ -66,6 +66,8 @@ #include "BKE_report.h" #include "BKE_workspace.h" +#include "DEG_depsgraph.h" + #include "BIF_glutil.h" #include "GPU_immediate.h" @@ -1731,7 +1733,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) glLineWidth(1.0f); - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_COLOR); + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); float viewport_size[4]; glGetFloatv(GL_VIEWPORT, viewport_size); @@ -1904,7 +1906,7 @@ static void drawTransformPixel(const struct bContext *UNUSED(C), ARegion *ar, vo TransInfo *t = arg; Scene *scene = t->scene; SceneLayer *sl = t->scene_layer; - Object *ob = OBACT_NEW; + Object *ob = OBACT_NEW(sl); /* draw autokeyframing hint in the corner * - only draw if enabled (advanced users may be distracted/annoyed), @@ -2015,8 +2017,10 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) View3D *v3d = t->view; v3d->twmode = t->current_orientation; - BLI_assert(BKE_workspace_transform_orientation_get_index(CTX_wm_workspace(C), t->custom_orientation) - == v3d->custom_orientation_index); + + BLI_assert(((v3d->custom_orientation_index == -1) && (t->custom_orientation == NULL)) || + (BKE_workspace_transform_orientation_get_index( + CTX_wm_workspace(C), t->custom_orientation) == v3d->custom_orientation_index)); } } } @@ -2621,6 +2625,9 @@ static void constraintTransLim(TransInfo *t, TransData *td) if (td->con) { const bConstraintTypeInfo *ctiLoc = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_LOCLIMIT); const bConstraintTypeInfo *ctiDist = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_DISTLIMIT); + EvaluationContext eval_ctx; + + CTX_data_eval_ctx(t->context, &eval_ctx); bConstraintOb cob = {NULL}; bConstraint *con; @@ -2670,7 +2677,7 @@ static void constraintTransLim(TransInfo *t, TransData *td) } /* get constraint targets if needed */ - BKE_constraint_targets_for_solving_get(con, &cob, &targets, ctime); + BKE_constraint_targets_for_solving_get(&eval_ctx, con, &cob, &targets, ctime); /* do constraint */ cti->evaluate_constraint(con, &cob, &targets); @@ -2916,7 +2923,9 @@ static void initBend(TransInfo *t) t->flag |= T_NO_CONSTRAINT; //copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view)); - calculateCenterCursor(t, t->center); + if ((t->flag & T_OVERRIDE_CENTER) == 0) { + calculateCenterCursor(t, t->center); + } calculateCenterGlobal(t, t->center, t->center_global); t->val = 0.0f; @@ -4097,13 +4106,15 @@ static void initTrackball(TransInfo *t) static void applyTrackballValue(TransInfo *t, const float axis1[3], const float axis2[3], float angles[2]) { TransData *td = t->data; - float mat[3][3], smat[3][3], totmat[3][3]; + float mat[3][3]; + float axis[3]; + float angle; int i; - axis_angle_normalized_to_mat3(smat, axis1, angles[0]); - axis_angle_normalized_to_mat3(totmat, axis2, angles[1]); - - mul_m3_m3m3(mat, smat, totmat); + mul_v3_v3fl(axis, axis1, angles[0]); + madd_v3_v3fl(axis, axis2, angles[1]); + angle = normalize_v3(axis); + axis_angle_normalized_to_mat3(mat, axis, angle); for (i = 0; i < t->total; i++, td++) { if (td->flag & TD_NOACTION) @@ -4113,10 +4124,7 @@ static void applyTrackballValue(TransInfo *t, const float axis1[3], const float continue; if (t->flag & T_PROP_EDIT) { - axis_angle_normalized_to_mat3(smat, axis1, td->factor * angles[0]); - axis_angle_normalized_to_mat3(totmat, axis2, td->factor * angles[1]); - - mul_m3_m3m3(mat, smat, totmat); + axis_angle_normalized_to_mat3(mat, axis, td->factor * angle); } ElementRotation(t, td, mat, t->around); @@ -7556,7 +7564,7 @@ static void drawVertSlide(TransInfo *t) glLineWidth(1.0f); - immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); float viewport_size[4]; glGetFloatv(GL_VIEWPORT, viewport_size); @@ -8393,8 +8401,15 @@ static void initTimeSlide(TransInfo *t) TransData *td = t->data; for (i = 0; i < t->total; i++, td++) { - if (min > *(td->val)) min = *(td->val); - if (max < *(td->val)) max = *(td->val); + AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; + float val = *(td->val); + + /* strip/action time to global (mapped) time */ + if (adt) + val = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_MAP); + + if (min > val) min = val; + if (max < val) max = val; } if (min == max) { @@ -8469,25 +8484,38 @@ static void applyTimeSlideValue(TransInfo *t, float sval) */ AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; float cval = t->values[0]; - - /* apply NLA-mapping to necessary values */ - if (adt) - cval = BKE_nla_tweakedit_remap(adt, cval, NLATIME_CONVERT_UNMAP); - + /* only apply to data if in range */ if ((sval > minx) && (sval < maxx)) { float cvalc = CLAMPIS(cval, minx, maxx); + float ival = td->ival; float timefac; - + + /* NLA mapping magic here works as follows: + * - "ival" goes from strip time to global time + * - calculation is performed into td->val in global time + * (since sval and min/max are all in global time) + * - "td->val" then gets put back into strip time + */ + if (adt) { + /* strip to global */ + ival = BKE_nla_tweakedit_remap(adt, ival, NLATIME_CONVERT_MAP); + } + /* left half? */ - if (td->ival < sval) { - timefac = (sval - td->ival) / (sval - minx); + if (ival < sval) { + timefac = (sval - ival) / (sval - minx); *(td->val) = cvalc - timefac * (cvalc - minx); } else { - timefac = (td->ival - sval) / (maxx - sval); + timefac = (ival - sval) / (maxx - sval); *(td->val) = cvalc + timefac * (maxx - cvalc); } + + if (adt) { + /* global to strip */ + *(td->val) = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_UNMAP); + } } } } @@ -8546,9 +8574,11 @@ static void initTimeScale(TransInfo *t) /* recalculate center2d to use CFRA and mouse Y, since that's * what is used in time scale */ - t->center[0] = t->scene->r.cfra; - projectFloatView(t, t->center, center); - center[1] = t->mouse.imval[1]; + if ((t->flag & T_OVERRIDE_CENTER) == 0) { + t->center[0] = t->scene->r.cfra; + projectFloatView(t, t->center, center); + center[1] = t->mouse.imval[1]; + } /* force a reinit with the center2d used here */ initMouseInput(t, &t->mouse, center, t->mouse.imval, false); diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index d415b3eabeb..92eb31aabe6 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -535,6 +535,9 @@ typedef struct TransInfo { /* alternative transformation. used to add offset to tracking markers */ #define T_ALT_TRANSFORM (1 << 24) + /** #TransInfo.center has been set, don't change it. */ +#define T_OVERRIDE_CENTER (1 << 25) + /* TransInfo->modifiers */ #define MOD_CONSTRAINT_SELECT 0x01 #define MOD_PRECISION 0x02 @@ -638,7 +641,7 @@ void restoreBones(TransInfo *t); /*********************** transform_manipulator.c ********** */ -#define MANIPULATOR_AXIS_LINE_WIDTH 2.0 +#define MANIPULATOR_AXIS_LINE_WIDTH 2.0f bool gimbal_axis(struct Object *ob, float gmat[3][3]); /* return 0 when no gimbal for selection */ diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 654072766a8..4e409e7f77f 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -735,7 +735,7 @@ void drawConstraint(TransInfo *t) const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); float viewport_size[4]; glGetFloatv(GL_VIEWPORT, viewport_size); @@ -851,6 +851,13 @@ static void drawObjectConstraint(TransInfo *t) } } + if (t->options & CTX_GPENCIL_STROKES) { + /* only draw a constraint line for one point, otherwise we can't see anything */ + if ((options & DRAWLIGHT) == 0) { + break; + } + } + if (t->flag & T_OBJECT) { copy_v3_v3(co, td->ob->obmat[3]); axismtx = td->axismtx; diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 243788c20b3..166a5805fa1 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -292,7 +292,7 @@ static void createTransTexspace(TransInfo *t) ID *id; short *texflag; - ob = OBACT_NEW; + ob = OBACT_NEW(sl); if (ob == NULL) { // Shouldn't logically happen, but still... t->total = 0; @@ -772,29 +772,37 @@ int count_set_pose_transflags(int *out_mode, short around, Object *ob) /* -------- Auto-IK ---------- */ /* adjust pose-channel's auto-ik chainlen */ -static void pchan_autoik_adjust(bPoseChannel *pchan, short chainlen) +static bool pchan_autoik_adjust(bPoseChannel *pchan, short chainlen) { bConstraint *con; + bool changed = false; /* don't bother to search if no valid constraints */ - if ((pchan->constflag & (PCHAN_HAS_IK | PCHAN_HAS_TARGET)) == 0) - return; + if ((pchan->constflag & (PCHAN_HAS_IK | PCHAN_HAS_TARGET)) == 0) { + return changed; + } /* check if pchan has ik-constraint */ for (con = pchan->constraints.first; con; con = con->next) { if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce != 0.0f)) { bKinematicConstraint *data = con->data; - + /* only accept if a temporary one (for auto-ik) */ if (data->flag & CONSTRAINT_IK_TEMP) { /* chainlen is new chainlen, but is limited by maximum chainlen */ - if ((chainlen == 0) || (chainlen > data->max_rootbone)) + const int old_rootbone = data->rootbone; + if ((chainlen == 0) || (chainlen > data->max_rootbone)) { data->rootbone = data->max_rootbone; - else + } + else { data->rootbone = chainlen; + } + changed |= (data->rootbone != old_rootbone); } } } + + return changed; } /* change the chain-length of auto-ik */ @@ -810,7 +818,13 @@ void transform_autoik_update(TransInfo *t, short mode) } else if (mode == -1) { /* mode==-1 is from WHEELMOUSEUP... decreases len */ - if (*chainlen > 0) (*chainlen)--; + if (*chainlen > 0) { + (*chainlen)--; + } + else { + /* IK length did not change, skip updates. */ + return; + } } /* sanity checks (don't assume t->poseobj is set, or that it is an armature) */ @@ -818,8 +832,14 @@ void transform_autoik_update(TransInfo *t, short mode) return; /* apply to all pose-channels */ + bool changed = false; for (pchan = t->poseobj->pose->chanbase.first; pchan; pchan = pchan->next) { - pchan_autoik_adjust(pchan, *chainlen); + changed |= pchan_autoik_adjust(pchan, *chainlen); + } + + if (changed) { + /* TODO(sergey): Consider doing partial update only. */ + DEG_relations_tag_update(G.main); } } @@ -829,6 +849,7 @@ static void pose_grab_with_ik_clear(Object *ob) bKinematicConstraint *data; bPoseChannel *pchan; bConstraint *con, *next; + bool relations_changed = false; for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { /* clear all temporary lock flags */ @@ -842,6 +863,8 @@ static void pose_grab_with_ik_clear(Object *ob) if (con->type == CONSTRAINT_TYPE_KINEMATIC) { data = con->data; if (data->flag & CONSTRAINT_IK_TEMP) { + relations_changed = true; + /* iTaSC needs clear for removed constraints */ BIK_clear_data(ob->pose); @@ -857,8 +880,10 @@ static void pose_grab_with_ik_clear(Object *ob) } } - /* TODO(sergey): Consider doing partial update only. */ - DEG_relations_tag_update(G.main); + if (relations_changed) { + /* TODO(sergey): Consider doing partial update only. */ + DEG_relations_tag_update(G.main); + } } /* adds the IK to pchan - returns if added */ @@ -1485,6 +1510,48 @@ static TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struc return hdata; } +/** + * For the purpose of transform code we need to behave as if handles are selected, + * even when they aren't (see special case below). + */ +static int bezt_select_to_transform_triple_flag( + const BezTriple *bezt, const bool hide_handles) +{ + int flag = 0; + + if (hide_handles) { + if (bezt->f2 & SELECT) { + flag = (1 << 0) | (1 << 1) | (1 << 2); + } + } + else { + flag = ( + ((bezt->f1 & SELECT) ? (1 << 0) : 0) | + ((bezt->f2 & SELECT) ? (1 << 1) : 0) | + ((bezt->f3 & SELECT) ? (1 << 2) : 0) + ); + } + + /* Special case for auto & aligned handles: + * When a center point is being moved without the handles, + * leaving the handles stationary makes no sense and only causes strange behavior, + * where one handle is arbitrarily anchored, the other one is aligned and lengthened + * based on where the center point is moved. Also a bug when cancelling, see: T52007. + * + * A more 'correct' solution could be to store handle locations in 'TransDataCurveHandleFlags'. + * However that doesn't resolve odd behavior, so best transform the handles in this case. + */ + if ((flag != ((1 << 0) | (1 << 1) | (1 << 2))) && (flag & (1 << 1))) { + if (ELEM(bezt->h1, HD_AUTO, HD_ALIGN) && + ELEM(bezt->h2, HD_AUTO, HD_ALIGN)) + { + flag = (1 << 0) | (1 << 1) | (1 << 2); + } + } + + return flag; +} + static void createTransCurveVerts(TransInfo *t) { Curve *cu = t->obedit->data; @@ -1502,22 +1569,22 @@ static void createTransCurveVerts(TransInfo *t) /* to be sure */ if (cu->editnurb == NULL) return; +#define SEL_F1 (1 << 0) +#define SEL_F2 (1 << 1) +#define SEL_F3 (1 << 2) + /* count total of vertices, check identical as in 2nd loop for making transdata! */ nurbs = BKE_curve_editNurbs_get(cu); for (nu = nurbs->first; nu; nu = nu->next) { if (nu->type == CU_BEZIER) { for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) { if (bezt->hide == 0) { - if (hide_handles) { - if (bezt->f2 & SELECT) countsel += 3; - if (is_prop_edit) count += 3; - } - else { - if (bezt->f1 & SELECT) countsel++; - if (bezt->f2 & SELECT) countsel++; - if (bezt->f3 & SELECT) countsel++; - if (is_prop_edit) count += 3; - } + const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles); + if (bezt_tx & SEL_F1) { countsel++; } + if (bezt_tx & SEL_F2) { countsel++; } + if (bezt_tx & SEL_F3) { countsel++; } + if (is_prop_edit) count += 3; + } } } @@ -1568,10 +1635,10 @@ static void createTransCurveVerts(TransInfo *t) } } - if (is_prop_edit || - ((bezt->f2 & SELECT) && hide_handles) || - ((bezt->f1 & SELECT) && hide_handles == 0)) - { + /* Elements that will be transform (not always a match to selection). */ + const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles); + + if (is_prop_edit || bezt_tx & SEL_F1) { copy_v3_v3(td->iloc, bezt->vec[0]); td->loc = bezt->vec[0]; copy_v3_v3(td->center, bezt->vec[(hide_handles || @@ -1602,7 +1669,7 @@ static void createTransCurveVerts(TransInfo *t) } /* This is the Curve Point, the other two are handles */ - if (is_prop_edit || (bezt->f2 & SELECT)) { + if (is_prop_edit || bezt_tx & SEL_F2) { copy_v3_v3(td->iloc, bezt->vec[1]); td->loc = bezt->vec[1]; copy_v3_v3(td->center, td->loc); @@ -1628,7 +1695,7 @@ static void createTransCurveVerts(TransInfo *t) copy_m3_m3(td->axismtx, axismtx); } - if ((bezt->f1 & SELECT) == 0 && (bezt->f3 & SELECT) == 0) + if ((bezt_tx & SEL_F1) == 0 && (bezt_tx & SEL_F3) == 0) /* If the middle is selected but the sides arnt, this is needed */ if (hdata == NULL) { /* if the handle was not saved by the previous handle */ hdata = initTransDataCurveHandles(td, bezt); @@ -1638,10 +1705,7 @@ static void createTransCurveVerts(TransInfo *t) count++; tail++; } - if (is_prop_edit || - ((bezt->f2 & SELECT) && hide_handles) || - ((bezt->f3 & SELECT) && hide_handles == 0)) - { + if (is_prop_edit || bezt_tx & SEL_F3) { copy_v3_v3(td->iloc, bezt->vec[2]); td->loc = bezt->vec[2]; copy_v3_v3(td->center, bezt->vec[(hide_handles || @@ -1696,6 +1760,26 @@ static void createTransCurveVerts(TransInfo *t) for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) { if (bp->hide == 0) { if (is_prop_edit || (bp->f1 & SELECT)) { + float axismtx[3][3]; + + if (t->around == V3D_AROUND_LOCAL_ORIGINS) { + if (nu->pntsv == 1) { + float normal[3], plane[3]; + + BKE_nurb_bpoint_calc_normal(nu, bp, normal); + BKE_nurb_bpoint_calc_plane(nu, bp, plane); + + if (createSpaceNormalTangent(axismtx, normal, plane)) { + /* pass */ + } + else { + normalize_v3(normal); + axis_dominant_v3_to_m3(axismtx, normal); + invert_m3(axismtx); + } + } + } + copy_v3_v3(td->iloc, bp->vec); td->loc = bp->vec; copy_v3_v3(td->center, td->loc); @@ -1714,6 +1798,11 @@ static void createTransCurveVerts(TransInfo *t) copy_m3_m3(td->smtx, smtx); copy_m3_m3(td->mtx, mtx); + if (t->around == V3D_AROUND_LOCAL_ORIGINS) { + if (nu->pntsv == 1) { + copy_m3_m3(td->axismtx, axismtx); + } + } td++; count++; @@ -1729,6 +1818,10 @@ static void createTransCurveVerts(TransInfo *t) calc_distanceCurveVerts(head, tail - 1); } } + +#undef SEL_F1 +#undef SEL_F2 +#undef SEL_F3 } /* ********************* lattice *************** */ @@ -1918,7 +2011,7 @@ void flushTransParticles(TransInfo *t) { Scene *scene = t->scene; SceneLayer *sl = t->scene_layer; - Object *ob = OBACT_NEW; + Object *ob = OBACT_NEW(sl); PTCacheEdit *edit = PE_get_current(scene, sl, ob); ParticleSystem *psys = edit->psys; ParticleSystemModifierData *psmd = NULL; @@ -1958,7 +2051,9 @@ void flushTransParticles(TransInfo *t) point->flag |= PEP_EDIT_RECALC; } - PE_update_object(scene, sl, OBACT_NEW, 1); + EvaluationContext eval_ctx; + CTX_data_eval_ctx(t->context, &eval_ctx); + PE_update_object(&eval_ctx, scene, sl, OBACT_NEW(sl), 1); } /* ********************* mesh ****************** */ @@ -2370,6 +2465,7 @@ static void createTransEditVerts(TransInfo *t) { TransData *tob = NULL; TransDataExtension *tx = NULL; + EvaluationContext eval_ctx; BMEditMesh *em = BKE_editmesh_from_object(t->obedit); Mesh *me = t->obedit->data; BMesh *bm = em->bm; @@ -2388,6 +2484,10 @@ static void createTransEditVerts(TransInfo *t) int island_info_tot; int *island_vert_map = NULL; + DEG_evaluation_context_init_from_scene(&eval_ctx, + t->scene, t->scene_layer, + DAG_EVAL_VIEWPORT); + /* Even for translation this is needed because of island-orientation, see: T51651. */ const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS); /* Original index of our connected vertex when connected distances are calculated. @@ -2471,7 +2571,7 @@ static void createTransEditVerts(TransInfo *t) if (modifiers_isCorrectableDeformed(t->scene, t->obedit)) { /* check if we can use deform matrices for modifier from the * start up to stack, they are more accurate than quats */ - totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(t->scene, t->obedit, em, &defmats, &defcos); + totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(&eval_ctx, t->scene, t->obedit, em, &defmats, &defcos); } /* if we still have more modifiers, also do crazyspace @@ -2484,7 +2584,7 @@ static void createTransEditVerts(TransInfo *t) if (totleft > 0) #endif { - mappedcos = BKE_crazyspace_get_mapped_editverts(t->scene, t->obedit); + mappedcos = BKE_crazyspace_get_mapped_editverts(&eval_ctx, t->scene, t->obedit); quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats"); BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode); if (mappedcos) @@ -2694,7 +2794,7 @@ void flushTransSeq(TransInfo *t) tdsq = (TransDataSeq *)td->extra; seq = tdsq->seq; old_start = seq->start; - new_frame = iroundf(td2d->loc[0]); + new_frame = round_fl_to_int(td2d->loc[0]); switch (tdsq->sel_flag) { case SELECT: @@ -2706,7 +2806,7 @@ void flushTransSeq(TransInfo *t) seq->start = new_frame - tdsq->start_offset; #endif if (seq->depth == 0) { - seq->machine = iroundf(td2d->loc[1]); + seq->machine = round_fl_to_int(td2d->loc[1]); CLAMP(seq->machine, 1, MAXSEQ); } break; @@ -3652,7 +3752,7 @@ void flushTransIntFrameActionData(TransInfo *t) /* flush data! */ for (i = 0; i < t->total; i++, tfd++) { - *(tfd->sdata) = iroundf(tfd->val); + *(tfd->sdata) = round_fl_to_int(tfd->val); } } @@ -4680,7 +4780,7 @@ void flushTransGraphData(TransInfo *t) /* if int-values only, truncate to integers */ if (td->flag & TD_INTVALUES) - td2d->loc2d[1] = floorf(td2d->loc[1] + 0.5f); + td2d->loc2d[1] = floorf(td2d->loc[1] * inv_unit_scale - tdg->offset + 0.5f); else td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale - tdg->offset; @@ -5310,6 +5410,9 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) Scene *scene = t->scene; bool constinv; bool skip_invert = false; + EvaluationContext eval_ctx; + + CTX_data_eval_ctx(t->context, &eval_ctx); if (t->mode != TFM_DUMMY && ob->rigidbody_object) { float rot[3][3], scale[3]; @@ -5333,7 +5436,8 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) } /* update object's loc/rot to get current rigid body transform */ mat4_to_loc_rot_size(ob->loc, rot, scale, ob->obmat); - BKE_object_mat3_to_rot(ob, rot, false); + sub_v3_v3(ob->loc, ob->dloc); + BKE_object_mat3_to_rot(ob, rot, false); /* drot is already corrected here */ } } @@ -5356,11 +5460,11 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) if (skip_invert == false && constinv == false) { ob->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc_time checks this */ - BKE_object_where_is_calc(t->scene, ob); + BKE_object_where_is_calc(&eval_ctx, t->scene, ob); ob->transflag &= ~OB_NO_CONSTRAINTS; } else - BKE_object_where_is_calc(t->scene, ob); + BKE_object_where_is_calc(&eval_ctx, t->scene, ob); td->ob = ob; @@ -5451,10 +5555,14 @@ static void set_trans_object_base_flags(TransInfo *t) DEG_scene_relations_update(G.main, t->scene); /* handle pending update events, otherwise they got copied below */ + EvaluationContext eval_ctx; + DEG_evaluation_context_init_from_scene(&eval_ctx, + t->scene, t->scene_layer, + DAG_EVAL_VIEWPORT); for (base = sl->object_bases.first; base; base = base->next) { if (base->object->recalc & OB_RECALC_ALL) { /* TODO(sergey): Ideally, it's not needed. */ - BKE_object_handle_update(G.main->eval_ctx, t->scene, base->object); + BKE_object_handle_update(&eval_ctx, t->scene, base->object); } } @@ -5467,8 +5575,8 @@ static void set_trans_object_base_flags(TransInfo *t) /* if parent selected, deselect */ while (parsel) { - Base *parbase = BKE_scene_layer_base_find(sl, parsel); - if (parbase->flag & BASE_SELECTED) { + if (parsel->base_flag & BASE_SELECTED) { + Base *parbase = BKE_scene_layer_base_find(sl, parsel); if (parbase) { /* in rare cases this can fail */ if (TESTBASELIB_BGMODE_NEW(parbase)) { break; @@ -5494,6 +5602,9 @@ static void set_trans_object_base_flags(TransInfo *t) } } + /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ + DEG_scene_flush_update(G.main, t->scene); + /* and we store them temporal in base (only used for transform code) */ /* this because after doing updates, the object->recalc is cleared */ for (base = sl->object_bases.first; base; base = base->next) { @@ -5572,6 +5683,7 @@ static int count_proportional_objects(TransInfo *t) /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ DEG_scene_relations_update(G.main, t->scene); + DEG_scene_flush_update(G.main, t->scene); /* and we store them temporal in base (only used for transform code) */ /* this because after doing updates, the object->recalc is cleared */ @@ -5652,7 +5764,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, SceneLayer *sl, View3D * } else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) { if (v3d->around == V3D_AROUND_ACTIVE) { - if (ob != OBACT_NEW) + if (ob != OBACT_NEW(sl)) do_loc = true; } else if (v3d->around == V3D_AROUND_CURSOR) @@ -5663,7 +5775,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, SceneLayer *sl, View3D * } else if (tmode == TFM_RESIZE) { if (v3d->around == V3D_AROUND_ACTIVE) { - if (ob != OBACT_NEW) + if (ob != OBACT_NEW(sl)) do_loc = true; } else if (v3d->around == V3D_AROUND_CURSOR) @@ -5841,7 +5953,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o */ if (C && (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) { //ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear - ED_pose_recalculate_paths(scene, ob); + ED_pose_recalculate_paths(C, scene, ob); } } else { @@ -5859,27 +5971,23 @@ static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t) { SpaceClip *sc = t->sa->spacedata.first; MovieClip *clip = ED_space_clip_get_clip(sc); - MovieTrackingPlaneTrack *plane_track; ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); - int framenr = ED_space_clip_get_clip_frame_number(sc); - - for (plane_track = plane_tracks_base->first; + const int framenr = ED_space_clip_get_clip_frame_number(sc); + /* Update coordinates of modified plane tracks. */ + for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) { bool do_update = false; - if (plane_track->flag & PLANE_TRACK_HIDDEN) { continue; } - do_update |= PLANE_TRACK_VIEW_SELECTED(plane_track) != 0; if (do_update == false) { if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) { int i; for (i = 0; i < plane_track->point_tracksnr; i++) { MovieTrackingTrack *track = plane_track->point_tracks[i]; - if (TRACK_VIEW_SELECTED(sc, track)) { do_update = true; break; @@ -5887,15 +5995,14 @@ static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t) } } } - if (do_update) { BKE_tracking_track_plane_from_existing_motion(plane_track, framenr); } } - - if (t->scene->nodetree) { - /* tracks can be used for stabilization nodes, - * flush update for such nodes */ + if (t->scene->nodetree != NULL) { + /* Tracks can be used for stabilization nodes, + * flush update for such nodes. + */ nodeUpdateID(t->scene->nodetree, &clip->id); WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL); } @@ -6001,10 +6108,13 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) * */ void special_aftertrans_update(bContext *C, TransInfo *t) { + EvaluationContext eval_ctx; Object *ob; // short redrawipo=0, resetslowpar=1; const bool canceled = (t->state == TRANS_CANCEL); const bool duplicate = (t->mode == TFM_TIME_DUPLICATE); + + CTX_data_eval_ctx(C, &eval_ctx); /* early out when nothing happened */ if (t->total == 0 || t->mode == TFM_DUMMY) @@ -6344,7 +6454,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) * we need to update the pose otherwise no updates get called during * transform and the auto-ik is not applied. see [#26164] */ struct Object *pose_ob = t->poseobj; - BKE_pose_where_is(t->scene, pose_ob); + BKE_pose_where_is(&eval_ctx, t->scene, pose_ob); } /* set BONE_TRANSFORM flags for autokey, manipulator draw might have changed them */ @@ -7722,7 +7832,7 @@ static void createTransGPencil(bContext *C, TransInfo *t) float mtx[3][3], smtx[3][3]; const Scene *scene = CTX_data_scene(C); - const int cfra = CFRA; + const int cfra_scene = CFRA; const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0; @@ -7747,7 +7857,7 @@ static void createTransGPencil(bContext *C, TransInfo *t) if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { bGPDframe *gpf = gpl->actframe; bGPDstroke *gps; - + for (gps = gpf->strokes.first; gps; gps = gps->next) { /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) { @@ -7803,6 +7913,7 @@ static void createTransGPencil(bContext *C, TransInfo *t) for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* only editable and visible layers are considered */ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { + const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene; bGPDframe *gpf = gpl->actframe; bGPDstroke *gps; float diff_mat[4][4]; @@ -7819,7 +7930,6 @@ static void createTransGPencil(bContext *C, TransInfo *t) * - This is useful when animating as it saves that "uh-oh" moment when you realize you've * spent too much time editing the wrong frame... */ - // XXX: should this be allowed when framelock is enabled? if (gpf->framenum != cfra) { gpf = BKE_gpencil_frame_addcopy(gpl, cfra); /* in some weird situations (framelock enabled) return NULL */ @@ -7967,7 +8077,7 @@ void createTransData(bContext *C, TransInfo *t) { Scene *scene = t->scene; SceneLayer *sl = t->scene_layer; - Object *ob = OBACT_NEW; + Object *ob = OBACT_NEW(sl); /* if tests must match recalcData for correct updates */ if (t->options & CTX_TEXTURE) { diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index ca9e15f5de4..2bed1dd28f2 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -317,7 +317,7 @@ static bool fcu_test_selected(FCurve *fcu) /* helper for recalcData() - for Action Editor transforms */ static void recalcData_actedit(TransInfo *t) { - SceneLayer *sl= t->scene_layer; + SceneLayer *sl = t->scene_layer; SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first; bAnimContext ac = {NULL}; @@ -329,7 +329,7 @@ static void recalcData_actedit(TransInfo *t) /* NOTE: sync this with the code in ANIM_animdata_get_context() */ ac.scene = t->scene; ac.scene_layer = t->scene_layer; - ac.obact = OBACT_NEW; + ac.obact = OBACT_NEW(sl); ac.sa = t->sa; ac.ar = t->ar; ac.sl = (t->sa) ? t->sa->spacedata.first : NULL; @@ -379,7 +379,7 @@ static void recalcData_graphedit(TransInfo *t) /* NOTE: sync this with the code in ANIM_animdata_get_context() */ ac.scene = t->scene; ac.scene_layer = t->scene_layer; - ac.obact = OBACT_NEW; + ac.obact = OBACT_NEW(sl); ac.sa = t->sa; ac.ar = t->ar; ac.sl = (t->sa) ? t->sa->spacedata.first : NULL; @@ -714,6 +714,9 @@ static void recalcData_spaceclip(TransInfo *t) static void recalcData_objects(TransInfo *t) { Base *base = t->scene_layer->basact; + EvaluationContext eval_ctx; + + CTX_data_eval_ctx(t->context, &eval_ctx); if (t->obedit) { if (ELEM(t->obedit->type, OB_CURVE, OB_SURF)) { @@ -898,7 +901,7 @@ static void recalcData_objects(TransInfo *t) BIK_clear_data(ob->pose); } else - BKE_pose_where_is(t->scene, ob); + BKE_pose_where_is(&eval_ctx, t->scene, ob); } else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->scene, t->scene_layer, base->object)) { if (t->state != TRANS_CANCEL) { @@ -1457,6 +1460,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve #endif setTransformViewAspect(t, t->aspect); + + if (op && (prop = RNA_struct_find_property(op->ptr, "center_override")) && RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_get_array(op->ptr, prop, t->center); + mul_v3_v3(t->center, t->aspect); + t->flag |= T_OVERRIDE_CENTER; + } + setTransformViewMatrices(t); initNumInput(&t->num); } @@ -1790,7 +1800,7 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]) } else if (t->flag & T_POSE) { SceneLayer *sl = t->scene_layer; - Object *ob = OBACT_NEW; + Object *ob = OBACT_NEW(sl); if (ob) { bPoseChannel *pchan = BKE_pose_channel_active(ob); if (pchan && (!select_only || (pchan->bone->flag & BONE_SELECTED))) { @@ -1810,8 +1820,8 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]) else { /* object mode */ SceneLayer *sl = t->scene_layer; - Object *ob = OBACT_NEW; - Base *base = BASACT_NEW; + Object *ob = OBACT_NEW(sl); + Base *base = BASACT_NEW(sl); if (ob && ((!select_only) || ((base->flag & BASE_SELECTED) != 0))) { copy_v3_v3(r_center, ob->obmat[3]); ok = true; @@ -1858,7 +1868,9 @@ static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[ void calculateCenter(TransInfo *t) { - calculateCenter_FromAround(t, t->around, t->center); + if ((t->flag & T_OVERRIDE_CENTER) == 0) { + calculateCenter_FromAround(t, t->around, t->center); + } calculateCenterGlobal(t, t->center, t->center_global); /* avoid calculating again */ @@ -1872,7 +1884,7 @@ void calculateCenter(TransInfo *t) calculateCenter2D(t); /* for panning from cameraview */ - if (t->flag & T_OBJECT) { + if ((t->flag & T_OBJECT) && (t->flag & T_OVERRIDE_CENTER) == 0) { if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) { if (t->flag & T_CAMERA) { diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 0f5f2f02e84..c0c7c922061 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -86,6 +86,8 @@ #include "GPU_immediate.h" #include "GPU_matrix.h" +// #define USE_AXIS_BOUNDS + /* return codes for select, and drawing flags */ #define MAN_TRANS_X (1 << 0) @@ -114,27 +116,31 @@ enum { MAN_AXIS_TRANS_Z, MAN_AXIS_TRANS_C, + MAN_AXIS_TRANS_XY, + MAN_AXIS_TRANS_YZ, + MAN_AXIS_TRANS_ZX, +#define MAN_AXIS_RANGE_TRANS_START MAN_AXIS_TRANS_X +#define MAN_AXIS_RANGE_TRANS_END (MAN_AXIS_TRANS_ZX + 1) + MAN_AXIS_ROT_X, MAN_AXIS_ROT_Y, MAN_AXIS_ROT_Z, MAN_AXIS_ROT_C, MAN_AXIS_ROT_T, /* trackball rotation */ +#define MAN_AXIS_RANGE_ROT_START MAN_AXIS_ROT_X +#define MAN_AXIS_RANGE_ROT_END (MAN_AXIS_ROT_T + 1) MAN_AXIS_SCALE_X, MAN_AXIS_SCALE_Y, MAN_AXIS_SCALE_Z, MAN_AXIS_SCALE_C, - - /* special */ - MAN_AXIS_TRANS_XY, - MAN_AXIS_TRANS_YZ, - MAN_AXIS_TRANS_ZX, - MAN_AXIS_SCALE_XY, MAN_AXIS_SCALE_YZ, MAN_AXIS_SCALE_ZX, +#define MAN_AXIS_RANGE_SCALE_START MAN_AXIS_SCALE_X +#define MAN_AXIS_RANGE_SCALE_END (MAN_AXIS_SCALE_ZX + 1) - MAN_AXIS_LAST, + MAN_AXIS_LAST = MAN_AXIS_RANGE_SCALE_END, }; /* axis types */ @@ -148,29 +154,19 @@ enum { typedef struct ManipulatorGroup { bool all_hidden; - struct wmManipulator *translate_x, - *translate_y, - *translate_z, - *translate_xy, - *translate_yz, - *translate_zx, - *translate_c, - - *rotate_x, - *rotate_y, - *rotate_z, - *rotate_c, - *rotate_t, /* trackball rotation */ - - *scale_x, - *scale_y, - *scale_z, - *scale_xy, - *scale_yz, - *scale_zx, - *scale_c; + struct wmManipulator *manipulators[MAN_AXIS_LAST]; } ManipulatorGroup; +struct TransformBounds { + float center[3]; /* Center for transform widget. */ + float min[3], max[3]; /* Boundbox of selection for transform widget. */ + +#ifdef USE_AXIS_BOUNDS + /* Normalized axis */ + float axis[3][3]; + float axis_min[3], axis_max[3]; +#endif +}; /* **************** Utilities **************** */ @@ -189,93 +185,78 @@ typedef struct ManipulatorGroup { static wmManipulator *manipulator_get_axis_from_index(const ManipulatorGroup *man, const short axis_idx) { BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN_AXIS_TRANS_X, (float)MAN_AXIS_LAST)); - - switch (axis_idx) { - case MAN_AXIS_TRANS_X: - return man->translate_x; - case MAN_AXIS_TRANS_Y: - return man->translate_y; - case MAN_AXIS_TRANS_Z: - return man->translate_z; - case MAN_AXIS_TRANS_XY: - return man->translate_xy; - case MAN_AXIS_TRANS_YZ: - return man->translate_yz; - case MAN_AXIS_TRANS_ZX: - return man->translate_zx; - case MAN_AXIS_TRANS_C: - return man->translate_c; - case MAN_AXIS_ROT_X: - return man->rotate_x; - case MAN_AXIS_ROT_Y: - return man->rotate_y; - case MAN_AXIS_ROT_Z: - return man->rotate_z; - case MAN_AXIS_ROT_C: - return man->rotate_c; - case MAN_AXIS_ROT_T: - return man->rotate_t; - case MAN_AXIS_SCALE_X: - return man->scale_x; - case MAN_AXIS_SCALE_Y: - return man->scale_y; - case MAN_AXIS_SCALE_Z: - return man->scale_z; - case MAN_AXIS_SCALE_XY: - return man->scale_xy; - case MAN_AXIS_SCALE_YZ: - return man->scale_yz; - case MAN_AXIS_SCALE_ZX: - return man->scale_zx; - case MAN_AXIS_SCALE_C: - return man->scale_c; - } - - return NULL; + return man->manipulators[axis_idx]; } -static short manipulator_get_axis_type(const ManipulatorGroup *man, const wmManipulator *axis) +static short manipulator_get_axis_type(const int axis_idx) { - if (ELEM(axis, man->translate_x, man->translate_y, man->translate_z, man->translate_c, - man->translate_xy, man->translate_yz, man->translate_zx)) - { + if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) { return MAN_AXES_TRANSLATE; } - else if (ELEM(axis, man->rotate_x, man->rotate_y, man->rotate_z, man->rotate_c, man->rotate_t)) { + if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) { return MAN_AXES_ROTATE; } - else { + if (axis_idx >= MAN_AXIS_RANGE_SCALE_START && axis_idx < MAN_AXIS_RANGE_SCALE_END) { return MAN_AXES_SCALE; } + BLI_assert(0); + return -1; } -/* get index within axis type, so that x == 0, y == 1 and z == 2, no matter which axis type */ -static uint manipulator_index_normalize(const int axis_idx) +static uint manipulator_orientation_axis(const int axis_idx, bool *r_is_plane) { - if (axis_idx > MAN_AXIS_TRANS_ZX) { - return axis_idx - 16; - } - else if (axis_idx > MAN_AXIS_SCALE_C) { - return axis_idx - 13; - } - else if (axis_idx > MAN_AXIS_ROT_T) { - return axis_idx - 9; - } - else if (axis_idx > MAN_AXIS_TRANS_C) { - return axis_idx - 4; - } + switch (axis_idx) { + case MAN_AXIS_TRANS_YZ: + case MAN_AXIS_SCALE_YZ: + if (r_is_plane) { + *r_is_plane = true; + } + ATTR_FALLTHROUGH; + case MAN_AXIS_TRANS_X: + case MAN_AXIS_ROT_X: + case MAN_AXIS_SCALE_X: + return 0; + + case MAN_AXIS_TRANS_ZX: + case MAN_AXIS_SCALE_ZX: + if (r_is_plane) { + *r_is_plane = true; + } + ATTR_FALLTHROUGH; + case MAN_AXIS_TRANS_Y: + case MAN_AXIS_ROT_Y: + case MAN_AXIS_SCALE_Y: + return 1; - return axis_idx; + case MAN_AXIS_TRANS_XY: + case MAN_AXIS_SCALE_XY: + if (r_is_plane) { + *r_is_plane = true; + } + ATTR_FALLTHROUGH; + case MAN_AXIS_TRANS_Z: + case MAN_AXIS_ROT_Z: + case MAN_AXIS_SCALE_Z: + return 2; + } + return 3; } static bool manipulator_is_axis_visible( const View3D *v3d, const RegionView3D *rv3d, const float idot[3], const int axis_type, const int axis_idx) { - const uint aidx_norm = manipulator_index_normalize(axis_idx); + bool is_plane = false; + const uint aidx_norm = manipulator_orientation_axis(axis_idx, &is_plane); /* don't draw axis perpendicular to the view */ - if (aidx_norm < 3 && idot[aidx_norm] < TW_AXIS_DOT_MIN) { - return false; + if (aidx_norm < 3) { + float idot_axis = idot[aidx_norm]; + if (is_plane) { + idot_axis = 1.0f - idot_axis; + } + if (idot_axis < TW_AXIS_DOT_MIN) { + return false; + } } if ((axis_type == MAN_AXES_TRANSLATE && !(v3d->twtype & V3D_MANIP_TRANSLATE)) || @@ -351,10 +332,14 @@ static void manipulator_get_axis_color( const float alpha_hi = 1.0f; float alpha_fac; - const int axis_idx_norm = manipulator_index_normalize(axis_idx); + bool is_plane = false; + const int axis_idx_norm = manipulator_orientation_axis(axis_idx, &is_plane); /* get alpha fac based on axis angle, to fade axis out when hiding it because it points towards view */ if (axis_idx_norm < 3) { - const float idot_axis = idot[axis_idx_norm]; + float idot_axis = idot[axis_idx_norm]; + if (is_plane) { + idot_axis = 1.0f - idot_axis; + } alpha_fac = (idot_axis > TW_AXIS_DOT_MAX) ? 1.0f : (idot_axis < TW_AXIS_DOT_MIN) ? 0.0f : ((idot_axis - TW_AXIS_DOT_MIN) / (TW_AXIS_DOT_MAX - TW_AXIS_DOT_MIN)); @@ -441,14 +426,18 @@ static void manipulator_get_axis_constraint(const int axis_idx, int r_axis[3]) /* **************** Preparation Stuff **************** */ /* transform widget center calc helper for below */ -static void calc_tw_center(Scene *scene, const float co[3]) +static void calc_tw_center(struct TransformBounds *tbounds, const float co[3]) { - float *twcent = scene->twcent; - float *min = scene->twmin; - float *max = scene->twmax; + minmax_v3v3_v3(tbounds->min, tbounds->max, co); + add_v3_v3(tbounds->center, co); - minmax_v3v3_v3(min, max, co); - add_v3_v3(twcent, co); +#ifdef USE_AXIS_BOUNDS + for (int i = 0; i < 3; i++) { + const float d = dot_v3v3(tbounds->axis[i], co); + tbounds->axis_min[i] = min_ff(d, tbounds->axis_min[i]); + tbounds->axis_max[i] = max_ff(d, tbounds->axis_max[i]); + } +#endif } static void protectflag_to_drawflags(short protectflag, short *drawflags) @@ -593,7 +582,7 @@ bool gimbal_axis(Object *ob, float gmat[3][3]) /* centroid, boundbox, of selection */ /* returns total items selected */ -static int calc_manipulator_stats(const bContext *C) +static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbounds) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); @@ -603,7 +592,7 @@ static int calc_manipulator_stats(const bContext *C) View3D *v3d = sa->spacedata.first; RegionView3D *rv3d = ar->regiondata; Base *base; - Object *ob = OBACT_NEW; + Object *ob = OBACT_NEW(sl); bGPdata *gpd = CTX_data_gpencil_data(C); const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)); int a, totsel = 0; @@ -613,10 +602,88 @@ static int calc_manipulator_stats(const bContext *C) rv3d->twdrawflag = 0xFFFF; + + /* global, local or normal orientation? + * if we could check 'totsel' now, this should be skipped with no selection. */ + if (ob && !is_gp_edit) { + + switch (v3d->twmode) { + + case V3D_MANIP_GLOBAL: + { + break; /* nothing to do */ + } + case V3D_MANIP_GIMBAL: + { + float mat[3][3]; + if (gimbal_axis(ob, mat)) { + copy_m4_m3(rv3d->twmat, mat); + break; + } + /* if not gimbal, fall through to normal */ + ATTR_FALLTHROUGH; + } + case V3D_MANIP_NORMAL: + { + if (obedit || ob->mode & OB_MODE_POSE) { + float mat[3][3]; + ED_getTransformOrientationMatrix(C, mat, v3d->around); + copy_m4_m3(rv3d->twmat, mat); + break; + } + /* no break we define 'normal' as 'local' in Object mode */ + ATTR_FALLTHROUGH; + } + case V3D_MANIP_LOCAL: + { + if (ob->mode & OB_MODE_POSE) { + /* each bone moves on its own local axis, but to avoid confusion, + * use the active pones axis for display [#33575], this works as expected on a single bone + * and users who select many bones will understand whats going on and what local means + * when they start transforming */ + float mat[3][3]; + ED_getTransformOrientationMatrix(C, mat, v3d->around); + copy_m4_m3(rv3d->twmat, mat); + break; + } + copy_m4_m4(rv3d->twmat, ob->obmat); + normalize_m4(rv3d->twmat); + break; + } + case V3D_MANIP_VIEW: + { + float mat[3][3]; + copy_m3_m4(mat, rv3d->viewinv); + normalize_m3(mat); + copy_m4_m3(rv3d->twmat, mat); + break; + } + case V3D_MANIP_CUSTOM: + { + TransformOrientation *custom_orientation = BKE_workspace_transform_orientation_find( + CTX_wm_workspace(C), v3d->custom_orientation_index); + float mat[3][3]; + + if (applyTransformOrientation(custom_orientation, mat, NULL)) { + copy_m4_m3(rv3d->twmat, mat); + } + break; + } + } + } + /* transform widget centroid/center */ - INIT_MINMAX(scene->twmin, scene->twmax); - zero_v3(scene->twcent); - + INIT_MINMAX(tbounds->min, tbounds->max); + zero_v3(tbounds->center); + +#ifdef USE_AXIS_BOUNDS + copy_m3_m4(tbounds->axis, rv3d->twmat); + for (int i = 0; i < 3; i++) { + tbounds->axis_min[i] = +FLT_MAX; + tbounds->axis_max[i] = -FLT_MAX; + } +#endif + if (is_gp_edit) { float diff_mat[4][4]; float fpt[3]; @@ -645,12 +712,12 @@ static int calc_manipulator_stats(const bContext *C) for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { if (pt->flag & GP_SPOINT_SELECT) { if (gpl->parent == NULL) { - calc_tw_center(scene, &pt->x); + calc_tw_center(tbounds, &pt->x); totsel++; } else { mul_v3_m4v3(fpt, diff_mat, &pt->x); - calc_tw_center(scene, fpt); + calc_tw_center(tbounds, fpt); totsel++; } } @@ -663,7 +730,7 @@ static int calc_manipulator_stats(const bContext *C) /* selection center */ if (totsel) { - mul_v3_fl(scene->twcent, 1.0f / (float)totsel); /* centroid! */ + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); /* centroid! */ } } else if (obedit) { @@ -676,7 +743,7 @@ static int calc_manipulator_stats(const bContext *C) /* USE LAST SELECTE WITH ACTIVE */ if ((v3d->around == V3D_AROUND_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) { BM_editselection_center(&ese, vec); - calc_tw_center(scene, vec); + calc_tw_center(tbounds, vec); totsel = 1; } else { @@ -689,7 +756,7 @@ static int calc_manipulator_stats(const bContext *C) if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { totsel++; - calc_tw_center(scene, eve->co); + calc_tw_center(tbounds, eve->co); } } } @@ -702,13 +769,13 @@ static int calc_manipulator_stats(const bContext *C) if ((v3d->around == V3D_AROUND_ACTIVE) && (ebo = arm->act_edbone)) { /* doesn't check selection or visibility intentionally */ if (ebo->flag & BONE_TIPSEL) { - calc_tw_center(scene, ebo->tail); + calc_tw_center(tbounds, ebo->tail); totsel++; } if ((ebo->flag & BONE_ROOTSEL) || ((ebo->flag & BONE_TIPSEL) == false)) /* ensure we get at least one point */ { - calc_tw_center(scene, ebo->head); + calc_tw_center(tbounds, ebo->head); totsel++; } protectflag_to_drawflags_ebone(rv3d, ebo); @@ -717,7 +784,7 @@ static int calc_manipulator_stats(const bContext *C) for (ebo = arm->edbo->first; ebo; ebo = ebo->next) { if (EBONE_VISIBLE(arm, ebo)) { if (ebo->flag & BONE_TIPSEL) { - calc_tw_center(scene, ebo->tail); + calc_tw_center(tbounds, ebo->tail); totsel++; } if ((ebo->flag & BONE_ROOTSEL) && @@ -727,7 +794,7 @@ static int calc_manipulator_stats(const bContext *C) (ebo->parent->flag & BONE_TIPSEL) && EBONE_VISIBLE(arm, ebo->parent)) == 0) { - calc_tw_center(scene, ebo->head); + calc_tw_center(tbounds, ebo->head); totsel++; } if (ebo->flag & BONE_SELECTED) { @@ -742,7 +809,7 @@ static int calc_manipulator_stats(const bContext *C) float center[3]; if (v3d->around == V3D_AROUND_ACTIVE && ED_curve_active_center(cu, center)) { - calc_tw_center(scene, center); + calc_tw_center(tbounds, center); totsel++; } else { @@ -763,21 +830,21 @@ static int calc_manipulator_stats(const bContext *C) */ if (cu->drawflag & CU_HIDE_HANDLES) { if (bezt->f2 & SELECT) { - calc_tw_center(scene, bezt->vec[1]); + calc_tw_center(tbounds, bezt->vec[1]); totsel++; } } else if (bezt->f2 & SELECT) { - calc_tw_center(scene, bezt->vec[1]); + calc_tw_center(tbounds, bezt->vec[1]); totsel++; } else { if (bezt->f1 & SELECT) { - calc_tw_center(scene, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]); + calc_tw_center(tbounds, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]); totsel++; } if (bezt->f3 & SELECT) { - calc_tw_center(scene, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]); + calc_tw_center(tbounds, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]); totsel++; } } @@ -789,7 +856,7 @@ static int calc_manipulator_stats(const bContext *C) a = nu->pntsu * nu->pntsv; while (a--) { if (bp->f1 & SELECT) { - calc_tw_center(scene, bp->vec); + calc_tw_center(tbounds, bp->vec); totsel++; } bp++; @@ -804,13 +871,13 @@ static int calc_manipulator_stats(const bContext *C) MetaElem *ml; if ((v3d->around == V3D_AROUND_ACTIVE) && (ml = mb->lastelem)) { - calc_tw_center(scene, &ml->x); + calc_tw_center(tbounds, &ml->x); totsel++; } else { for (ml = mb->editelems->first; ml; ml = ml->next) { if (ml->flag & SELECT) { - calc_tw_center(scene, &ml->x); + calc_tw_center(tbounds, &ml->x); totsel++; } } @@ -821,7 +888,7 @@ static int calc_manipulator_stats(const bContext *C) BPoint *bp; if ((v3d->around == V3D_AROUND_ACTIVE) && (bp = BKE_lattice_active_point_get(lt))) { - calc_tw_center(scene, bp->vec); + calc_tw_center(tbounds, bp->vec); totsel++; } else { @@ -829,7 +896,7 @@ static int calc_manipulator_stats(const bContext *C) a = lt->pntsu * lt->pntsv * lt->pntsw; while (a--) { if (bp->f1 & SELECT) { - calc_tw_center(scene, bp->vec); + calc_tw_center(tbounds, bp->vec); totsel++; } bp++; @@ -839,10 +906,10 @@ static int calc_manipulator_stats(const bContext *C) /* selection center */ if (totsel) { - mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid! - mul_m4_v3(obedit->obmat, scene->twcent); - mul_m4_v3(obedit->obmat, scene->twmin); - mul_m4_v3(obedit->obmat, scene->twmax); + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! + mul_m4_v3(obedit->obmat, tbounds->center); + mul_m4_v3(obedit->obmat, tbounds->min); + mul_m4_v3(obedit->obmat, tbounds->max); } } else if (ob && (ob->mode & OB_MODE_POSE)) { @@ -854,7 +921,7 @@ static int calc_manipulator_stats(const bContext *C) /* doesn't check selection or visibility intentionally */ Bone *bone = pchan->bone; if (bone) { - calc_tw_center(scene, pchan->pose_head); + calc_tw_center(tbounds, pchan->pose_head); protectflag_to_drawflags_pchan(rv3d, pchan); totsel = 1; ok = true; @@ -868,7 +935,7 @@ static int calc_manipulator_stats(const bContext *C) for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { Bone *bone = pchan->bone; if (bone && (bone->flag & BONE_TRANSFORM)) { - calc_tw_center(scene, pchan->pose_head); + calc_tw_center(tbounds, pchan->pose_head); protectflag_to_drawflags_pchan(rv3d, pchan); } } @@ -877,10 +944,10 @@ static int calc_manipulator_stats(const bContext *C) } if (ok) { - mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid! - mul_m4_v3(ob->obmat, scene->twcent); - mul_m4_v3(ob->obmat, scene->twmin); - mul_m4_v3(ob->obmat, scene->twmax); + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! + mul_m4_v3(ob->obmat, tbounds->center); + mul_m4_v3(ob->obmat, tbounds->min); + mul_m4_v3(ob->obmat, tbounds->max); } } else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) { @@ -899,7 +966,7 @@ static int calc_manipulator_stats(const bContext *C) for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) { if (ek->flag & PEK_SELECT) { - calc_tw_center(scene, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co); + calc_tw_center(tbounds, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co); totsel++; } } @@ -907,21 +974,21 @@ static int calc_manipulator_stats(const bContext *C) /* selection center */ if (totsel) - mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid! + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! } } else { /* we need the one selected object, if its not active */ - base = BASACT_NEW; - ob = OBACT_NEW; + base = BASACT_NEW(sl); + ob = OBACT_NEW(sl); if (base && ((base->flag & BASE_SELECTED) == 0)) ob = NULL; for (base = sl->object_bases.first; base; base = base->next) { if (TESTBASELIB_NEW(base)) { if (ob == NULL) ob = base->object; - calc_tw_center(scene, base->object->obmat[3]); + calc_tw_center(tbounds, base->object->obmat[3]); protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag); totsel++; } @@ -929,77 +996,12 @@ static int calc_manipulator_stats(const bContext *C) /* selection center */ if (totsel) { - mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid! + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! } } - /* global, local or normal orientation? */ - if (ob && totsel && !is_gp_edit) { - - switch (v3d->twmode) { - - case V3D_MANIP_GLOBAL: - { - break; /* nothing to do */ - } - case V3D_MANIP_GIMBAL: - { - float mat[3][3]; - if (gimbal_axis(ob, mat)) { - copy_m4_m3(rv3d->twmat, mat); - break; - } - /* if not gimbal, fall through to normal */ - ATTR_FALLTHROUGH; - } - case V3D_MANIP_NORMAL: - { - if (obedit || ob->mode & OB_MODE_POSE) { - float mat[3][3]; - ED_getTransformOrientationMatrix(C, mat, v3d->around); - copy_m4_m3(rv3d->twmat, mat); - break; - } - /* no break we define 'normal' as 'local' in Object mode */ - ATTR_FALLTHROUGH; - } - case V3D_MANIP_LOCAL: - { - if (ob->mode & OB_MODE_POSE) { - /* each bone moves on its own local axis, but to avoid confusion, - * use the active pones axis for display [#33575], this works as expected on a single bone - * and users who select many bones will understand whats going on and what local means - * when they start transforming */ - float mat[3][3]; - ED_getTransformOrientationMatrix(C, mat, v3d->around); - copy_m4_m3(rv3d->twmat, mat); - break; - } - copy_m4_m4(rv3d->twmat, ob->obmat); - normalize_m4(rv3d->twmat); - break; - } - case V3D_MANIP_VIEW: - { - float mat[3][3]; - copy_m3_m4(mat, rv3d->viewinv); - normalize_m3(mat); - copy_m4_m3(rv3d->twmat, mat); - break; - } - case V3D_MANIP_CUSTOM: - { - TransformOrientation *custom_orientation = BKE_workspace_transform_orientation_find( - CTX_wm_workspace(C), v3d->custom_orientation_index); - float mat[3][3]; - - if (applyTransformOrientation(custom_orientation, mat, NULL)) { - copy_m4_m3(rv3d->twmat, mat); - } - break; - } - } - + if (totsel == 0) { + unit_m4(rv3d->twmat); } return totsel; @@ -1015,7 +1017,8 @@ static void manipulator_get_idot(RegionView3D *rv3d, float r_idot[3]) } } -static void manipulator_prepare_mat(const bContext *C, View3D *v3d, RegionView3D *rv3d) +static void manipulator_prepare_mat( + const bContext *C, View3D *v3d, RegionView3D *rv3d, const struct TransformBounds *tbounds) { Scene *scene = CTX_data_scene(C); SceneLayer *sl = CTX_data_scene_layer(C); @@ -1024,23 +1027,23 @@ static void manipulator_prepare_mat(const bContext *C, View3D *v3d, RegionView3D case V3D_AROUND_CENTER_BOUNDS: case V3D_AROUND_ACTIVE: { - bGPdata *gpd = CTX_data_gpencil_data(C); - Object *ob = OBACT_NEW; + bGPdata *gpd = CTX_data_gpencil_data(C); + Object *ob = OBACT_NEW(sl); - if (((v3d->around == V3D_AROUND_ACTIVE) && (scene->obedit == NULL)) && - ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) && - (!(ob->mode & OB_MODE_POSE))) - { - copy_v3_v3(rv3d->twmat[3], ob->obmat[3]); - } - else { - mid_v3_v3v3(rv3d->twmat[3], scene->twmin, scene->twmax); - } - break; + if (((v3d->around == V3D_AROUND_ACTIVE) && (scene->obedit == NULL)) && + ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) && + (!(ob->mode & OB_MODE_POSE))) + { + copy_v3_v3(rv3d->twmat[3], ob->obmat[3]); + } + else { + mid_v3_v3v3(rv3d->twmat[3], tbounds->min, tbounds->max); + } + break; } case V3D_AROUND_LOCAL_ORIGINS: case V3D_AROUND_CENTER_MEAN: - copy_v3_v3(rv3d->twmat[3], scene->twcent); + copy_v3_v3(rv3d->twmat[3], tbounds->center); break; case V3D_AROUND_CURSOR: copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d)); @@ -1090,48 +1093,48 @@ static ManipulatorGroup *manipulatorgroup_init(wmManipulatorGroup *mgroup) const wmManipulatorType *wt_dial = WM_manipulatortype_find("MANIPULATOR_WT_dial_3d", true); const wmManipulatorType *wt_prim = WM_manipulatortype_find("MANIPULATOR_WT_primitive_3d", true); -#define MANIPULATOR_NEW_ARROW(v, name, draw_style) { \ - v = WM_manipulator_new_ptr(wt_arrow, mgroup, name, NULL); \ - RNA_enum_set((v)->ptr, "draw_style", draw_style); \ +#define MANIPULATOR_NEW_ARROW(v, draw_style) { \ + man->manipulators[v] = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); \ + RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \ } ((void)0) -#define MANIPULATOR_NEW_DIAL(v, name, draw_options) { \ - v = WM_manipulator_new_ptr(wt_dial, mgroup, name, NULL); \ - RNA_enum_set((v)->ptr, "draw_options", draw_options); \ +#define MANIPULATOR_NEW_DIAL(v, draw_options) { \ + man->manipulators[v] = WM_manipulator_new_ptr(wt_dial, mgroup, NULL); \ + RNA_enum_set(man->manipulators[v]->ptr, "draw_options", draw_options); \ } ((void)0) -#define MANIPULATOR_NEW_PRIM(v, name, draw_style) { \ - v = WM_manipulator_new_ptr(wt_prim, mgroup, name, NULL); \ - RNA_enum_set((v)->ptr, "draw_style", draw_style); \ +#define MANIPULATOR_NEW_PRIM(v, draw_style) { \ + man->manipulators[v] = WM_manipulator_new_ptr(wt_prim, mgroup, NULL); \ + RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \ } ((void)0) /* add/init widgets - order matters! */ - MANIPULATOR_NEW_DIAL(man->rotate_t, "rotate_t", ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL); + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_T, ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL); - MANIPULATOR_NEW_DIAL(man->scale_c, "scale_c", ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP); + MANIPULATOR_NEW_DIAL(MAN_AXIS_SCALE_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP); - MANIPULATOR_NEW_ARROW(man->scale_x, "scale_x", ED_MANIPULATOR_ARROW_STYLE_BOX); - MANIPULATOR_NEW_ARROW(man->scale_y, "scale_y", ED_MANIPULATOR_ARROW_STYLE_BOX); - MANIPULATOR_NEW_ARROW(man->scale_z, "scale_z", ED_MANIPULATOR_ARROW_STYLE_BOX); + MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_X, ED_MANIPULATOR_ARROW_STYLE_BOX); + MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_Y, ED_MANIPULATOR_ARROW_STYLE_BOX); + MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_Z, ED_MANIPULATOR_ARROW_STYLE_BOX); - MANIPULATOR_NEW_PRIM(man->scale_xy, "scale_xy", ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); - MANIPULATOR_NEW_PRIM(man->scale_yz, "scale_yz", ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); - MANIPULATOR_NEW_PRIM(man->scale_zx, "scale_zx", ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_XY, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_YZ, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_ZX, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); - MANIPULATOR_NEW_DIAL(man->rotate_x, "rotate_x", ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP); - MANIPULATOR_NEW_DIAL(man->rotate_y, "rotate_y", ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP); - MANIPULATOR_NEW_DIAL(man->rotate_z, "rotate_z", ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP); + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_X, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP); + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_Y, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP); + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_Z, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP); /* init screen aligned widget last here, looks better, behaves better */ - MANIPULATOR_NEW_DIAL(man->rotate_c, "rotate_c", ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP); + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP); - MANIPULATOR_NEW_DIAL(man->translate_c, "translate_c", ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP); + MANIPULATOR_NEW_DIAL(MAN_AXIS_TRANS_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP); - MANIPULATOR_NEW_ARROW(man->translate_x, "translate_x", ED_MANIPULATOR_ARROW_STYLE_NORMAL); - MANIPULATOR_NEW_ARROW(man->translate_y, "translate_y", ED_MANIPULATOR_ARROW_STYLE_NORMAL); - MANIPULATOR_NEW_ARROW(man->translate_z, "translate_z", ED_MANIPULATOR_ARROW_STYLE_NORMAL); + MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_X, ED_MANIPULATOR_ARROW_STYLE_NORMAL); + MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_Y, ED_MANIPULATOR_ARROW_STYLE_NORMAL); + MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_Z, ED_MANIPULATOR_ARROW_STYLE_NORMAL); - MANIPULATOR_NEW_PRIM(man->translate_xy, "translate_xy", ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); - MANIPULATOR_NEW_PRIM(man->translate_yz, "translate_yz", ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); - MANIPULATOR_NEW_PRIM(man->translate_zx, "translate_zx", ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_XY, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_YZ, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_ZX, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); return man; } @@ -1139,20 +1142,25 @@ static ManipulatorGroup *manipulatorgroup_init(wmManipulatorGroup *mgroup) /** * Custom handler for manipulator widgets */ -static void manipulator_modal( - bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event), const int UNUSED(flag)) +static int manipulator_modal( + bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event), + eWM_ManipulatorTweak UNUSED(tweak_flag)) { const ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); View3D *v3d = sa->spacedata.first; RegionView3D *rv3d = ar->regiondata; + struct TransformBounds tbounds; - if (calc_manipulator_stats(C)) { - manipulator_prepare_mat(C, v3d, rv3d); + + if (calc_manipulator_stats(C, &tbounds)) { + manipulator_prepare_mat(C, v3d, rv3d, &tbounds); WM_manipulator_set_matrix_location(widget, rv3d->twmat[3]); } ED_region_tag_redraw(ar); + + return OPERATOR_RUNNING_MODAL; } static void WIDGETGROUP_manipulator_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) @@ -1168,7 +1176,7 @@ static void WIDGETGROUP_manipulator_setup(const bContext *UNUSED(C), wmManipulat MAN_ITER_AXES_BEGIN(axis, axis_idx) { - const short axis_type = manipulator_get_axis_type(man, axis); + const short axis_type = manipulator_get_axis_type(axis_idx); int constraint_axis[3] = {1, 0, 0}; PointerRNA *ptr; @@ -1177,7 +1185,7 @@ static void WIDGETGROUP_manipulator_setup(const bContext *UNUSED(C), wmManipulat /* custom handler! */ WM_manipulator_set_fn_custom_modal(axis, manipulator_modal); - switch(axis_idx) { + switch (axis_idx) { case MAN_AXIS_TRANS_X: case MAN_AXIS_TRANS_Y: case MAN_AXIS_TRANS_Z: @@ -1204,6 +1212,7 @@ static void WIDGETGROUP_manipulator_setup(const bContext *UNUSED(C), wmManipulat const float ofs[3] = {ofs_ax, ofs_ax, 0.0f}; WM_manipulator_set_scale(axis, 0.07f); WM_manipulator_set_matrix_offset_location(axis, ofs); + WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_OFFSET_SCALE, true); break; } case MAN_AXIS_TRANS_C: @@ -1228,7 +1237,7 @@ static void WIDGETGROUP_manipulator_setup(const bContext *UNUSED(C), wmManipulat if (ot_store.translate == NULL) { ot_store.translate = WM_operatortype_find("TRANSFORM_OT_translate", true); } - ptr = WM_manipulator_set_operator(axis, ot_store.translate, NULL); + ptr = WM_manipulator_operator_set(axis, 0, ot_store.translate, NULL); break; case MAN_AXES_ROTATE: { @@ -1245,7 +1254,7 @@ static void WIDGETGROUP_manipulator_setup(const bContext *UNUSED(C), wmManipulat } ot_rotate = ot_store.rotate; } - ptr = WM_manipulator_set_operator(axis, ot_rotate, NULL); + ptr = WM_manipulator_operator_set(axis, 0, ot_rotate, NULL); break; } case MAN_AXES_SCALE: @@ -1253,7 +1262,7 @@ static void WIDGETGROUP_manipulator_setup(const bContext *UNUSED(C), wmManipulat if (ot_store.resize == NULL) { ot_store.resize = WM_operatortype_find("TRANSFORM_OT_resize", true); } - ptr = WM_manipulator_set_operator(axis, ot_store.resize, NULL); + ptr = WM_manipulator_operator_set(axis, 0, ot_store.resize, NULL); break; } } @@ -1277,19 +1286,20 @@ static void WIDGETGROUP_manipulator_refresh(const bContext *C, wmManipulatorGrou ARegion *ar = CTX_wm_region(C); View3D *v3d = sa->spacedata.first; RegionView3D *rv3d = ar->regiondata; + struct TransformBounds tbounds; /* skip, we don't draw anything anyway */ - if ((man->all_hidden = (calc_manipulator_stats(C) == 0))) + if ((man->all_hidden = (calc_manipulator_stats(C, &tbounds) == 0))) return; - manipulator_prepare_mat(C, v3d, rv3d); + manipulator_prepare_mat(C, v3d, rv3d, &tbounds); /* *** set properties for axes *** */ MAN_ITER_AXES_BEGIN(axis, axis_idx) { - const short axis_type = manipulator_get_axis_type(man, axis); - const int aidx_norm = manipulator_index_normalize(axis_idx); + const short axis_type = manipulator_get_axis_type(axis_idx); + const int aidx_norm = manipulator_orientation_axis(axis_idx, NULL); WM_manipulator_set_matrix_location(axis, rv3d->twmat[3]); @@ -1309,6 +1319,7 @@ static void WIDGETGROUP_manipulator_refresh(const bContext *C, wmManipulatorGrou WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]); RNA_float_set(axis->ptr, "length", len); WM_manipulator_set_matrix_offset_location(axis, start_co); + WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_OFFSET_SCALE, true); break; } case MAN_AXIS_ROT_X: @@ -1323,8 +1334,8 @@ static void WIDGETGROUP_manipulator_refresh(const bContext *C, wmManipulatorGrou case MAN_AXIS_SCALE_YZ: case MAN_AXIS_SCALE_ZX: { - const float *y_axis = rv3d->twmat[aidx_norm + 1 > 2 ? 0 : aidx_norm + 1]; - const float *z_axis = rv3d->twmat[aidx_norm - 1 < 0 ? 2 : aidx_norm - 1]; + const float *y_axis = rv3d->twmat[aidx_norm - 1 < 0 ? 2 : aidx_norm - 1]; + const float *z_axis = rv3d->twmat[aidx_norm]; WM_manipulator_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis); break; } @@ -1358,7 +1369,7 @@ static void WIDGETGROUP_manipulator_draw_prepare(const bContext *C, wmManipulato MAN_ITER_AXES_BEGIN(axis, axis_idx) { - const short axis_type = manipulator_get_axis_type(man, axis); + const short axis_type = manipulator_get_axis_type(axis_idx); /* XXX maybe unset _HIDDEN flag on redraw? */ if (manipulator_is_axis_visible(v3d, rv3d, idot, axis_type, axis_idx)) { WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, false); @@ -1368,10 +1379,10 @@ static void WIDGETGROUP_manipulator_draw_prepare(const bContext *C, wmManipulato continue; } - float col[4], col_hi[4]; - manipulator_get_axis_color(axis_idx, idot, col, col_hi); - WM_manipulator_set_color(axis, col); - WM_manipulator_set_color_highlight(axis, col_hi); + float color[4], color_hi[4]; + manipulator_get_axis_color(axis_idx, idot, color, color_hi); + WM_manipulator_set_color(axis, color); + WM_manipulator_set_color_highlight(axis, color_hi); switch (axis_idx) { case MAN_AXIS_TRANS_C: diff --git a/source/blender/editors/transform/transform_manipulator2d.c b/source/blender/editors/transform/transform_manipulator2d.c index 104675cb1a8..94f425eb9f0 100644 --- a/source/blender/editors/transform/transform_manipulator2d.c +++ b/source/blender/editors/transform/transform_manipulator2d.c @@ -73,8 +73,13 @@ typedef struct ManipulatorGroup2D { wmManipulator *translate_x, *translate_y; + wmManipulator *cage; + /* Current origin in view space, used to update widget origin for possible view changes */ float origin[2]; + float min[2]; + float max[2]; + } ManipulatorGroup2D; @@ -131,11 +136,18 @@ static void manipulator2d_get_axis_color(const int axis_idx, float *r_col, float static ManipulatorGroup2D *manipulatorgroup2d_init(wmManipulatorGroup *mgroup) { const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_2d", true); + const wmManipulatorType *wt_cage = WM_manipulatortype_find("MANIPULATOR_WT_cage_2d", true); ManipulatorGroup2D *man = MEM_callocN(sizeof(ManipulatorGroup2D), __func__); - man->translate_x = WM_manipulator_new_ptr(wt_arrow, mgroup, "translate_x", NULL); - man->translate_y = WM_manipulator_new_ptr(wt_arrow, mgroup, "translate_y", NULL); + man->translate_x = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); + man->translate_y = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); + man->cage = WM_manipulator_new_ptr(wt_cage, mgroup, NULL); + + RNA_enum_set(man->cage->ptr, "transform", + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE | + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE); return man; } @@ -143,17 +155,24 @@ static ManipulatorGroup2D *manipulatorgroup2d_init(wmManipulatorGroup *mgroup) /** * Calculates origin in view space, use with #manipulator2d_origin_to_region. */ -static void manipulator2d_calc_origin(const bContext *C, float *r_origin) +static void manipulator2d_calc_bounds(const bContext *C, float *r_center, float *r_min, float *r_max) { SpaceImage *sima = CTX_wm_space_image(C); Image *ima = ED_space_image(sima); - if (sima->around == V3D_AROUND_CURSOR) { - copy_v2_v2(r_origin, sima->cursor); + float min_buf[2], max_buf[2]; + if (r_min == NULL) { + r_min = min_buf; } - else { - ED_uvedit_center(CTX_data_scene(C), ima, CTX_data_edit_object(C), r_origin, sima->around); + if (r_max == NULL) { + r_max = max_buf; + } + + if (!ED_uvedit_minmax(CTX_data_scene(C), ima, CTX_data_edit_object(C), r_min, r_max)) { + zero_v2(r_min); + zero_v2(r_max); } + mid_v2_v2v2(r_center, r_min, r_max); } /** @@ -167,17 +186,20 @@ BLI_INLINE void manipulator2d_origin_to_region(ARegion *ar, float *r_origin) /** * Custom handler for manipulator widgets */ -static void manipulator2d_modal( - bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event), const int UNUSED(flag)) +static int manipulator2d_modal( + bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event), + eWM_ManipulatorTweak UNUSED(tweak_flag)) { ARegion *ar = CTX_wm_region(C); float origin[3]; - manipulator2d_calc_origin(C, origin); + manipulator2d_calc_bounds(C, origin, NULL, NULL); manipulator2d_origin_to_region(ar, origin); WM_manipulator_set_matrix_location(widget, origin); ED_region_tag_redraw(ar); + + return OPERATOR_RUNNING_MODAL; } void ED_widgetgroup_manipulator2d_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) @@ -190,8 +212,8 @@ void ED_widgetgroup_manipulator2d_setup(const bContext *UNUSED(C), wmManipulator { const float offset[3] = {0.0f, 0.2f}; - float col[4], col_hi[4]; - manipulator2d_get_axis_color(axis_idx, col, col_hi); + float color[4], color_hi[4]; + manipulator2d_get_axis_color(axis_idx, color, color_hi); /* custom handler! */ WM_manipulator_set_fn_custom_modal(axis, manipulator2d_modal); @@ -201,41 +223,128 @@ void ED_widgetgroup_manipulator2d_setup(const bContext *UNUSED(C), wmManipulator WM_manipulator_set_matrix_offset_location(axis, offset); WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH); WM_manipulator_set_scale(axis, U.manipulator_size); - WM_manipulator_set_color(axis, col); - WM_manipulator_set_color_highlight(axis, col_hi); + WM_manipulator_set_color(axis, color); + WM_manipulator_set_color_highlight(axis, color_hi); /* assign operator */ - PointerRNA *ptr = WM_manipulator_set_operator(axis, ot_translate, NULL); - int constraint[3] = {0.0f}; + PointerRNA *ptr = WM_manipulator_operator_set(axis, 0, ot_translate, NULL); + int constraint[3] = {0}; constraint[(axis_idx + 1) % 2] = 1; if (RNA_struct_find_property(ptr, "constraint_axis")) RNA_boolean_set_array(ptr, "constraint_axis", constraint); RNA_boolean_set(ptr, "release_confirm", 1); } MAN2D_ITER_AXES_END; + + { + wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true); + wmOperatorType *ot_rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true); + PointerRNA *ptr; + + /* assign operator */ + ptr = WM_manipulator_operator_set(man->cage, 0, ot_translate, NULL); + RNA_boolean_set(ptr, "release_confirm", 1); + + int constraint_x[3] = {1, 0, 0}; + int constraint_y[3] = {0, 1, 0}; + + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X, ot_resize, NULL); + PropertyRNA *prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm"); + PropertyRNA *prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis"); + RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X, ot_resize, NULL); + RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y, ot_resize, NULL); + RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y, ot_resize, NULL); + RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y, ot_resize, NULL); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y, ot_resize, NULL); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y, ot_resize, NULL); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y, ot_resize, NULL); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_ROTATE, ot_rotate, NULL); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + } } void ED_widgetgroup_manipulator2d_refresh(const bContext *C, wmManipulatorGroup *mgroup) { ManipulatorGroup2D *man = mgroup->customdata; float origin[3]; - - manipulator2d_calc_origin(C, origin); + manipulator2d_calc_bounds(C, origin, man->min, man->max); copy_v2_v2(man->origin, origin); + bool show_cage = !equals_v2v2(man->min, man->max); + + if (show_cage) { + man->cage->flag &= ~WM_MANIPULATOR_HIDDEN; + man->translate_x->flag |= WM_MANIPULATOR_HIDDEN; + man->translate_y->flag |= WM_MANIPULATOR_HIDDEN; + } + else { + man->cage->flag |= WM_MANIPULATOR_HIDDEN; + man->translate_x->flag &= ~WM_MANIPULATOR_HIDDEN; + man->translate_y->flag &= ~WM_MANIPULATOR_HIDDEN; + } + + if (show_cage) { + wmManipulatorOpElem *mpop; + float mid[2]; + const float *min = man->min; + const float *max = man->max; + mid_v2_v2v2(mid, min, max); + + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X); + PropertyRNA *prop_center_override = RNA_struct_find_property(&mpop->ptr, "center_override"); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){max[0], mid[1], 0.0f}); + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){min[0], mid[1], 0.0f}); + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){mid[0], max[1], 0.0f}); + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){mid[0], min[1], 0.0f}); + + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){max[0], max[1], 0.0f}); + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){max[0], min[1], 0.0f}); + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){min[0], max[1], 0.0f}); + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){min[0], min[1], 0.0f}); + + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_ROTATE); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){mid[0], mid[1], 0.0f}); + } } void ED_widgetgroup_manipulator2d_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) { + ARegion *ar = CTX_wm_region(C); ManipulatorGroup2D *man = mgroup->customdata; float origin[3] = {UNPACK2(man->origin), 0.0f}; + float origin_aa[3] = {UNPACK2(man->origin), 0.0f}; - manipulator2d_origin_to_region(CTX_wm_region(C), origin); + manipulator2d_origin_to_region(ar, origin); MAN2D_ITER_AXES_BEGIN(axis, axis_idx) { WM_manipulator_set_matrix_location(axis, origin); } MAN2D_ITER_AXES_END; + + UI_view2d_view_to_region_m4(&ar->v2d, man->cage->matrix_space); + WM_manipulator_set_matrix_offset_location(man->cage, origin_aa); + man->cage->matrix_offset[0][0] = (man->max[0] - man->min[0]); + man->cage->matrix_offset[1][1] = (man->max[1] - man->min[1]); } /* TODO (Julian) diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index dba442259d1..d7ed80841da 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -559,6 +559,14 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) RNA_def_boolean(ot->srna, "correct_uv", 0, "Correct UVs", "Correct UV coordinates when transforming"); } + if (flags & P_CENTER) { + /* For manipulators that define their own center. */ + prop = RNA_def_property(ot->srna, "center_override", PROP_FLOAT, PROP_XYZ); + RNA_def_property_array(prop, 3); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + RNA_def_property_ui_text(prop, "Center Override", "Force using this center value (when set)"); + } + if ((flags & P_NO_DEFAULTS) == 0) { // Add confirm method all the time. At the end because it's not really that important and should be hidden only in log, not in keymap edit /*prop =*/ RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", "Always confirm operation when releasing button"); @@ -606,7 +614,8 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot) RNA_def_float_vector(ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX); - Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS | P_GPENCIL_EDIT); + Transform_Properties( + ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS | P_GPENCIL_EDIT | P_CENTER); } static int skin_resize_poll(bContext *C) @@ -657,7 +666,7 @@ static void TRANSFORM_OT_trackball(struct wmOperatorType *ot) /* Maybe we could use float_vector_xyz here too? */ RNA_def_float_rotation(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX); - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT); + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER); } static void TRANSFORM_OT_rotate(struct wmOperatorType *ot) @@ -677,7 +686,8 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot) RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2); - Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_GPENCIL_EDIT); + Transform_Properties( + ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_GPENCIL_EDIT | P_CENTER); } static void TRANSFORM_OT_tilt(struct wmOperatorType *ot) @@ -720,7 +730,7 @@ static void TRANSFORM_OT_bend(struct wmOperatorType *ot) RNA_def_float_rotation(ot->srna, "value", 1, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2); - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT); + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER); } static void TRANSFORM_OT_shear(struct wmOperatorType *ot) @@ -761,7 +771,7 @@ static void TRANSFORM_OT_push_pull(struct wmOperatorType *ot) RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Distance", "", -FLT_MAX, FLT_MAX); - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP); + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_CENTER); } static void TRANSFORM_OT_shrink_fatten(struct wmOperatorType *ot) @@ -804,7 +814,7 @@ static void TRANSFORM_OT_tosphere(struct wmOperatorType *ot) RNA_def_float_factor(ot->srna, "value", 0, 0, 1, "Factor", "", 0, 1); - Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT); + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER); } static void TRANSFORM_OT_mirror(struct wmOperatorType *ot) @@ -822,7 +832,7 @@ static void TRANSFORM_OT_mirror(struct wmOperatorType *ot) ot->cancel = transform_cancel; ot->poll = ED_operator_screenactive; - Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT); + Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT | P_CENTER); } static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot) @@ -985,7 +995,8 @@ static void TRANSFORM_OT_transform(struct wmOperatorType *ot) RNA_def_float_vector(ot->srna, "value", 4, NULL, -FLT_MAX, FLT_MAX, "Values", "", -FLT_MAX, FLT_MAX); - Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_GPENCIL_EDIT); + Transform_Properties( + ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_GPENCIL_EDIT | P_CENTER); } void transform_operatortypes(void) @@ -1050,6 +1061,8 @@ void transform_keymap_for_space(wmKeyConfig *keyconf, wmKeyMap *keymap, int spac kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", TABKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); RNA_string_set(kmi->ptr, "data_path", "tool_settings.snap_element"); + /* Will fall-through to texture-space transform. */ + kmi = WM_keymap_add_item(keymap, "OBJECT_OT_transform_axis_target", TKEY, KM_PRESS, KM_SHIFT, 0); kmi = WM_keymap_add_item(keymap, OP_TRANSLATION, TKEY, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "texture_space", true); diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index c0db83ffa5e..e91db762eb1 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -581,7 +581,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3 SceneLayer *sl = CTX_data_scene_layer(C); Object *obedit = CTX_data_edit_object(C); Base *base; - Object *ob = OBACT_NEW; + Object *ob = OBACT_NEW(sl); int result = ORIENTATION_NONE; const bool activeOnly = (around == V3D_AROUND_ACTIVE); @@ -809,15 +809,21 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3 else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { Curve *cu = obedit->data; Nurb *nu = NULL; - BezTriple *bezt = NULL; int a; ListBase *nurbs = BKE_curve_editNurbs_get(cu); - if (activeOnly && BKE_curve_nurb_vert_active_get(cu, &nu, (void *)&bezt)) { + void *vert_act = NULL; + if (activeOnly && BKE_curve_nurb_vert_active_get(cu, &nu, &vert_act)) { if (nu->type == CU_BEZIER) { + BezTriple *bezt = vert_act; BKE_nurb_bezt_calc_normal(nu, bezt, normal); BKE_nurb_bezt_calc_plane(nu, bezt, plane); } + else { + BPoint *bp = vert_act; + BKE_nurb_bpoint_calc_normal(nu, bp, normal); + BKE_nurb_bpoint_calc_plane(nu, bp, plane); + } } else { const bool use_handle = (cu->drawflag & CU_HIDE_HANDLES) == 0; @@ -825,7 +831,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3 for (nu = nurbs->first; nu; nu = nu->next) { /* only bezier has a normal */ if (nu->type == CU_BEZIER) { - bezt = nu->bezt; + BezTriple *bezt = nu->bezt; a = nu->pntsu; while (a--) { short flag = 0; @@ -877,6 +883,36 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3 bezt++; } } + else if (nu->bp && (nu->pntsv == 1)) { + BPoint *bp = nu->bp; + a = nu->pntsu; + while (a--) { + if (bp->f1 & SELECT) { + float tvec[3]; + + BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp); + BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp); + + const bool is_prev_sel = bp_prev && (bp_prev->f1 & SELECT); + const bool is_next_sel = bp_next && (bp_next->f1 & SELECT); + if (is_prev_sel == false && is_next_sel == false) { + /* Isolated, add based on surrounding */ + BKE_nurb_bpoint_calc_normal(nu, bp, tvec); + add_v3_v3(normal, tvec); + } + else if (is_next_sel) { + /* A segment, add the edge normal */ + sub_v3_v3v3(tvec, bp->vec, bp_next->vec ); + normalize_v3(tvec); + add_v3_v3(normal, tvec); + } + + BKE_nurb_bpoint_calc_plane(nu, bp, tvec); + add_v3_v3(plane, tvec); + } + bp++; + } + } } } @@ -1008,8 +1044,8 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3 } else { /* we need the one selected object, if its not active */ - base = BASACT_NEW; - ob = OBACT_NEW; + base = BASACT_NEW(sl); + ob = OBACT_NEW(sl); if (base && ((base->flag & BASE_SELECTED) != 0)) { /* pass */ } diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 1181f584313..e3ea8a51c6d 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -1001,7 +1001,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here char node_border; - if (snapNodesTransform(t, t->mval, t->tsnap.modeSelect, loc, &dist_px, &node_border)) { + if (snapNodesTransform(t, t->mval, loc, &dist_px, &node_border)) { copy_v2_v2(t->tsnap.snapPoint, loc); t->tsnap.snapNodeBorder = node_border; @@ -1397,22 +1397,11 @@ static bool snapNodes( } bool snapNodesTransform( - TransInfo *t, const int mval[2], SnapSelect snap_select, + TransInfo *t, const int mval[2], float r_loc[2], float *r_dist_px, char *r_node_border) { return snapNodes( - t->settings, t->sa->spacedata.first, t->ar, mval, snap_select, - r_loc, r_dist_px, r_node_border); -} - -bool snapNodesContext( - bContext *C, const int mval[2], SnapSelect snap_select, - float r_loc[2], float *r_dist_px, char *r_node_border) -{ - Scene *scene = CTX_data_scene(C); - ARegion *ar = CTX_wm_region(C); - return snapNodes( - scene->toolsettings, CTX_wm_space_node(C), ar, mval, snap_select, + t->settings, t->sa->spacedata.first, t->ar, mval, t->tsnap.modeSelect, r_loc, r_dist_px, r_node_border); } @@ -1462,7 +1451,7 @@ void snapSequenceBounds(TransInfo *t, const int mval[2]) /* convert to frame range */ UI_view2d_region_to_view(&t->ar->v2d, mval[0], mval[1], &xmouse, &ymouse); - mframe = iroundf(xmouse); + mframe = round_fl_to_int(xmouse); /* now find the closest sequence */ frame = BKE_sequencer_find_next_prev_edit(t->scene, mframe, SEQ_SIDE_BOTH, true, false, true); diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index cd33e18ce3e..e72bfa40480 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -51,6 +51,9 @@ #include "BKE_editmesh.h" #include "BKE_main.h" #include "BKE_tracking.h" +#include "BKE_context.h" + +#include "DEG_depsgraph.h" #include "ED_transform.h" #include "ED_transform_snap_object_context.h" @@ -101,7 +104,8 @@ typedef struct SnapObjectData_EditMesh { struct SnapObjectContext { Main *bmain; Scene *scene; - SceneLayer *scene_layer; + EvaluationContext eval_ctx; + int flag; /* Optional: when performing screen-space projection. @@ -131,18 +135,149 @@ struct SnapObjectContext { }; -static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt); +/** \} */ /* -------------------------------------------------------------------- */ -/** \name Support for storing all depths, not just the first (raycast 'all') +/** Common utilities +* \{ */ + + +typedef void(*IterSnapObjsCallback)(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data); + +/** + * Walks through all objects in the scene to create the list of objets to snap. * - * This uses a list of #SnapObjectHitDepth structs. + * \param sctx: Snap context to store data. + * \param snap_select : from enum SnapSelect. + * \param obedit : Object Edited to use its coordinates of BMesh(if any) to do the snapping. + */ +static void iter_snap_objects( + SnapObjectContext *sctx, + const SnapSelect snap_select, + Object *obedit, + IterSnapObjsCallback sob_callback, + void *data) +{ + Base *base_act = sctx->eval_ctx.scene_layer->basact; + /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA + * which makes the loop skip it, even the derived mesh will never change + * + * To solve that problem, we do it first as an exception. + * */ + if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) { + sob_callback(sctx, false, base_act->object, base_act->object->obmat, data); + } + + for (Base *base = sctx->eval_ctx.scene_layer->object_bases.first; base != NULL; base = base->next) { + if ((BASE_VISIBLE_NEW(base)) && (base->flag_legacy & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 && + !((snap_select == SNAP_NOT_SELECTED && ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL))) || + (snap_select == SNAP_NOT_ACTIVE && base == base_act))) + { + bool use_obedit; + Object *obj = base->object; + if (obj->transflag & OB_DUPLI) { + DupliObject *dupli_ob; + ListBase *lb = object_duplilist(&sctx->eval_ctx, sctx->scene, obj); + for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { + use_obedit = obedit && dupli_ob->ob->data == obedit->data; + sob_callback(sctx, use_obedit, use_obedit ? obedit : dupli_ob->ob, dupli_ob->mat, data); + } + free_object_duplilist(lb); + } + + use_obedit = obedit && obj->data == obedit->data; + sob_callback(sctx, use_obedit, use_obedit ? obedit : obj, obj->obmat, data); + } + } +} + + +/** + * Generates a struct with the immutable parameters that will be used on all objects. * - * \{ */ + * \param snap_to: Element to snap, Vertice, Edge or Face. + * \param view_proj: ORTHO or PERSP. + * Currently only works one at a time, but can eventually operate as flag. + * + * \param mval: Mouse coords. + * (When NULL, ray-casting is handled without any projection matrix correction.) + * \param ray_origin: ray_start before being moved toward the ray_normal at the distance from vew3d clip_min. + * \param ray_start: ray_origin moved for the start clipping plane (clip_min). + * \param ray_direction: Unit length direction of the ray. + * \param depth_range: distances of clipe plane min and clip plane max; + */ +static void snap_data_set( + SnapData *snapdata, + const ARegion *ar, const unsigned short snap_to, const enum eViewProj view_proj, + const float mval[2], const float ray_origin[3], const float ray_start[3], + const float ray_direction[3], const float depth_range[2]) +{ + copy_m4_m4(snapdata->pmat, ((RegionView3D *)ar->regiondata)->persmat); + snapdata->win_half[0] = ar->winx / 2; + snapdata->win_half[1] = ar->winy / 2; + copy_v2_v2(snapdata->mval, mval); + snapdata->snap_to = snap_to; + copy_v3_v3(snapdata->ray_origin, ray_origin); + copy_v3_v3(snapdata->ray_start, ray_start); + copy_v3_v3(snapdata->ray_dir, ray_direction); + snapdata->view_proj = view_proj; + copy_v2_v2(snapdata->depth_range, depth_range); +} + + +MINLINE float depth_get(const float co[3], const float ray_start[3], const float ray_dir[3]) +{ + float dvec[3]; + sub_v3_v3v3(dvec, co, ray_start); + return dot_v3v3(dvec, ray_dir); +} + + +static bool walk_parent_bvhroot_cb(const BVHTreeAxisRange *bounds, void *userdata) +{ + BVHTreeRay *ray = userdata; + const float bbmin[3] = {bounds[0].min, bounds[1].min, bounds[2].min}; + const float bbmax[3] = {bounds[0].max, bounds[1].max, bounds[2].max}; + if (!isect_ray_aabb_v3_simple(ray->origin, ray->direction, bbmin, bbmax, &ray->radius, NULL)) { + ray->radius = -1; + } + return false; +} + + +static bool isect_ray_bvhroot_v3(struct BVHTree *tree, const float ray_start[3], const float ray_dir[3], float *depth) +{ + BVHTreeRay ray; + copy_v3_v3(ray.origin, ray_start); + copy_v3_v3(ray.direction, ray_dir); + + BLI_bvhtree_walk_dfs(tree, walk_parent_bvhroot_cb, NULL, NULL, &ray); + + if (ray.radius > 0) { + *depth = ray.radius; + return true; + } + else { + return false; + } +} + + +static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt); + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Ray Cast Funcs +* \{ */ + +/* Store all ray-hits + * Support for storing all depths, not just the first (raycast 'all') */ -/* Store all ray-hits */ struct RayCastAll_Data { void *bvhdata; @@ -163,6 +298,7 @@ struct RayCastAll_Data { bool retval; }; + static struct SnapObjectHitDepth *hit_depth_create( const float depth, const float co[3], const float no[3], int index, Object *ob, const float obmat[4][4], unsigned int ob_uuid) @@ -230,57 +366,501 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH } } -/** \} */ +static bool raycastDerivedMesh( + SnapObjectContext *sctx, + const float ray_start[3], const float ray_dir[3], + Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index, + /* read/write args */ + float *ray_depth, + /* return args */ + float r_loc[3], float r_no[3], int *r_index, + ListBase *r_hit_list) +{ + bool retval = false; -/* -------------------------------------------------------------------- */ + if (dm->getNumPolys(dm) == 0) { + return retval; + } + + float imat[4][4]; + float timat[3][3]; /* transpose inverse matrix for normals */ + float ray_start_local[3], ray_normal_local[3]; + float local_scale, local_depth, len_diff = 0.0f; + + invert_m4_m4(imat, obmat); + transpose_m3_m4(timat, imat); + + copy_v3_v3(ray_start_local, ray_start); + copy_v3_v3(ray_normal_local, ray_dir); + + mul_m4_v3(imat, ray_start_local); + mul_mat3_m4_v3(imat, ray_normal_local); + + /* local scale in normal direction */ + local_scale = normalize_v3(ray_normal_local); + local_depth = *ray_depth; + if (local_depth != BVH_RAYCAST_DIST_MAX) { + local_depth *= local_scale; + } + + /* Test BoundBox */ + BoundBox *bb = BKE_object_boundbox_get(ob); + if (bb) { + /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */ + if (!isect_ray_aabb_v3_simple( + ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], &len_diff, NULL)) + { + return retval; + } + } + + SnapObjectData_Mesh *sod = NULL; + BVHTreeFromMesh *treedata; + + void **sod_p; + if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { + sod = *sod_p; + } + else { + sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); + sod->sd.type = SNAP_MESH; + } + + if (sod->bvh_trees[2] == NULL) { + sod->bvh_trees[2] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata)); + } + + treedata = sod->bvh_trees[2]; + + if (treedata) { + /* the tree is owned by the DM and may have been freed since we last used! */ + if (treedata->tree) { + if (treedata->cached && !bvhcache_has_tree(dm->bvhCache, treedata->tree)) { + free_bvhtree_from_mesh(treedata); + } + else { + if (treedata->vert == NULL) { + treedata->vert = DM_get_vert_array(dm, &treedata->vert_allocated); + } + if (treedata->loop == NULL) { + treedata->loop = DM_get_loop_array(dm, &treedata->loop_allocated); + } + if (treedata->looptri == NULL) { + if (sod->mpoly == NULL) { + sod->mpoly = DM_get_poly_array(dm, &sod->poly_allocated); + } + treedata->looptri = dm->getLoopTriArray(dm); + treedata->looptri_allocated = false; + } + } + } + + if (treedata->tree == NULL) { + bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6); + + if (treedata->tree == NULL) { + return retval; + } + } + } + else { + return retval; + } + + /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already + * been *inside* boundbox, leading to snap failures (see T38409). + * Note also ar might be null (see T38435), in this case we assume ray_start is ok! + */ + if (len_diff == 0.0f) { /* do_ray_start_correction */ + /* We *need* a reasonably valid len_diff in this case. + * Get the distance to bvhtree root */ + if (!isect_ray_bvhroot_v3(treedata->tree, ray_start_local, ray_normal_local, &len_diff)) { + return retval; + } + } + /* You need to make sure that ray_start is really far away, + * because even in the Orthografic view, in some cases, + * the ray can start inside the object (see T50486) */ + if (len_diff > 400.0f) { + /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with + * very far away ray_start values (as returned in case of ortho view3d), see T38358. + */ + len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ + madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff); + local_depth -= len_diff; + } + else { + len_diff = 0.0f; + } + if (r_hit_list) { + struct RayCastAll_Data data; + + data.bvhdata = treedata; + data.raycast_callback = treedata->raycast_callback; + data.obmat = obmat; + data.timat = timat; + data.len_diff = len_diff; + data.local_scale = local_scale; + data.ob = ob; + data.ob_uuid = ob_index; + data.hit_list = r_hit_list; + data.retval = retval; + + BLI_bvhtree_ray_cast_all( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + *ray_depth, raycast_all_cb, &data); + + retval = data.retval; + } + else { + BVHTreeRayHit hit = {.index = -1, .dist = local_depth}; + + if (BLI_bvhtree_ray_cast( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + &hit, treedata->raycast_callback, treedata) != -1) + { + hit.dist += len_diff; + hit.dist /= local_scale; + if (hit.dist <= *ray_depth) { + *ray_depth = hit.dist; + copy_v3_v3(r_loc, hit.co); + + /* back to worldspace */ + mul_m4_v3(obmat, r_loc); + + if (r_no) { + copy_v3_v3(r_no, hit.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } + + retval = true; + + if (r_index) { + *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]); + } + } + } + } + + return retval; +} + +static bool raycastEditMesh( + SnapObjectContext *sctx, + const float ray_start[3], const float ray_dir[3], + Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index, + /* read/write args */ + float *ray_depth, + /* return args */ + float r_loc[3], float r_no[3], int *r_index, + ListBase *r_hit_list) +{ + bool retval = false; + if (em->bm->totface == 0) { + return retval; + } + + SnapObjectData_EditMesh *sod = NULL; + BVHTreeFromEditMesh *treedata = NULL; + + void **sod_p; + if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { + sod = *sod_p; + } + else { + sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); + sod->sd.type = SNAP_EDIT_MESH; + } + + if (sod->bvh_trees[2] == NULL) { + sod->bvh_trees[2] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata)); + } + treedata = sod->bvh_trees[2]; + + if (treedata) { + if (treedata->tree == NULL) { + BLI_bitmap *elem_mask = NULL; + int looptri_num_active = -1; + + if (sctx->callbacks.edit_mesh.test_face_fn) { + elem_mask = BLI_BITMAP_NEW(em->tottri, __func__); + looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface( + em->bm, elem_mask, + sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data); + } + bvhtree_from_editmesh_looptri_ex(treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, NULL); + + if (elem_mask) { + MEM_freeN(elem_mask); + } + } + if (treedata->tree == NULL) { + return retval; + } + } + else { + return retval; + } + + float imat[4][4]; + float timat[3][3]; /* transpose inverse matrix for normals */ + float ray_normal_local[3], ray_start_local[3], len_diff = 0.0f; + + invert_m4_m4(imat, obmat); + transpose_m3_m4(timat, imat); + + copy_v3_v3(ray_normal_local, ray_dir); + mul_mat3_m4_v3(imat, ray_normal_local); + + copy_v3_v3(ray_start_local, ray_start); + mul_m4_v3(imat, ray_start_local); + + /* local scale in normal direction */ + float local_scale = normalize_v3(ray_normal_local); + float local_depth = *ray_depth; + if (local_depth != BVH_RAYCAST_DIST_MAX) { + local_depth *= local_scale; + } + + /* Only use closer ray_start in case of ortho view! In perspective one, ray_start + * may already been *inside* boundbox, leading to snap failures (see T38409). + * Note also ar might be null (see T38435), in this case we assume ray_start is ok! + */ + if (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp) { /* do_ray_start_correction */ + /* We *need* a reasonably valid len_diff in this case. + * Get the distance to bvhtree root */ + if (!isect_ray_bvhroot_v3(treedata->tree, ray_start_local, ray_normal_local, &len_diff)) { + return retval; + } + /* You need to make sure that ray_start is really far away, + * because even in the Orthografic view, in some cases, + * the ray can start inside the object (see T50486) */ + if (len_diff > 400.0f) { + /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with + * very far away ray_start values (as returned in case of ortho view3d), see T38358. + */ + len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ + madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff); + local_depth -= len_diff; + } + else len_diff = 0.0f; + } + if (r_hit_list) { + struct RayCastAll_Data data; + + data.bvhdata = treedata; + data.raycast_callback = treedata->raycast_callback; + data.obmat = obmat; + data.timat = timat; + data.len_diff = len_diff; + data.local_scale = local_scale; + data.ob = ob; + data.ob_uuid = ob_index; + data.hit_list = r_hit_list; + data.retval = retval; + + BLI_bvhtree_ray_cast_all( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + *ray_depth, raycast_all_cb, &data); + + retval = data.retval; + } + else { + BVHTreeRayHit hit = {.index = -1, .dist = local_depth}; + + if (BLI_bvhtree_ray_cast( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + &hit, treedata->raycast_callback, treedata) != -1) + { + hit.dist += len_diff; + hit.dist /= local_scale; + if (hit.dist <= *ray_depth) { + *ray_depth = hit.dist; + copy_v3_v3(r_loc, hit.co); + + /* back to worldspace */ + mul_m4_v3(obmat, r_loc); + + if (r_no) { + copy_v3_v3(r_no, hit.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } + + retval = true; + + if (r_index) { + *r_index = hit.index; + } + } + } + } + + return retval; +} -/** Common utilities - * \{ */ /** - * Generates a struct with the immutable parameters that will be used on all objects. - * - * \param snap_to: Element to snap, Vertice, Edge or Face. - * \param view_proj: ORTHO or PERSP. - * Currently only works one at a time, but can eventually operate as flag. + * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping; * - * \param mval: Mouse coords. - * (When NULL, ray-casting is handled without any projection matrix correction.) - * \param ray_origin: ray_start before being moved toward the ray_normal at the distance from vew3d clip_min. - * \param ray_start: ray_origin moved for the start clipping plane (clip_min). - * \param ray_direction: Unit length direction of the ray. - * \param depth_range: distances of clipe plane min and clip plane max; + * \note Duplicate args here are documented at #snapObjectsRay */ -static void snap_data_set( - SnapData *snapdata, - const ARegion *ar, const unsigned short snap_to, const enum eViewProj view_proj, - const float mval[2], const float ray_origin[3], const float ray_start[3], - const float ray_direction[3], const float depth_range[2]) +static bool raycastObj( + SnapObjectContext *sctx, + const float ray_start[3], const float ray_dir[3], + Object *ob, float obmat[4][4], const unsigned int ob_index, + bool use_obedit, + /* read/write args */ + float *ray_depth, + /* return args */ + float r_loc[3], float r_no[3], int *r_index, + Object **r_ob, float r_obmat[4][4], + ListBase *r_hit_list) { - if (ar) { - copy_m4_m4(snapdata->pmat, ((RegionView3D *)ar->regiondata)->persmat); - snapdata->win_half[0] = ar->winx / 2; - snapdata->win_half[1] = ar->winy / 2; + bool retval = false; + + if (ob->type == OB_MESH) { + BMEditMesh *em; + + if (use_obedit) { + em = BKE_editmesh_from_object(ob); + retval = raycastEditMesh( + sctx, + ray_start, ray_dir, + ob, em, obmat, ob_index, + ray_depth, r_loc, r_no, r_index, r_hit_list); + } + else { + /* in this case we want the mesh from the editmesh, avoids stale data. see: T45978. + * still set the 'em' to NULL, since we only want the 'dm'. */ + DerivedMesh *dm; + em = BKE_editmesh_from_object(ob); + if (em) { + editbmesh_get_derived_cage_and_final(&sctx->eval_ctx, sctx->scene, ob, em, CD_MASK_BAREMESH, &dm); + } + else { + dm = mesh_get_derived_final(&sctx->eval_ctx, sctx->scene, ob, CD_MASK_BAREMESH); + } + retval = raycastDerivedMesh( + sctx, + ray_start, ray_dir, + ob, dm, obmat, ob_index, + ray_depth, r_loc, r_no, r_index, r_hit_list); + } } - if (mval) { - copy_v2_v2(snapdata->mval, mval); + + if (retval) { + if (r_ob) { + *r_ob = ob; + copy_m4_m4(r_obmat, obmat); + } } - snapdata->snap_to = snap_to; - copy_v3_v3(snapdata->ray_origin, ray_origin); - copy_v3_v3(snapdata->ray_start, ray_start); - copy_v3_v3(snapdata->ray_dir, ray_direction); - snapdata->view_proj = view_proj; - copy_v2_v2(snapdata->depth_range, depth_range); + + return retval; } -MINLINE float depth_get(const float co[3], const float ray_start[3], const float ray_dir[3]) + +struct RaycastObjUserData { + const float *ray_start; + const float *ray_dir; + unsigned int ob_index; + /* read/write args */ + float *ray_depth; + /* return args */ + float *r_loc; + float *r_no; + int *r_index; + Object **r_ob; + float (*r_obmat)[4]; + ListBase *r_hit_list; + bool ret; +}; + +static void raycast_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data) { - float dvec[3]; - sub_v3_v3v3(dvec, co, ray_start); - return dot_v3v3(dvec, ray_dir); + struct RaycastObjUserData *dt = data; + dt->ret |= raycastObj( + sctx, + dt->ray_start, dt->ray_dir, + ob, obmat, dt->ob_index++, is_obedit, + dt->ray_depth, + dt->r_loc, dt->r_no, dt->r_index, + dt->r_ob, dt->r_obmat, + dt->r_hit_list); +} + +/** + * Main RayCast Function + * ====================== + * + * Walks through all objects in the scene to find the `hit` on object surface. + * + * \param sctx: Snap context to store data. + * \param snapdata: struct generated in `set_snapdata`. + * \param snap_select : from enum SnapSelect. + * \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`). + * + * Read/Write Args + * --------------- + * + * \param ray_depth: maximum depth allowed for r_co, elements deeper than this value will be ignored. + * + * Output Args + * ----------- + * + * \param r_loc: Hit location. + * \param r_no: Hit normal (optional). + * \param r_index: Hit index or -1 when no valid index is found. + * (currently only set to the polygon index when when using ``snap_to == SCE_SNAP_MODE_FACE``). + * \param r_ob: Hit object. + * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances). + * \param r_hit_list: List of #SnapObjectHitDepth (caller must free). + * + */ +static bool raycastObjects( + SnapObjectContext *sctx, + const float ray_start[3], const float ray_dir[3], + const SnapSelect snap_select, const bool use_object_edit_cage, + /* read/write args */ + float *ray_depth, + /* return args */ + float r_loc[3], float r_no[3], int *r_index, + Object **r_ob, float r_obmat[4][4], + ListBase *r_hit_list) +{ + Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL; + + struct RaycastObjUserData data = { + .ray_start = ray_start, + .ray_dir = ray_dir, + .ob_index = 0, + .ray_depth = ray_depth, + .r_loc = r_loc, + .r_no = r_no, + .r_index = r_index, + .r_ob = r_ob, + .r_obmat = r_obmat, + .r_hit_list = r_hit_list, + .ret = false, + }; + + iter_snap_objects(sctx, snap_select, obedit, raycast_obj_cb, &data); + + return data.ret; } + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** Snap Nearest utilities + * \{ */ + static void copy_dm_vert_no(const int index, float r_no[3], const BVHTreeFromMesh *data) { const MVert *vert = data->vert + index; @@ -489,36 +1069,20 @@ static float dist_squared_to_projected_aabb( main_axis += 3; } - /* if rtmin < rtmax, ray intersect `AABB` */ - if (rtmin <= rtmax) { #define IGNORE_BEHIND_RAY #ifdef IGNORE_BEHIND_RAY - /* `if rtmax < depth_min`, the hit is behind us */ - if (rtmax < data->ray_min_dist) { - /* Test if the entire AABB is behind us */ - float depth = depth_get( - local_bvmax, data->ray_origin_local, data->ray_direction_local); - if (depth < (data->ray_min_dist)) { - return FLT_MAX; - } - } -#endif - const float proj = rtmin * data->ray_direction_local[main_axis]; - r_axis_closest[main_axis] = (proj - va[main_axis]) < (vb[main_axis] - proj); - return 0.0f; - } -#ifdef IGNORE_BEHIND_RAY - /* `if rtmin < depth_min`, the hit is behing us */ - else if (rtmin < data->ray_min_dist) { - /* Test if the entire AABB is behind us */ - float depth = depth_get( - local_bvmax, data->ray_origin_local, data->ray_direction_local); - if (depth < (data->ray_min_dist)) { - return FLT_MAX; - } + float depth_max = depth_get(local_bvmax, data->ray_origin_local, data->ray_direction_local); + if (depth_max < data->ray_min_dist) { + return FLT_MAX; } #endif #undef IGNORE_BEHIND_RAY + + /* if rtmin <= rtmax, ray intersect `AABB` */ + if (rtmin <= rtmax) { + return 0; + } + if (data->sign[main_axis]) { va[main_axis] = local_bvmax[main_axis]; vb[main_axis] = local_bvmin[main_axis]; @@ -559,15 +1123,12 @@ static float dist_squared_to_projected_aabb( vb2d[0] *= data->win_half[0]; vb2d[1] *= data->win_half[1]; - //float dvec[2], edge[2], rdist; - //sub_v2_v2v2(dvec, data->mval, va2d); - //sub_v2_v2v2(edge, vb2d, va2d); - float rdist; - short dvec[2] = {data->mval[0] - va2d[0], data->mval[1] - va2d[1]}; - short edge[2] = {vb2d[0] - va2d[0], vb2d[1] - va2d[1]}; - float lambda = dvec[0] * edge[0] + dvec[1] * edge[1]; + float dvec[2], edge[2], lambda, rdist; + sub_v2_v2v2(dvec, data->mval, va2d); + sub_v2_v2v2(edge, vb2d, va2d); + lambda = dot_v2v2(dvec, edge); if (lambda != 0.0f) { - lambda /= edge[0] * edge[0] + edge[1] * edge[1]; + lambda /= len_squared_v2(edge); if (lambda <= 0.0f) { rdist = len_squared_v2v2(data->mval, va2d); r_axis_closest[main_axis] = true; @@ -604,18 +1165,6 @@ static float dist_squared_to_projected_aabb_simple( return dist_squared_to_projected_aabb(&data, bbmin, bbmax, dummy); } -static float dist_aabb_to_plane( - const float bbmin[3], const float bbmax[3], - const float plane_co[3], const float plane_no[3]) -{ - const float local_bvmin[3] = { - (plane_no[0] < 0) ? bbmax[0] : bbmin[0], - (plane_no[1] < 0) ? bbmax[1] : bbmin[1], - (plane_no[2] < 0) ? bbmax[2] : bbmin[2], - }; - return depth_get(local_bvmin, plane_co, plane_no); -} - /** \} */ @@ -1054,21 +1603,15 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt) static bool snapDerivedMesh( SnapObjectContext *sctx, SnapData *snapdata, - Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index, + Object *ob, DerivedMesh *dm, float obmat[4][4], /* read/write args */ float *ray_depth, float *dist_px, /* return args */ - float r_loc[3], float r_no[3], int *r_index, - ListBase *r_hit_list) + float r_loc[3], float r_no[3]) { bool retval = false; - if (snapdata->snap_to == SCE_SNAP_MODE_FACE) { - if (dm->getNumPolys(dm) == 0) { - return retval; - } - } - else if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) { + if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) { if (dm->getNumEdges(dm) == 0) { return retval; } @@ -1079,38 +1622,27 @@ static bool snapDerivedMesh( } } - bool need_ray_start_correction_init = - (snapdata->snap_to == SCE_SNAP_MODE_FACE) && - (snapdata->view_proj == VIEW_PROJ_ORTHO); - float imat[4][4]; float timat[3][3]; /* transpose inverse matrix for normals */ - float ray_start_local[3], ray_normal_local[3]; - float local_scale, local_depth, len_diff; + float ray_normal_local[3]; + float local_scale; invert_m4_m4(imat, obmat); transpose_m3_m4(timat, imat); - copy_v3_v3(ray_start_local, snapdata->ray_start); copy_v3_v3(ray_normal_local, snapdata->ray_dir); - mul_m4_v3(imat, ray_start_local); mul_mat3_m4_v3(imat, ray_normal_local); /* local scale in normal direction */ local_scale = normalize_v3(ray_normal_local); - local_depth = *ray_depth; - if (local_depth != BVH_RAYCAST_DIST_MAX) { - local_depth *= local_scale; - } float lpmat[4][4]; float ray_org_local[3]; float ray_min_dist; - if (ELEM(snapdata->snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) { - mul_m4_m4m4(lpmat, snapdata->pmat, obmat); - ray_min_dist = snapdata->depth_range[0] * local_scale; - } + + mul_m4_m4m4(lpmat, snapdata->pmat, obmat); + ray_min_dist = snapdata->depth_range[0] * local_scale; copy_v3_v3(ray_org_local, snapdata->ray_origin); mul_m4_v3(imat, ray_org_local); @@ -1119,26 +1651,12 @@ static bool snapDerivedMesh( BoundBox *bb = BKE_object_boundbox_get(ob); if (bb) { /* In vertex and edges you need to get the pixel distance from ray to BoundBox, see: T46099, T46816 */ - if (ELEM(snapdata->snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) { - float dist_px_sq = dist_squared_to_projected_aabb_simple( - lpmat, snapdata->win_half, ray_min_dist, snapdata->mval, - ray_org_local, ray_normal_local, bb->vec[0], bb->vec[6]); - if (dist_px_sq > SQUARE(*dist_px)) { - return retval; - } - } - else { - /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */ - if (!isect_ray_aabb_v3_simple( - ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], NULL, NULL)) - { - return retval; - } + float dist_px_sq = dist_squared_to_projected_aabb_simple( + lpmat, snapdata->win_half, ray_min_dist, snapdata->mval, + ray_org_local, ray_normal_local, bb->vec[0], bb->vec[6]); + if (dist_px_sq > SQUARE(*dist_px)) { + return retval; } - /* was local_depth, see: T47838 */ - len_diff = dist_aabb_to_plane(bb->vec[0], bb->vec[6], ray_start_local, ray_normal_local); - if (len_diff < 0) len_diff = 0.0f; - need_ray_start_correction_init = false; } SnapObjectData_Mesh *sod = NULL; @@ -1155,9 +1673,6 @@ static bool snapDerivedMesh( int tree_index = -1; switch (snapdata->snap_to) { - case SCE_SNAP_MODE_FACE: - tree_index = 2; - break; case SCE_SNAP_MODE_EDGE: tree_index = 1; break; @@ -1177,183 +1692,75 @@ static bool snapDerivedMesh( free_bvhtree_from_mesh(treedata); } else { - if (!treedata->vert_allocated) { + if (treedata->vert == NULL) { treedata->vert = DM_get_vert_array(dm, &treedata->vert_allocated); } - if ((tree_index == 1) && !treedata->edge_allocated) { - treedata->edge = DM_get_edge_array(dm, &treedata->vert_allocated); - } - if (tree_index == 2) { - if (!treedata->loop_allocated) { - treedata->loop = DM_get_loop_array(dm, &treedata->loop_allocated); - } - if (!treedata->looptri_allocated) { - if (!sod->poly_allocated) { - sod->mpoly = DM_get_poly_array(dm, &sod->poly_allocated); - } - treedata->looptri = DM_get_looptri_array( - dm, treedata->vert, - sod->mpoly, dm->getNumPolys(dm), - treedata->loop, dm->getNumLoops(dm), - &treedata->looptri_allocated); - } + if ((tree_index == 1) && (treedata->edge == NULL)) { + treedata->edge = DM_get_edge_array(dm, &treedata->edge_allocated); } } } } - if (treedata && treedata->tree == NULL) { - switch (snapdata->snap_to) { - case SCE_SNAP_MODE_FACE: - bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6); - break; - case SCE_SNAP_MODE_EDGE: - bvhtree_from_mesh_edges(treedata, dm, 0.0f, 2, 6); - break; - case SCE_SNAP_MODE_VERTEX: - bvhtree_from_mesh_verts(treedata, dm, 0.0f, 2, 6); - break; + if (treedata) { + if (treedata->tree == NULL) { + switch (snapdata->snap_to) { + case SCE_SNAP_MODE_EDGE: + bvhtree_from_mesh_edges(treedata, dm, 0.0f, 2, 6); + break; + case SCE_SNAP_MODE_VERTEX: + bvhtree_from_mesh_verts(treedata, dm, 0.0f, 2, 6); + break; + } + } + if (treedata->tree == NULL) { + return retval; } } - if (!treedata || !treedata->tree) { + else { return retval; } - if (snapdata->snap_to == SCE_SNAP_MODE_FACE) { - /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already - * been *inside* boundbox, leading to snap failures (see T38409). - * Note also ar might be null (see T38435), in this case we assume ray_start is ok! - */ - if (snapdata->view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */ - if (need_ray_start_correction_init) { - /* We *need* a reasonably valid len_diff in this case. - * Use BHVTree to find the closest face from ray_start_local. - */ - BVHTreeNearest nearest; - nearest.index = -1; - nearest.dist_sq = FLT_MAX; - /* Compute and store result. */ - BLI_bvhtree_find_nearest( - treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata); - if (nearest.index != -1) { - float dvec[3]; - sub_v3_v3v3(dvec, nearest.co, ray_start_local); - len_diff = dot_v3v3(dvec, ray_normal_local); - } - } - /* You need to make sure that ray_start is really far away, - * because even in the Orthografic view, in some cases, - * the ray can start inside the object (see T50486) */ - if (len_diff > 400.0f) { - /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with - * very far away ray_start values (as returned in case of ortho view3d), see T38358. - */ - len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ - madd_v3_v3v3fl( - ray_start_local, ray_org_local, ray_normal_local, - len_diff + snapdata->depth_range[0] * local_scale); - local_depth -= len_diff; - } - else len_diff = 0.0f; - } - else { - len_diff = 0.0f; - } - if (r_hit_list) { - struct RayCastAll_Data data; - - data.bvhdata = treedata; - data.raycast_callback = treedata->raycast_callback; - data.obmat = obmat; - data.timat = timat; - data.len_diff = len_diff; - data.local_scale = local_scale; - data.ob = ob; - data.ob_uuid = ob_index; - data.hit_list = r_hit_list; - data.retval = retval; - - BLI_bvhtree_ray_cast_all( - treedata->tree, ray_start_local, ray_normal_local, 0.0f, - *ray_depth, raycast_all_cb, &data); - - retval = data.retval; - } - else { - BVHTreeRayHit hit = {.index = -1, .dist = local_depth}; + /* Warning: the depth_max is currently being used only in perspective view. + * It is not correct to limit the maximum depth for elements obtained with nearest + * since this limitation depends on the normal and the size of the occlusion face. + * And more... ray_depth is being confused with Z-depth here... (varies only the precision) */ + const float ray_depth_max_global = *ray_depth + snapdata->depth_range[0]; - if (BLI_bvhtree_ray_cast( - treedata->tree, ray_start_local, ray_normal_local, 0.0f, - &hit, treedata->raycast_callback, treedata) != -1) - { - hit.dist += len_diff; - hit.dist /= local_scale; - if (hit.dist <= *ray_depth) { - *ray_depth = hit.dist; - copy_v3_v3(r_loc, hit.co); - - /* back to worldspace */ - mul_m4_v3(obmat, r_loc); - - if (r_no) { - copy_v3_v3(r_no, hit.no); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); - } + Nearest2dUserData neasrest2d = { + .dist_px_sq = SQUARE(*dist_px), + .r_axis_closest = {1.0f, 1.0f, 1.0f}, + .depth_range = {snapdata->depth_range[0], ray_depth_max_global}, + .userdata = treedata, + .get_edge_verts = (Nearest2DGetEdgeVertsCallback)get_dm_edge_verts, + .copy_vert_no = (Nearest2DCopyVertNoCallback)copy_dm_vert_no, + .index = -1}; - retval = true; + dist_squared_to_projected_aabb_precalc( + &neasrest2d.data_precalc, lpmat, + snapdata->view_proj == VIEW_PROJ_PERSP, snapdata->win_half, + ray_min_dist, snapdata->mval, ray_org_local, ray_normal_local); - if (r_index) { - *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]); - } - } - } - } - } - /* SCE_SNAP_MODE_VERTEX or SCE_SNAP_MODE_EDGE */ - else { + BVHTree_WalkLeafCallback cb_walk_leaf = + (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) ? + cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge; - /* Warning: the depth_max is currently being used only in perspective view. - * It is not correct to limit the maximum depth for elements obtained with nearest - * since this limitation depends on the normal and the size of the occlusion face. - * And more... ray_depth is being confused with Z-depth here... (varies only the precision) */ - const float ray_depth_max_global = *ray_depth + snapdata->depth_range[0]; - - Nearest2dUserData neasrest2d = { - .dist_px_sq = SQUARE(*dist_px), - .r_axis_closest = {1.0f, 1.0f, 1.0f}, - .depth_range = {snapdata->depth_range[0], ray_depth_max_global}, - .userdata = treedata, - .get_edge_verts = (Nearest2DGetEdgeVertsCallback)get_dm_edge_verts, - .copy_vert_no = (Nearest2DCopyVertNoCallback)copy_dm_vert_no, - .index = -1}; - - dist_squared_to_projected_aabb_precalc( - &neasrest2d.data_precalc, lpmat, - snapdata->view_proj == VIEW_PROJ_PERSP, snapdata->win_half, - ray_min_dist, snapdata->mval, ray_org_local, ray_normal_local); - - BVHTree_WalkLeafCallback cb_walk_leaf = - (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) ? - cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge; - - BLI_bvhtree_walk_dfs( - treedata->tree, - cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest2d); - - if (neasrest2d.index != -1) { - copy_v3_v3(r_loc, neasrest2d.co); - mul_m4_v3(obmat, r_loc); - if (r_no) { - copy_v3_v3(r_no, neasrest2d.no); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); - } - *dist_px = sqrtf(neasrest2d.dist_px_sq); - *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); + BLI_bvhtree_walk_dfs( + treedata->tree, + cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest2d); - retval = true; + if (neasrest2d.index != -1) { + copy_v3_v3(r_loc, neasrest2d.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, neasrest2d.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); } + *dist_px = sqrtf(neasrest2d.dist_px_sq); + *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); + + retval = true; } return retval; @@ -1361,20 +1768,14 @@ static bool snapDerivedMesh( static bool snapEditMesh( SnapObjectContext *sctx, SnapData *snapdata, - Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index, + Object *ob, BMEditMesh *em, float obmat[4][4], /* read/write args */ float *ray_depth, float *dist_px, /* return args */ - float r_loc[3], float r_no[3], int *r_index, - ListBase *r_hit_list) + float r_loc[3], float r_no[3]) { bool retval = false; - if (snapdata->snap_to == SCE_SNAP_MODE_FACE) { - if (em->bm->totface == 0) { - return retval; - } - } if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) { if (em->bm->totedge == 0) { return retval; @@ -1399,13 +1800,8 @@ static bool snapEditMesh( /* local scale in normal direction */ float local_scale = normalize_v3(ray_normal_local); - float local_depth = *ray_depth; - if (local_depth != BVH_RAYCAST_DIST_MAX) { - local_depth *= local_scale; - } SnapObjectData_EditMesh *sod = NULL; - BVHTreeFromEditMesh *treedata = NULL; void **sod_p; @@ -1419,9 +1815,6 @@ static bool snapEditMesh( int tree_index = -1; switch (snapdata->snap_to) { - case SCE_SNAP_MODE_FACE: - tree_index = 2; - break; case SCE_SNAP_MODE_EDGE: tree_index = 1; break; @@ -1436,197 +1829,90 @@ static bool snapEditMesh( treedata = sod->bvh_trees[tree_index]; } - if (treedata && treedata->tree == NULL) { - BLI_bitmap *elem_mask = NULL; - switch (snapdata->snap_to) { - case SCE_SNAP_MODE_FACE: - { - int looptri_num_active = -1; - if (sctx->callbacks.edit_mesh.test_face_fn) { - elem_mask = BLI_BITMAP_NEW(em->tottri, __func__); - looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface( - em->bm, elem_mask, - sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data); + if (treedata) { + if (treedata->tree == NULL) { + BLI_bitmap *elem_mask = NULL; + switch (snapdata->snap_to) { + case SCE_SNAP_MODE_EDGE: + { + int edges_num_active = -1; + if (sctx->callbacks.edit_mesh.test_edge_fn) { + elem_mask = BLI_BITMAP_NEW(em->bm->totedge, __func__); + edges_num_active = BM_iter_mesh_bitmap_from_filter( + BM_EDGES_OF_MESH, em->bm, elem_mask, + (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_edge_fn, + sctx->callbacks.edit_mesh.user_data); + } + bvhtree_from_editmesh_edges_ex(treedata, em, elem_mask, edges_num_active, 0.0f, 2, 6); + break; } - bvhtree_from_editmesh_looptri_ex(treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, NULL); - break; - } - case SCE_SNAP_MODE_EDGE: - { - int edges_num_active = -1; - if (sctx->callbacks.edit_mesh.test_edge_fn) { - elem_mask = BLI_BITMAP_NEW(em->bm->totedge, __func__); - edges_num_active = BM_iter_mesh_bitmap_from_filter( - BM_EDGES_OF_MESH, em->bm, elem_mask, - (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_edge_fn, - sctx->callbacks.edit_mesh.user_data); + case SCE_SNAP_MODE_VERTEX: + { + int verts_num_active = -1; + if (sctx->callbacks.edit_mesh.test_vert_fn) { + elem_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__); + verts_num_active = BM_iter_mesh_bitmap_from_filter( + BM_VERTS_OF_MESH, em->bm, elem_mask, + (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_vert_fn, + sctx->callbacks.edit_mesh.user_data); + } + bvhtree_from_editmesh_verts_ex(treedata, em, elem_mask, verts_num_active, 0.0f, 2, 6); + break; } - bvhtree_from_editmesh_edges_ex(treedata, em, elem_mask, edges_num_active, 0.0f, 2, 6); - break; } - case SCE_SNAP_MODE_VERTEX: - { - int verts_num_active = -1; - if (sctx->callbacks.edit_mesh.test_vert_fn) { - elem_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__); - verts_num_active = BM_iter_mesh_bitmap_from_filter( - BM_VERTS_OF_MESH, em->bm, elem_mask, - (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_vert_fn, - sctx->callbacks.edit_mesh.user_data); - } - bvhtree_from_editmesh_verts_ex(treedata, em, elem_mask, verts_num_active, 0.0f, 2, 6); - break; + if (elem_mask) { + MEM_freeN(elem_mask); } } - if (elem_mask) { - MEM_freeN(elem_mask); + if (treedata->tree == NULL) { + return retval; } } - - if (!treedata || !treedata->tree) { + else { return retval; } - if (snapdata->snap_to == SCE_SNAP_MODE_FACE) { - float ray_start_local[3]; - copy_v3_v3(ray_start_local, snapdata->ray_start); - mul_m4_v3(imat, ray_start_local); + float ray_org_local[3]; + copy_v3_v3(ray_org_local, snapdata->ray_origin); + mul_m4_v3(imat, ray_org_local); - /* Only use closer ray_start in case of ortho view! In perspective one, ray_start - * may already been *inside* boundbox, leading to snap failures (see T38409). - * Note also ar might be null (see T38435), in this case we assume ray_start is ok! - */ - float len_diff = 0.0f; - if (snapdata->view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */ - /* We *need* a reasonably valid len_diff in this case. - * Use BHVTree to find the closest face from ray_start_local. - */ - BVHTreeNearest nearest; - nearest.index = -1; - nearest.dist_sq = FLT_MAX; - /* Compute and store result. */ - if (BLI_bvhtree_find_nearest( - treedata->tree, ray_start_local, &nearest, NULL, NULL) != -1) - { - float dvec[3]; - sub_v3_v3v3(dvec, nearest.co, ray_start_local); - len_diff = dot_v3v3(dvec, ray_normal_local); - /* You need to make sure that ray_start is really far away, - * because even in the Orthografic view, in some cases, - * the ray can start inside the object (see T50486) */ - if (len_diff > 400.0f) { - float ray_org_local[3]; - - copy_v3_v3(ray_org_local, snapdata->ray_origin); - mul_m4_v3(imat, ray_org_local); - - /* We pass a temp ray_start, set from object's boundbox, - * to avoid precision issues with very far away ray_start values - * (as returned in case of ortho view3d), see T38358. - */ - len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ - madd_v3_v3v3fl( - ray_start_local, ray_org_local, ray_normal_local, - len_diff + snapdata->depth_range[0] * local_scale); - local_depth -= len_diff; - } - else len_diff = 0.0f; - } - } - if (r_hit_list) { - struct RayCastAll_Data data; - - data.bvhdata = treedata; - data.raycast_callback = treedata->raycast_callback; - data.obmat = obmat; - data.timat = timat; - data.len_diff = len_diff; - data.local_scale = local_scale; - data.ob = ob; - data.ob_uuid = ob_index; - data.hit_list = r_hit_list; - data.retval = retval; - - BLI_bvhtree_ray_cast_all( - treedata->tree, ray_start_local, ray_normal_local, 0.0f, - *ray_depth, raycast_all_cb, &data); - - retval = data.retval; - } - else { - BVHTreeRayHit hit = {.index = -1, .dist = local_depth}; + Nearest2dUserData neasrest2d = { + .dist_px_sq = SQUARE(*dist_px), + .r_axis_closest = {1.0f, 1.0f, 1.0f}, + .depth_range = {snapdata->depth_range[0], *ray_depth + snapdata->depth_range[0]}, + .userdata = treedata, + .get_edge_verts = (Nearest2DGetEdgeVertsCallback)get_bedge_verts, + .copy_vert_no = (Nearest2DCopyVertNoCallback)copy_bvert_no, + .index = -1}; - if (BLI_bvhtree_ray_cast( - treedata->tree, ray_start_local, ray_normal_local, 0.0f, - &hit, treedata->raycast_callback, treedata) != -1) - { - hit.dist += len_diff; - hit.dist /= local_scale; - if (hit.dist <= *ray_depth) { - *ray_depth = hit.dist; - copy_v3_v3(r_loc, hit.co); - - /* back to worldspace */ - mul_m4_v3(obmat, r_loc); - - if (r_no) { - copy_v3_v3(r_no, hit.no); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); - } + float lpmat[4][4]; + mul_m4_m4m4(lpmat, snapdata->pmat, obmat); + dist_squared_to_projected_aabb_precalc( + &neasrest2d.data_precalc, lpmat, + snapdata->view_proj == VIEW_PROJ_PERSP, snapdata->win_half, + (snapdata->depth_range[0] * local_scale), snapdata->mval, + ray_org_local, ray_normal_local); - retval = true; + BVHTree_WalkLeafCallback cb_walk_leaf = + (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) ? + cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge; - if (r_index) { - *r_index = hit.index; - } - } - } - } - } - else { - float ray_org_local[3]; - copy_v3_v3(ray_org_local, snapdata->ray_origin); - mul_m4_v3(imat, ray_org_local); - - Nearest2dUserData neasrest2d = { - .dist_px_sq = SQUARE(*dist_px), - .r_axis_closest = {1.0f, 1.0f, 1.0f}, - .depth_range = {snapdata->depth_range[0], *ray_depth + snapdata->depth_range[0]}, - .userdata = treedata, - .get_edge_verts = (Nearest2DGetEdgeVertsCallback)get_bedge_verts, - .copy_vert_no = (Nearest2DCopyVertNoCallback)copy_bvert_no, - .index = -1}; - - float lpmat[4][4]; - mul_m4_m4m4(lpmat, snapdata->pmat, obmat); - dist_squared_to_projected_aabb_precalc( - &neasrest2d.data_precalc, lpmat, - snapdata->view_proj == VIEW_PROJ_PERSP, snapdata->win_half, - (snapdata->depth_range[0] * local_scale), snapdata->mval, - ray_org_local, ray_normal_local); - - BVHTree_WalkLeafCallback cb_walk_leaf = - (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) ? - cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge; - - BLI_bvhtree_walk_dfs( - treedata->tree, - cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest2d); - - if (neasrest2d.index != -1) { - copy_v3_v3(r_loc, neasrest2d.co); - mul_m4_v3(obmat, r_loc); - if (r_no) { - copy_v3_v3(r_no, neasrest2d.no); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); - } - *dist_px = sqrtf(neasrest2d.dist_px_sq); - *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); + BLI_bvhtree_walk_dfs( + treedata->tree, + cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest2d); - retval = true; + if (neasrest2d.index != -1) { + copy_v3_v3(r_loc, neasrest2d.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, neasrest2d.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); } + *dist_px = sqrtf(neasrest2d.dist_px_sq); + *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); + + retval = true; } return retval; @@ -1639,14 +1925,13 @@ static bool snapEditMesh( */ static bool snapObject( SnapObjectContext *sctx, SnapData *snapdata, - Object *ob, float obmat[4][4], const unsigned int ob_index, + Object *ob, float obmat[4][4], bool use_obedit, /* read/write args */ float *ray_depth, float *dist_px, /* return args */ - float r_loc[3], float r_no[3], int *r_index, - Object **r_ob, float r_obmat[4][4], - ListBase *r_hit_list) + float r_loc[3], float r_no[3], + Object **r_ob, float r_obmat[4][4]) { bool retval = false; @@ -1656,10 +1941,9 @@ static bool snapObject( if (use_obedit) { em = BKE_editmesh_from_object(ob); retval = snapEditMesh( - sctx, snapdata, ob, em, obmat, ob_index, + sctx, snapdata, ob, em, obmat, ray_depth, dist_px, - r_loc, r_no, r_index, - r_hit_list); + r_loc, r_no); } else { /* in this case we want the mesh from the editmesh, avoids stale data. see: T45978. @@ -1667,16 +1951,15 @@ static bool snapObject( DerivedMesh *dm; em = BKE_editmesh_from_object(ob); if (em) { - editbmesh_get_derived_cage_and_final(sctx->scene, ob, em, CD_MASK_BAREMESH, &dm); + editbmesh_get_derived_cage_and_final(&sctx->eval_ctx, sctx->scene, ob, em, CD_MASK_BAREMESH, &dm); } else { - dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH); + dm = mesh_get_derived_final(&sctx->eval_ctx, sctx->scene, ob, CD_MASK_BAREMESH); } retval = snapDerivedMesh( - sctx, snapdata, ob, dm, obmat, ob_index, + sctx, snapdata, ob, dm, obmat, ray_depth, dist_px, - r_loc, r_no, - r_index, r_hit_list); + r_loc, r_no); dm->release(dm); } @@ -1721,6 +2004,34 @@ static bool snapObject( return retval; } + +struct SnapObjUserData { + SnapData *snapdata; + /* read/write args */ + float *ray_depth; + float *dist_px; + /* return args */ + float *r_loc; + float *r_no; + Object **r_ob; + float (*r_obmat)[4]; + bool ret; +}; + +static void sanp_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data) +{ + struct SnapObjUserData *dt = data; + dt->ret |= snapObject( + sctx, dt->snapdata, + ob, obmat, is_obedit, + /* read/write args */ + dt->ray_depth, dt->dist_px, + /* return args */ + dt->r_loc, dt->r_no, + dt->r_ob, dt->r_obmat); +} + + /** * Main Snapping Function * ====================== @@ -1729,8 +2040,8 @@ static bool snapObject( * * \param sctx: Snap context to store data. * \param snapdata: struct generated in `get_snapdata`. - * \param snap_select: from enum SnapSelect. - * \param use_object_edit_cage: Uses the coordinates of BMesh (if any) to do the snapping. + * \param snap_select : from enum SnapSelect. + * \param use_object_edit_cage : Uses the coordinates of BMesh(if any) to do the snapping. * * Read/Write Args * --------------- @@ -1747,89 +2058,33 @@ static bool snapObject( * (currently only set to the polygon index when when using ``snap_to == SCE_SNAP_MODE_FACE``). * \param r_ob: Hit object. * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances). - * \param r_hit_list: List of #SnapObjectHitDepth (caller must free). * */ static bool snapObjectsRay( SnapObjectContext *sctx, SnapData *snapdata, - const SnapSelect snap_select, - const bool use_object_edit_cage, + const SnapSelect snap_select, const bool use_object_edit_cage, /* read/write args */ float *ray_depth, float *dist_px, /* return args */ - float r_loc[3], float r_no[3], int *r_index, - Object **r_ob, float r_obmat[4][4], - ListBase *r_hit_list) + float r_loc[3], float r_no[3], + Object **r_ob, float r_obmat[4][4]) { - bool retval = false; - - unsigned int ob_index = 0; Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL; - /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA - * which makes the loop skip it, even the derived mesh will never change - * - * To solve that problem, we do it first as an exception. - * */ - Base *base_act = sctx->scene_layer->basact; - if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) { - Object *ob = base_act->object; - - retval |= snapObject( - sctx, snapdata, ob, ob->obmat, ob_index++, false, - ray_depth, dist_px, - r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); - } - - bool ignore_object_selected = false, ignore_object_active = false; - switch (snap_select) { - case SNAP_ALL: - break; - case SNAP_NOT_SELECTED: - ignore_object_selected = true; - break; - case SNAP_NOT_ACTIVE: - ignore_object_active = true; - break; - } - for (Base *base = sctx->scene_layer->object_bases.first; base != NULL; base = base->next) { - if ((BASE_VISIBLE_NEW(base)) && - (base->flag_legacy & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 && - - !((ignore_object_selected && (((base->flag & BASE_SELECTED) != 0) || ((base->flag_legacy & BA_WAS_SEL)))) || - (ignore_object_active && base == base_act))) - { - Object *ob = base->object; - - if (ob->transflag & OB_DUPLI) { - DupliObject *dupli_ob; - ListBase *lb = object_duplilist(sctx->bmain->eval_ctx, sctx->scene, ob); - - for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { - bool use_obedit_dupli = (obedit && dupli_ob->ob->data == obedit->data); - Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob; - - retval |= snapObject( - sctx, snapdata, dupli_snap, dupli_ob->mat, - ob_index++, use_obedit_dupli, - ray_depth, dist_px, - r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); - } - - free_object_duplilist(lb); - } - - bool use_obedit = (obedit != NULL) && (ob->data == obedit->data); - Object *ob_snap = use_obedit ? obedit : ob; + struct SnapObjUserData data = { + .snapdata = snapdata, + .ray_depth = ray_depth, + .dist_px = dist_px, + .r_loc = r_loc, + .r_no = r_no, + .r_ob = r_ob, + .r_obmat = r_obmat, + .ret = false, + }; - retval |= snapObject( - sctx, snapdata, ob_snap, ob->obmat, ob_index++, use_obedit, - ray_depth, dist_px, - r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); - } - } + iter_snap_objects(sctx, snap_select, obedit, sanp_obj_cb, &data); - return retval; + return data.ret; } /** \} */ @@ -1849,7 +2104,8 @@ SnapObjectContext *ED_transform_snap_object_context_create( sctx->bmain = bmain; sctx->scene = scene; - sctx->scene_layer = sl; + + DEG_evaluation_context_init_from_scene(&sctx->eval_ctx, scene, sl, DAG_EVAL_VIEWPORT); sctx->cache.object_map = BLI_ghash_ptr_new(__func__); sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); @@ -1924,25 +2180,17 @@ void ED_transform_snap_object_context_set_editmesh_callbacks( bool ED_transform_snap_object_project_ray_ex( SnapObjectContext *sctx, - const unsigned short snap_to, const struct SnapObjectParams *params, const float ray_start[3], const float ray_normal[3], float *ray_depth, float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4]) { - const float depth_range[2] = {0.0f, FLT_MAX}; - - SnapData snapdata; - snap_data_set( - &snapdata, sctx->v3d_data.ar, snap_to, VIEW_PROJ_NONE, - NULL, ray_start, ray_start, ray_normal, depth_range); - - return snapObjectsRay( - sctx, &snapdata, + return raycastObjects( + sctx, + ray_start, ray_normal, params->snap_select, params->use_object_edit_cage, - ray_depth, NULL, - r_loc, r_no, r_index, r_ob, r_obmat, NULL); + ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, NULL); } /** @@ -1954,13 +2202,11 @@ bool ED_transform_snap_object_project_ray_ex( */ bool ED_transform_snap_object_project_ray_all( SnapObjectContext *sctx, - const unsigned short snap_to, const struct SnapObjectParams *params, const float ray_start[3], const float ray_normal[3], float ray_depth, bool sort, ListBase *r_hit_list) { - const float depth_range[2] = {0.0f, FLT_MAX}; if (ray_depth == -1.0f) { ray_depth = BVH_RAYCAST_DIST_MAX; } @@ -1969,15 +2215,11 @@ bool ED_transform_snap_object_project_ray_all( float ray_depth_prev = ray_depth; #endif - SnapData snapdata; - snap_data_set(&snapdata, sctx->v3d_data.ar, snap_to, VIEW_PROJ_NONE, NULL, - ray_start, ray_start, ray_normal, depth_range); - - bool retval = snapObjectsRay( - sctx, &snapdata, + bool retval = raycastObjects( + sctx, + ray_start, ray_normal, params->snap_select, params->use_object_edit_cage, - &ray_depth, NULL, - NULL, NULL, NULL, NULL, NULL, + &ray_depth, NULL, NULL, NULL, NULL, NULL, r_hit_list); /* meant to be readonly for 'all' hits, ensure it is */ @@ -2010,7 +2252,6 @@ static bool transform_snap_context_project_ray_impl( /* try snap edge, then face if it fails */ ret = ED_transform_snap_object_project_ray_ex( sctx, - SCE_SNAP_MODE_FACE, params, ray_start, ray_normal, ray_depth, r_co, r_no, NULL, @@ -2156,16 +2397,24 @@ bool ED_transform_snap_object_project_view3d_ex( ray_depth = &ray_depth_fallback; } - SnapData snapdata; - const enum eViewProj view_proj = ((RegionView3D *)ar->regiondata)->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO; - snap_data_set(&snapdata, ar, snap_to, view_proj, mval, - ray_origin, ray_start, ray_normal, depth_range); + if (snap_to == SCE_SNAP_MODE_FACE) { + return raycastObjects( + sctx, + ray_start, ray_normal, + params->snap_select, params->use_object_edit_cage, + ray_depth, r_loc, r_no, r_index, NULL, NULL, NULL); + } + else { + SnapData snapdata; + const enum eViewProj view_proj = ((RegionView3D *)ar->regiondata)->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO; + snap_data_set(&snapdata, ar, snap_to, view_proj, mval, + ray_origin, ray_start, ray_normal, depth_range); - return snapObjectsRay( - sctx, &snapdata, - params->snap_select, params->use_object_edit_cage, - ray_depth, dist_px, - r_loc, r_no, r_index, NULL, NULL, NULL); + return snapObjectsRay( + sctx, &snapdata, + params->snap_select, params->use_object_edit_cage, + ray_depth, dist_px, r_loc, r_no, NULL, NULL); + } } bool ED_transform_snap_object_project_view3d( @@ -2206,7 +2455,6 @@ bool ED_transform_snap_object_project_all_view3d_ex( return ED_transform_snap_object_project_ray_all( sctx, - SCE_SNAP_MODE_FACE, params, ray_start, ray_normal, ray_depth, sort, r_hit_list); |