diff options
author | Darshan Kadu <darsh7807@gmail.com> | 2017-09-10 15:41:40 +0300 |
---|---|---|
committer | Darshan Kadu <darsh7807@gmail.com> | 2017-09-10 15:41:40 +0300 |
commit | 6594fa1ce02809a275c9cd488fa0223d03d73571 (patch) | |
tree | 0bcd95846e1e3b09239126b40ef434ed3dc3a50d /source/blender/editors/transform | |
parent | f2017083a19e5c83aadc575625dce0642ffce6c5 (diff) |
merged the master branchsoc-2017-vertex_paint
Diffstat (limited to 'source/blender/editors/transform')
-rw-r--r-- | source/blender/editors/transform/transform.c | 101 | ||||
-rw-r--r-- | source/blender/editors/transform/transform.h | 3 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_conversions.c | 193 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_generics.c | 17 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_input.c | 11 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_manipulator.c | 2 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_ops.c | 27 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_orientations.c | 42 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_snap.c | 17 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_snap_object.c | 1410 |
10 files changed, 1115 insertions, 708 deletions
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index d786c755529..8cabf8d78ed 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -2878,7 +2878,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; @@ -3051,19 +3053,13 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2])) /** \name Transform Shear * \{ */ -static void postInputShear(TransInfo *UNUSED(t), float values[3]) -{ - mul_v3_fl(values, 0.05f); -} - static void initShear(TransInfo *t) { t->mode = TFM_SHEAR; t->transform = applyShear; t->handleEvent = handleEventShear; - - setInputPostFct(&t->mouse, postInputShear); - initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE); + + initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO); t->idx_max = 0; t->num.idx_max = 0; @@ -3085,24 +3081,24 @@ static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event) if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) { /* Use custom.mode.data pointer to signal Shear direction */ if (t->custom.mode.data == NULL) { - initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE); + initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_RATIO); t->custom.mode.data = (void *)1; } else { - initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE); + initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO); t->custom.mode.data = NULL; } status = TREDRAW_HARD; } else if (event->type == XKEY && event->val == KM_PRESS) { - initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE); + initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO); t->custom.mode.data = NULL; status = TREDRAW_HARD; } else if (event->type == YKEY && event->val == KM_PRESS) { - initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE); + initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_RATIO); t->custom.mode.data = (void *)1; status = TREDRAW_HARD; @@ -4073,13 +4069,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) @@ -4089,10 +4087,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); @@ -4278,7 +4273,7 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_ bUnit_AsString(distvec, sizeof(distvec), dist * t->scene->unit.scale_length, 4, t->scene->unit.system, B_UNIT_LENGTH, do_split, false); } - else if (dist > 1e10f || dist < -1e10f) { + else if (dist > 1e10f || dist < -1e10f) { /* prevent string buffer overflow */ BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4e", dist); } @@ -5565,7 +5560,7 @@ static void slide_origdata_interp_data_vert( float v_proj[3][3]; if (do_loop_weight || do_loop_mdisps) { - project_plane_v3_v3v3(v_proj[1], sv->co_orig_3d, v_proj_axis); + project_plane_normalized_v3_v3v3(v_proj[1], sv->co_orig_3d, v_proj_axis); } // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) { @@ -5599,19 +5594,19 @@ static void slide_origdata_interp_data_vert( /* In the unlikely case that we're next to a zero length edge - walk around the to the next. * Since we only need to check if the vertex is in this corner, * its not important _which_ loop - as long as its not overlapping 'sv->co_orig_3d', see: T45096. */ - project_plane_v3_v3v3(v_proj[0], co_prev, v_proj_axis); + project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis); while (UNLIKELY(((co_prev_ok = (len_squared_v3v3(v_proj[1], v_proj[0]) > eps)) == false) && ((l_prev = l_prev->prev) != l->next))) { co_prev = slide_origdata_orig_vert_co(sod, l_prev->v); - project_plane_v3_v3v3(v_proj[0], co_prev, v_proj_axis); + project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis); } - project_plane_v3_v3v3(v_proj[2], co_next, v_proj_axis); + project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis); while (UNLIKELY(((co_next_ok = (len_squared_v3v3(v_proj[1], v_proj[2]) > eps)) == false) && ((l_next = l_next->next) != l->prev))) { co_next = slide_origdata_orig_vert_co(sod, l_next->v); - project_plane_v3_v3v3(v_proj[2], co_next, v_proj_axis); + project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis); } if (co_prev_ok && co_next_ok) { @@ -8367,8 +8362,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) { @@ -8443,25 +8445,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); + } } } } @@ -8520,9 +8535,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 d60eb2f0778..06a60456cdb 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -533,6 +533,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 diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 04b9ae75c8f..521179fc1d9 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -771,29 +771,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 */ @@ -809,7 +817,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) */ @@ -817,8 +831,19 @@ 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); + } + +#ifdef WITH_LEGACY_DEPSGRAPH + if (!DEG_depsgraph_use_legacy()) +#endif + { + if (changed) { + /* TODO(sergey): Consider doing partial update only. */ + DAG_relations_tag_update(G.main); + } } } @@ -1500,6 +1525,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; @@ -1517,22 +1584,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; + } } } @@ -1583,10 +1650,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 || @@ -1617,7 +1684,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); @@ -1643,7 +1710,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); @@ -1653,10 +1720,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 || @@ -1711,6 +1775,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); @@ -1729,6 +1813,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++; @@ -1744,6 +1833,10 @@ static void createTransCurveVerts(TransInfo *t) calc_distanceCurveVerts(head, tail - 1); } } + +#undef SEL_F1 +#undef SEL_F2 +#undef SEL_F3 } /* ********************* lattice *************** */ @@ -2008,9 +2101,9 @@ static bool bmesh_test_dist_add( } /** - * \parm mtx: Measure disatnce in this space. - * \parm dists: Store the closest connected distance to selected vertices. - * \parm index: Optionally store the original index we're measuring the distance to (can be NULL). + * \param mtx: Measure disatnce in this space. + * \param dists: Store the closest connected distance to selected vertices. + * \param index: Optionally store the original index we're measuring the distance to (can be NULL). */ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float *dists, int *index) { @@ -2280,7 +2373,7 @@ static struct TransIslandData *editmesh_islands_info_calc( } if (group_tot_single != 0) { - trans_islands = MEM_reallocN(trans_islands, group_tot + group_tot_single); + trans_islands = MEM_reallocN(trans_islands, sizeof(*trans_islands) * (group_tot + group_tot_single)); BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) { if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) { @@ -2402,7 +2495,8 @@ static void createTransEditVerts(TransInfo *t) int island_info_tot; int *island_vert_map = NULL; - const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS) && (t->mode != TFM_TRANSLATION); + /* 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. * Optional, allocate if needed. */ int *dists_index = NULL; @@ -2468,11 +2562,6 @@ static void createTransEditVerts(TransInfo *t) editmesh_set_connectivity_distance(em->bm, mtx, dists, dists_index); } - /* Only in case of rotation and resize, we want the elements of the edited - * object to behave as groups whose pivot are the individual origins - * - * TODO: use island_info to detect the closest point when the "Snap Target" - * in Blender UI is "Closest" */ if (is_island_center) { /* In this specific case, near-by vertices will need to know the island of the nearest connected vertex. */ const bool calc_single_islands = ( @@ -5353,7 +5442,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 */ } } @@ -5886,27 +5976,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; @@ -5914,15 +6000,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); } @@ -7750,7 +7835,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; @@ -7775,7 +7860,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) { @@ -7831,6 +7916,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]; @@ -7847,7 +7933,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 */ diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index f78a23be7b8..179b68dd270 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -971,7 +971,7 @@ static void recalcData_sequencer(TransInfo *t) /* force recalculation of triangles during transformation */ static void recalcData_gpencil_strokes(TransInfo *t) - { +{ TransData *td = t->data; for (int i = 0; i < t->total; i++, td++) { bGPDstroke *gps = td->extra; @@ -1331,7 +1331,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->current_orientation = V3D_MANIP_GLOBAL; } } - + if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) && RNA_property_is_set(op->ptr, prop))) { @@ -1435,6 +1435,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); } @@ -1835,7 +1842,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 */ @@ -1849,7 +1858,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_input.c b/source/blender/editors/transform/transform_input.c index 22c39d6ed0c..5f2e5a99090 100644 --- a/source/blender/editors/transform/transform_input.c +++ b/source/blender/editors/transform/transform_input.c @@ -86,12 +86,11 @@ static void InputTrackBall(TransInfo *UNUSED(t), MouseInput *mi, const double mv output[1] *= mi->factor; } -static void InputHorizontalRatio(TransInfo *t, MouseInput *UNUSED(mi), const double mval[2], float output[3]) +static void InputHorizontalRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3]) { const int winx = t->ar ? t->ar->winx : 1; - const double pad = winx / 10; - output[0] = (mval[0] - pad) / (winx - 2 * pad); + output[0] = ((mval[0] - mi->imval[0]) / winx) * 2.0f; } static void InputHorizontalAbsolute(TransInfo *t, MouseInput *mi, const double mval[2], float output[3]) @@ -104,12 +103,11 @@ static void InputHorizontalAbsolute(TransInfo *t, MouseInput *mi, const double m output[0] = dot_v3v3(t->viewinv[0], vec) * 2.0f; } -static void InputVerticalRatio(TransInfo *t, MouseInput *UNUSED(mi), const double mval[2], float output[3]) +static void InputVerticalRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3]) { const int winy = t->ar ? t->ar->winy : 1; - const double pad = winy / 10; - output[0] = (mval[1] - pad) / (winy - 2 * pad); + output[0] = ((mval[1] - mi->imval[1]) / winy) * 2.0f; } static void InputVerticalAbsolute(TransInfo *t, MouseInput *mi, const double mval[2], float output[3]) @@ -314,7 +312,6 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode) t->helpline = HLP_TRACKBALL; break; case INPUT_HORIZONTAL_RATIO: - mi->factor = (float)(mi->center[0] - mi->imval[0]); mi->apply = InputHorizontalRatio; t->helpline = HLP_HARROW; break; diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index ab2a0225abc..ec066ba91a4 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -1755,7 +1755,7 @@ static int manipulator_selectbuf(Scene *scene, ScrArea *sa, ARegion *ar, const i hits = GPU_select_end(); - if (do_passes) { + if (do_passes && (hits > 0)) { GPU_select_begin(buffer, 64, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits); /* do the drawing */ diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 2a97384cf7d..1aa800f9fb1 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -565,6 +565,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"); @@ -612,7 +620,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) @@ -663,7 +672,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) @@ -683,7 +692,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) @@ -726,7 +736,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) @@ -767,7 +777,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) @@ -810,7 +820,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) @@ -828,7 +838,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) @@ -991,7 +1001,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) diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 23158495b44..54959304d72 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -817,15 +817,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; @@ -833,7 +839,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; @@ -885,6 +891,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++; + } + } } } diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 318d2718969..4e8a9f4dd67 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -1017,7 +1017,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; @@ -1413,22 +1413,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); } diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index b33528b4149..867f04563c6 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -130,18 +130,150 @@ 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->scene->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->scene->base.first; base != NULL; base = base->next) { + if ((BASE_VISIBLE_BGMODE(sctx->v3d_data.v3d, sctx->scene, base)) && + (base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 && + !((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | 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->bmain->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; @@ -162,6 +294,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) @@ -229,57 +362,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->scene, ob, em, CD_MASK_BAREMESH, &dm); + } + else { + dm = mesh_get_derived_final(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; @@ -558,15 +1135,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; @@ -603,24 +1177,12 @@ 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); -} - /** \} */ /* -------------------------------------------------------------------- */ -/** \Walk DFS +/** Walk DFS * \{ */ typedef void (*Nearest2DGetEdgeVertsCallback)(const int index, const float *v_pair[2], void *data); @@ -1053,21 +1615,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; } @@ -1078,38 +1634,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); @@ -1118,26 +1663,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; @@ -1154,9 +1685,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; @@ -1176,183 +1704,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; @@ -1360,20 +1780,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; @@ -1398,13 +1812,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; @@ -1418,9 +1827,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; @@ -1435,197 +1841,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; @@ -1638,14 +1937,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; @@ -1655,10 +1953,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. @@ -1672,10 +1969,9 @@ static bool snapObject( dm = mesh_get_derived_final(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); } @@ -1720,6 +2016,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 * ====================== @@ -1728,8 +2052,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 * --------------- @@ -1746,89 +2070,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->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->base.first; base != NULL; base = base->next) { - if ((BASE_VISIBLE_BGMODE(sctx->v3d_data.v3d, sctx->scene, base)) && - (base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 && - - !((ignore_object_selected && (base->flag & (SELECT | 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); - } + 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, + }; - bool use_obedit = (obedit != NULL) && (ob->data == obedit->data); - Object *ob_snap = use_obedit ? obedit : ob; + iter_snap_objects(sctx, snap_select, obedit, sanp_obj_cb, &data); - 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); - } - } - - return retval; + return data.ret; } /** \} */ @@ -1922,25 +2190,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); } /** @@ -1952,13 +2212,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; } @@ -1967,15 +2225,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 */ @@ -2008,7 +2262,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, @@ -2154,16 +2407,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( @@ -2204,7 +2465,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); |