diff options
-rw-r--r-- | source/blender/editors/transform/transform_convert_mesh.c | 123 |
1 files changed, 77 insertions, 46 deletions
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index 58cf82c72d3..de2f96c0f97 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -69,28 +69,43 @@ struct TransCustomData_PartialUpdate { float prop_size_prev; }; +/** + * \note It's important to order from least to greatest (which updates more data), + * since the larger values are used when values change between updates + * (which can happen when rotation is enabled with snapping). + */ enum ePartialType { PARTIAL_NONE = -1, /** - * Update for all tagged vertices (any kind of deformation). - * Use as a default since it can be used with any kind of deformation. - */ - PARTIAL_TYPE_ALL = 0, - /** * Update only faces between tagged and non-tagged faces (affine transformations). * Use when transforming is guaranteed not to change the relative locations of vertices. * * This has the advantage that selecting the entire mesh or only isolated elements, * can skip normal/tessellation updates entirely, so it's worth using when possible. */ - PARTIAL_TYPE_GROUP = 1, - + PARTIAL_TYPE_GROUP = 0, + /** + * Update for all tagged vertices (any kind of deformation). + * Use as a default since it can be used with any kind of deformation. + */ + PARTIAL_TYPE_ALL = 1, }; + #define PARTIAL_TYPE_MAX 2 +/** + * Settings used for a single update, + * use for comparison with previous updates. + */ +struct PartialTypeState { + enum ePartialType for_looptri; + enum ePartialType for_normals; +}; + struct TransCustomDataMesh { struct TransCustomDataLayer *cd_layer_correct; struct TransCustomData_PartialUpdate partial_update[PARTIAL_TYPE_MAX]; + struct PartialTypeState partial_update_state_prev; }; static struct TransCustomDataMesh *tc_mesh_customdata_ensure(TransDataContainer *tc) @@ -102,6 +117,8 @@ static struct TransCustomDataMesh *tc_mesh_customdata_ensure(TransDataContainer tc->custom.type.data = MEM_callocN(sizeof(struct TransCustomDataMesh), __func__); tc->custom.type.free_cb = tc_mesh_customdata_free_fn; tcmd = tc->custom.type.data; + tcmd->partial_update_state_prev.for_looptri = PARTIAL_NONE; + tcmd->partial_update_state_prev.for_normals = PARTIAL_NONE; } return tcmd; } @@ -1895,9 +1912,7 @@ static BMPartialUpdate *tc_mesh_partial_ensure(TransInfo *t, return pupdate->cache; } -static void tc_mesh_partial_types_calc(TransInfo *t, - enum ePartialType *r_partial_for_looptri, - enum ePartialType *r_partial_for_normals) +static void tc_mesh_partial_types_calc(TransInfo *t, struct PartialTypeState *r_partial_state) { /* Calculate the kind of partial updates which can be performed. */ enum ePartialType partial_for_normals = PARTIAL_NONE; @@ -1909,6 +1924,10 @@ static void tc_mesh_partial_types_calc(TransInfo *t, case TFM_TRANSLATION: { partial_for_looptri = PARTIAL_TYPE_GROUP; partial_for_normals = PARTIAL_TYPE_GROUP; + /* Translation can rotate when snapping to normal. */ + if (activeSnap(t) && usingSnappingNormal(t) && validSnappingNormal(t)) { + partial_for_normals = PARTIAL_TYPE_ALL; + } break; } case TFM_ROTATION: { @@ -1946,53 +1965,65 @@ static void tc_mesh_partial_types_calc(TransInfo *t, } } - *r_partial_for_looptri = partial_for_looptri; - *r_partial_for_normals = partial_for_normals; + r_partial_state->for_looptri = partial_for_looptri; + r_partial_state->for_normals = partial_for_normals; } static void tc_mesh_partial_update(TransInfo *t, TransDataContainer *tc, - enum ePartialType partial_for_looptri, - enum ePartialType partial_for_normals) + const struct PartialTypeState *partial_state) { BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); - /* Matching. */ - if ((partial_for_looptri == PARTIAL_TYPE_ALL) && (partial_for_normals == PARTIAL_TYPE_ALL)) { + struct TransCustomDataMesh *tcmd = tc_mesh_customdata_ensure(tc); + + const struct PartialTypeState *partial_state_prev = &tcmd->partial_update_state_prev; + + /* Promote the partial update types based on the previous state + * so the values that no longer modified are reset before being left as-is. + * Needed for translation which can toggle snap-to-normal during transform. */ + const enum ePartialType partial_for_looptri = MAX2(partial_state->for_looptri, + partial_state_prev->for_looptri); + const enum ePartialType partial_for_normals = MAX2(partial_state->for_normals, + partial_state_prev->for_normals); + + if ((partial_for_looptri == PARTIAL_TYPE_ALL) && (partial_for_normals == PARTIAL_TYPE_ALL) && + (em->bm->totvert == em->bm->totvertsel)) { /* The additional cost of generating the partial connectivity data isn't justified * when all data needs to be updated. * * While proportional editing can cause all geometry to need updating with a partial * selection. It's impractical to calculate this ahead of time. Further, the down side of * using partial updates when their not needed is negligible. */ - if (em->bm->totvert == em->bm->totvertsel) { - BKE_editmesh_looptri_and_normals_calc(em); - return; - } - } - - /* Not matching. */ - if (partial_for_looptri != PARTIAL_NONE) { - BMPartialUpdate *bmpinfo = tc_mesh_partial_ensure(t, tc, partial_for_looptri); - BKE_editmesh_looptri_calc_with_partial_ex(em, - bmpinfo, - &(const struct BMeshCalcTessellation_Params){ - .face_normals = true, - }); - } - - if (partial_for_normals != PARTIAL_NONE) { - BMPartialUpdate *bmpinfo = tc_mesh_partial_ensure(t, tc, partial_for_normals); - /* While not a large difference, take advantage of existing normals where possible. */ - const bool face_normals = !((partial_for_looptri == PARTIAL_TYPE_ALL) || - ((partial_for_looptri == PARTIAL_TYPE_GROUP) && - (partial_for_normals == PARTIAL_TYPE_GROUP))); - BM_mesh_normals_update_with_partial_ex(em->bm, - bmpinfo, - &(const struct BMeshNormalsUpdate_Params){ - .face_normals = face_normals, - }); + BKE_editmesh_looptri_and_normals_calc(em); } + else { + if (partial_for_looptri != PARTIAL_NONE) { + BMPartialUpdate *bmpinfo = tc_mesh_partial_ensure(t, tc, partial_for_looptri); + BKE_editmesh_looptri_calc_with_partial_ex(em, + bmpinfo, + &(const struct BMeshCalcTessellation_Params){ + .face_normals = true, + }); + } + + if (partial_for_normals != PARTIAL_NONE) { + BMPartialUpdate *bmpinfo = tc_mesh_partial_ensure(t, tc, partial_for_normals); + /* While not a large difference, take advantage of existing normals where possible. */ + const bool face_normals = !((partial_for_looptri == PARTIAL_TYPE_ALL) || + ((partial_for_looptri == PARTIAL_TYPE_GROUP) && + (partial_for_normals == PARTIAL_TYPE_GROUP))); + BM_mesh_normals_update_with_partial_ex(em->bm, + bmpinfo, + &(const struct BMeshNormalsUpdate_Params){ + .face_normals = face_normals, + }); + } + } + + /* Store the previous requested (not the previous used), + * since the values used may have been promoted based on the previous types. */ + tcmd->partial_update_state_prev = *partial_state; } /** \} */ @@ -2059,13 +2090,13 @@ void recalcData_mesh(TransInfo *t) tc_mesh_customdatacorrect_restore(t); } - enum ePartialType partial_for_looptri, partial_for_normals; - tc_mesh_partial_types_calc(t, &partial_for_looptri, &partial_for_normals); + struct PartialTypeState partial_state; + tc_mesh_partial_types_calc(t, &partial_state); FOREACH_TRANS_DATA_CONTAINER (t, tc) { DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY); - tc_mesh_partial_update(t, tc, partial_for_looptri, partial_for_normals); + tc_mesh_partial_update(t, tc, &partial_state); } } /** \} */ |