From 8a1860bd9aecddf611b64e3e842bdc8c76f15cc6 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 14 Jun 2021 22:56:03 +1000 Subject: BMesh: support face-normal calculation in normal & looptri functions Support calculating face normals when tessellating. When this is done before updating vertex normals it gives ~20% performance improvement. Now vertex normal calculation only needs to perform a single pass on the mesh vertices when called after tessellation. Extended versions of normal & looptri update functions have been added: - BM_mesh_calc_tessellation_ex - BM_mesh_normals_update_ex Most callers don't need to be aware of this detail by using: - BKE_editmesh_looptri_and_normals_calc - BKE_editmesh_looptri_and_normals_calc_with_partial - EDBM_update also takes advantage of this, where calling EDBM_update with calc_looptri & calc_normals enabled uses the faster normal updating logic. --- source/blender/blenkernel/BKE_editmesh.h | 10 ++ source/blender/blenkernel/intern/editmesh.c | 60 +++++++- source/blender/bmesh/intern/bmesh_mesh_normals.c | 41 ++++-- source/blender/bmesh/intern/bmesh_mesh_normals.h | 12 ++ .../blender/bmesh/intern/bmesh_mesh_tessellate.c | 161 +++++++++++++++++---- .../blender/bmesh/intern/bmesh_mesh_tessellate.h | 16 ++ source/blender/editors/include/ED_mesh.h | 3 + source/blender/editors/mesh/editmesh_utils.c | 24 ++- source/blender/editors/object/object_edit.c | 4 +- source/blender/editors/object/object_hook.c | 3 +- source/blender/editors/object/object_relations.c | 3 +- .../editors/transform/transform_convert_mesh.c | 6 +- .../transform/transform_convert_mesh_skin.c | 3 +- source/blender/makesrna/intern/rna_object.c | 3 +- 14 files changed, 286 insertions(+), 63 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h index 3a1eedfd807..075a9bc0eac 100644 --- a/source/blender/blenkernel/BKE_editmesh.h +++ b/source/blender/blenkernel/BKE_editmesh.h @@ -34,6 +34,7 @@ extern "C" { struct BMLoop; struct BMesh; struct BMPartialUpdate; +struct BMeshCalcTessellation_Params; struct BoundBox; struct Depsgraph; struct Mesh; @@ -85,8 +86,17 @@ typedef struct BMEditMesh { } BMEditMesh; /* editmesh.c */ +void BKE_editmesh_looptri_calc_ex(BMEditMesh *em, + const struct BMeshCalcTessellation_Params *params); void BKE_editmesh_looptri_calc(BMEditMesh *em); +void BKE_editmesh_looptri_calc_with_partial_ex(BMEditMesh *em, + struct BMPartialUpdate *bmpinfo, + const struct BMeshCalcTessellation_Params *params); void BKE_editmesh_looptri_calc_with_partial(BMEditMesh *em, struct BMPartialUpdate *bmpinfo); +void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em, + struct BMPartialUpdate *bmpinfo); + +void BKE_editmesh_looptri_and_normals_calc(BMEditMesh *em); BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate); BMEditMesh *BKE_editmesh_copy(BMEditMesh *em); diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c index 472de1f3c77..b908df267c4 100644 --- a/source/blender/blenkernel/intern/editmesh.c +++ b/source/blender/blenkernel/intern/editmesh.c @@ -96,7 +96,8 @@ BMEditMesh *BKE_editmesh_from_object(Object *ob) return ((Mesh *)ob->data)->edit_mesh; } -static void editmesh_tessface_calc_intern(BMEditMesh *em) +static void editmesh_tessface_calc_intern(BMEditMesh *em, + const struct BMeshCalcTessellation_Params *params) { /* allocating space before calculating the tessellation */ @@ -130,12 +131,13 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em) em->tottri = looptris_tot; /* after allocating the em->looptris, we're ready to tessellate */ - BM_mesh_calc_tessellation(em->bm, em->looptris); + BM_mesh_calc_tessellation_ex(em->bm, em->looptris, params); } -void BKE_editmesh_looptri_calc(BMEditMesh *em) +void BKE_editmesh_looptri_calc_ex(BMEditMesh *em, + const struct BMeshCalcTessellation_Params *params) { - editmesh_tessface_calc_intern(em); + editmesh_tessface_calc_intern(em, params); /* commented because editbmesh_build_data() ensures we get tessfaces */ #if 0 @@ -149,12 +151,58 @@ void BKE_editmesh_looptri_calc(BMEditMesh *em) #endif } -void BKE_editmesh_looptri_calc_with_partial(BMEditMesh *em, struct BMPartialUpdate *bmpinfo) +void BKE_editmesh_looptri_calc(BMEditMesh *em) +{ + BKE_editmesh_looptri_calc_ex(em, + &(const struct BMeshCalcTessellation_Params){ + .face_normals = false, + }); +} + +/** + * Performing the face normal calculation at the same time as tessellation + * gives a reasonable performance boost (approx ~20% faster). + */ +void BKE_editmesh_looptri_and_normals_calc(BMEditMesh *em) +{ + BKE_editmesh_looptri_calc_ex(em, + &(const struct BMeshCalcTessellation_Params){ + .face_normals = true, + }); + BM_mesh_normals_update_ex(em->bm, + &(const struct BMeshNormalsUpdate_Params){ + .face_normals = false, + }); +} + +void BKE_editmesh_looptri_calc_with_partial_ex(BMEditMesh *em, + struct BMPartialUpdate *bmpinfo, + const struct BMeshCalcTessellation_Params *params) { BLI_assert(em->tottri == poly_to_tri_count(em->bm->totface, em->bm->totloop)); BLI_assert(em->looptris != NULL); - BM_mesh_calc_tessellation_with_partial(em->bm, em->looptris, bmpinfo); + BM_mesh_calc_tessellation_with_partial_ex(em->bm, em->looptris, bmpinfo, params); +} + +void BKE_editmesh_looptri_calc_with_partial(BMEditMesh *em, struct BMPartialUpdate *bmpinfo) +{ + BKE_editmesh_looptri_calc_with_partial_ex(em, bmpinfo, false); +} + +void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em, + struct BMPartialUpdate *bmpinfo) +{ + BKE_editmesh_looptri_calc_with_partial_ex(em, + bmpinfo, + &(const struct BMeshCalcTessellation_Params){ + .face_normals = true, + }); + BM_mesh_normals_update_with_partial_ex(em->bm, + bmpinfo, + &(const struct BMeshNormalsUpdate_Params){ + .face_normals = false, + }); } void BKE_editmesh_free_derivedmesh(BMEditMesh *em) diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.c b/source/blender/bmesh/intern/bmesh_mesh_normals.c index bf30f3a52e1..bddd3da98b7 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_normals.c +++ b/source/blender/bmesh/intern/bmesh_mesh_normals.c @@ -240,19 +240,29 @@ static void bm_face_calc_normals_cb(void *UNUSED(userdata), * * Updates the normals of a mesh. */ -void BM_mesh_normals_update(BMesh *bm) +void BM_mesh_normals_update_ex(BMesh *bm, const struct BMeshNormalsUpdate_Params *params) { - /* Calculate all face normals. */ - TaskParallelSettings settings; - BLI_parallel_mempool_settings_defaults(&settings); - settings.use_threading = bm->totedge >= BM_OMP_LIMIT; + if (params->face_normals) { + /* Calculate all face normals. */ + TaskParallelSettings settings; + BLI_parallel_mempool_settings_defaults(&settings); + settings.use_threading = bm->totedge >= BM_OMP_LIMIT; - BM_iter_parallel(bm, BM_FACES_OF_MESH, bm_face_calc_normals_cb, NULL, &settings); + BM_iter_parallel(bm, BM_FACES_OF_MESH, bm_face_calc_normals_cb, NULL, &settings); + } /* Add weighted face normals to vertices, and normalize vert normals. */ bm_mesh_verts_calc_normals(bm, NULL, NULL, NULL); } +void BM_mesh_normals_update(BMesh *bm) +{ + BM_mesh_normals_update_ex(bm, + &(const struct BMeshNormalsUpdate_Params){ + .face_normals = true, + }); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -277,7 +287,9 @@ static void bm_partial_verts_parallel_range_calc_normal_cb( * A version of #BM_mesh_normals_update that updates a subset of geometry, * used to avoid the overhead of updating everything. */ -void BM_mesh_normals_update_with_partial(BMesh *UNUSED(bm), const BMPartialUpdate *bmpinfo) +void BM_mesh_normals_update_with_partial_ex(BMesh *UNUSED(bm), + const BMPartialUpdate *bmpinfo, + const struct BMeshNormalsUpdate_Params *params) { BLI_assert(bmpinfo->params.do_normals); @@ -290,14 +302,25 @@ void BM_mesh_normals_update_with_partial(BMesh *UNUSED(bm), const BMPartialUpdat BLI_parallel_range_settings_defaults(&settings); /* Faces. */ - BLI_task_parallel_range( - 0, faces_len, faces, bm_partial_faces_parallel_range_calc_normals_cb, &settings); + if (params->face_normals) { + BLI_task_parallel_range( + 0, faces_len, faces, bm_partial_faces_parallel_range_calc_normals_cb, &settings); + } /* Verts. */ BLI_task_parallel_range( 0, verts_len, verts, bm_partial_verts_parallel_range_calc_normal_cb, &settings); } +void BM_mesh_normals_update_with_partial(BMesh *bm, const BMPartialUpdate *bmpinfo) +{ + BM_mesh_normals_update_with_partial_ex(bm, + bmpinfo, + &(const struct BMeshNormalsUpdate_Params){ + .face_normals = true, + }); +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.h b/source/blender/bmesh/intern/bmesh_mesh_normals.h index 41191340e9e..ecd627d4bfe 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_normals.h +++ b/source/blender/bmesh/intern/bmesh_mesh_normals.h @@ -22,7 +22,19 @@ #include "bmesh_class.h" +struct BMeshNormalsUpdate_Params { + /** + * When calculating tessellation as well as normals, tessellate & calculate face normals + * for improved performance. See #BMeshCalcTessellation_Params + */ + bool face_normals; +}; + +void BM_mesh_normals_update_ex(BMesh *bm, const struct BMeshNormalsUpdate_Params *param); void BM_mesh_normals_update(BMesh *bm); +void BM_mesh_normals_update_with_partial_ex(BMesh *bm, + const struct BMPartialUpdate *bmpinfo, + const struct BMeshNormalsUpdate_Params *param); void BM_mesh_normals_update_with_partial(BMesh *bm, const struct BMPartialUpdate *bmpinfo); void BM_verts_calc_normal_vcos(BMesh *bm, diff --git a/source/blender/bmesh/intern/bmesh_mesh_tessellate.c b/source/blender/bmesh/intern/bmesh_mesh_tessellate.c index 7a95e52ce25..4092ad22ef9 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_tessellate.c +++ b/source/blender/bmesh/intern/bmesh_mesh_tessellate.c @@ -50,9 +50,13 @@ /** \name Default Mesh Tessellation * \{ */ -static int mesh_calc_tessellation_for_face(BMLoop *(*looptris)[3], - BMFace *efa, - MemArena **pf_arena_p) +/** + * \param face_normal: This will be optimized out as a constant. + */ +BLI_INLINE int mesh_calc_tessellation_for_face_impl(BMLoop *(*looptris)[3], + BMFace *efa, + MemArena **pf_arena_p, + const bool face_normal) { switch (efa->len) { case 3: { @@ -62,6 +66,9 @@ static int mesh_calc_tessellation_for_face(BMLoop *(*looptris)[3], l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa); l_ptr[1] = l = l->next; l_ptr[2] = l->next; + if (face_normal) { + normal_tri_v3(efa->no, l_ptr[0]->v->co, l_ptr[1]->v->co, l_ptr[2]->v->co); + } return 1; } case 4: { @@ -74,6 +81,11 @@ static int mesh_calc_tessellation_for_face(BMLoop *(*looptris)[3], (l_ptr_a[2] = l_ptr_b[1] = l = l->next); (l_ptr_b[2] = l->next); + if (face_normal) { + normal_quad_v3( + efa->no, l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co); + } + if (UNLIKELY(is_quad_flip_v3_first_third_fast( l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co))) { /* Flip out of degenerate 0-2 state. */ @@ -83,6 +95,10 @@ static int mesh_calc_tessellation_for_face(BMLoop *(*looptris)[3], return 2; } default: { + if (face_normal) { + BM_face_calc_normal(efa, efa->no); + } + BMLoop *l_iter, *l_first; BMLoop **l_arr; @@ -128,13 +144,29 @@ static int mesh_calc_tessellation_for_face(BMLoop *(*looptris)[3], } } +static int mesh_calc_tessellation_for_face(BMLoop *(*looptris)[3], + BMFace *efa, + MemArena **pf_arena_p) +{ + return mesh_calc_tessellation_for_face_impl(looptris, efa, pf_arena_p, false); +} + +static int mesh_calc_tessellation_for_face_with_normal(BMLoop *(*looptris)[3], + BMFace *efa, + MemArena **pf_arena_p) +{ + return mesh_calc_tessellation_for_face_impl(looptris, efa, pf_arena_p, true); +} + /** * \brief BM_mesh_calc_tessellation get the looptris and its number from a certain bmesh * \param looptris: * * \note \a looptris Must be pre-allocated to at least the size of given by: poly_to_tri_count */ -static void bm_mesh_calc_tessellation__single_threaded(BMesh *bm, BMLoop *(*looptris)[3]) +static void bm_mesh_calc_tessellation__single_threaded(BMesh *bm, + BMLoop *(*looptris)[3], + const char face_normals) { #ifndef NDEBUG const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop); @@ -146,9 +178,18 @@ static void bm_mesh_calc_tessellation__single_threaded(BMesh *bm, BMLoop *(*loop MemArena *pf_arena = NULL; - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - BLI_assert(efa->len >= 3); - i += mesh_calc_tessellation_for_face(looptris + i, efa, &pf_arena); + if (face_normals) { + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + BLI_assert(efa->len >= 3); + BM_face_calc_normal(efa, efa->no); + i += mesh_calc_tessellation_for_face_with_normal(looptris + i, efa, &pf_arena); + } + } + else { + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + BLI_assert(efa->len >= 3); + i += mesh_calc_tessellation_for_face(looptris + i, efa, &pf_arena); + } } if (pf_arena) { @@ -175,6 +216,18 @@ static void mesh_calc_tessellation_for_face_fn(void *__restrict userdata, mesh_calc_tessellation_for_face(looptris + offset, f, &tls_data->pf_arena); } +static void mesh_calc_tessellation_for_face_with_normals_fn(void *__restrict userdata, + MempoolIterData *mp_f, + const TaskParallelTLS *__restrict tls) +{ + struct TessellationUserTLS *tls_data = tls->userdata_chunk; + BMLoop *(*looptris)[3] = userdata; + BMFace *f = (BMFace *)mp_f; + BMLoop *l = BM_FACE_FIRST_LOOP(f); + const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2); + mesh_calc_tessellation_for_face_with_normal(looptris + offset, f, &tls_data->pf_arena); +} + static void mesh_calc_tessellation_for_face_free_fn(const void *__restrict UNUSED(userdata), void *__restrict tls_v) { @@ -184,7 +237,9 @@ static void mesh_calc_tessellation_for_face_free_fn(const void *__restrict UNUSE } } -static void bm_mesh_calc_tessellation__multi_threaded(BMesh *bm, BMLoop *(*looptris)[3]) +static void bm_mesh_calc_tessellation__multi_threaded(BMesh *bm, + BMLoop *(*looptris)[3], + const char face_normals) { BM_mesh_elem_index_ensure(bm, BM_LOOP | BM_FACE); @@ -194,19 +249,31 @@ static void bm_mesh_calc_tessellation__multi_threaded(BMesh *bm, BMLoop *(*loopt settings.userdata_chunk = &tls_dummy; settings.userdata_chunk_size = sizeof(tls_dummy); settings.func_free = mesh_calc_tessellation_for_face_free_fn; - BM_iter_parallel(bm, BM_FACES_OF_MESH, mesh_calc_tessellation_for_face_fn, looptris, &settings); + BM_iter_parallel(bm, + BM_FACES_OF_MESH, + face_normals ? mesh_calc_tessellation_for_face_with_normals_fn : + mesh_calc_tessellation_for_face_fn, + looptris, + &settings); } -void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3]) +void BM_mesh_calc_tessellation_ex(BMesh *bm, + BMLoop *(*looptris)[3], + const struct BMeshCalcTessellation_Params *params) { if (bm->totface < BM_FACE_TESSELLATE_THREADED_LIMIT) { - bm_mesh_calc_tessellation__single_threaded(bm, looptris); + bm_mesh_calc_tessellation__single_threaded(bm, looptris, params->face_normals); } else { - bm_mesh_calc_tessellation__multi_threaded(bm, looptris); + bm_mesh_calc_tessellation__multi_threaded(bm, looptris, params->face_normals); } } +void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3]) +{ + BM_mesh_calc_tessellation_ex(bm, looptris, false); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -234,6 +301,17 @@ static void mesh_calc_tessellation_for_face_partial_fn(void *__restrict userdata mesh_calc_tessellation_for_face(data->looptris + offset, f, &tls_data->pf_arena); } +static void mesh_calc_tessellation_for_face_partial_with_normals_fn( + void *__restrict userdata, const int index, const TaskParallelTLS *__restrict tls) +{ + struct PartialTessellationUserTLS *tls_data = tls->userdata_chunk; + struct PartialTessellationUserData *data = userdata; + BMFace *f = data->faces[index]; + BMLoop *l = BM_FACE_FIRST_LOOP(f); + const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2); + mesh_calc_tessellation_for_face_with_normal(data->looptris + offset, f, &tls_data->pf_arena); +} + static void mesh_calc_tessellation_for_face_partial_free_fn( const void *__restrict UNUSED(userdata), void *__restrict tls_v) { @@ -243,8 +321,10 @@ static void mesh_calc_tessellation_for_face_partial_free_fn( } } -static void bm_mesh_calc_tessellation_with_partial__multi_threaded(BMLoop *(*looptris)[3], - const BMPartialUpdate *bmpinfo) +static void bm_mesh_calc_tessellation_with_partial__multi_threaded( + BMLoop *(*looptris)[3], + const BMPartialUpdate *bmpinfo, + const struct BMeshCalcTessellation_Params *params) { const int faces_len = bmpinfo->faces_len; BMFace **faces = bmpinfo->faces; @@ -261,23 +341,40 @@ static void bm_mesh_calc_tessellation_with_partial__multi_threaded(BMLoop *(*loo settings.userdata_chunk_size = sizeof(tls_dummy); settings.func_free = mesh_calc_tessellation_for_face_partial_free_fn; - BLI_task_parallel_range( - 0, faces_len, &data, mesh_calc_tessellation_for_face_partial_fn, &settings); + BLI_task_parallel_range(0, + faces_len, + &data, + params->face_normals ? + mesh_calc_tessellation_for_face_partial_with_normals_fn : + mesh_calc_tessellation_for_face_partial_fn, + &settings); } -static void bm_mesh_calc_tessellation_with_partial__single_threaded(BMLoop *(*looptris)[3], - const BMPartialUpdate *bmpinfo) +static void bm_mesh_calc_tessellation_with_partial__single_threaded( + BMLoop *(*looptris)[3], + const BMPartialUpdate *bmpinfo, + const struct BMeshCalcTessellation_Params *params) { const int faces_len = bmpinfo->faces_len; BMFace **faces = bmpinfo->faces; MemArena *pf_arena = NULL; - for (int index = 0; index < faces_len; index++) { - BMFace *f = faces[index]; - BMLoop *l = BM_FACE_FIRST_LOOP(f); - const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2); - mesh_calc_tessellation_for_face(looptris + offset, f, &pf_arena); + if (params->face_normals) { + for (int index = 0; index < faces_len; index++) { + BMFace *f = faces[index]; + BMLoop *l = BM_FACE_FIRST_LOOP(f); + const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2); + mesh_calc_tessellation_for_face_with_normal(looptris + offset, f, &pf_arena); + } + } + else { + for (int index = 0; index < faces_len; index++) { + BMFace *f = faces[index]; + BMLoop *l = BM_FACE_FIRST_LOOP(f); + const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2); + mesh_calc_tessellation_for_face(looptris + offset, f, &pf_arena); + } } if (pf_arena) { @@ -285,22 +382,30 @@ static void bm_mesh_calc_tessellation_with_partial__single_threaded(BMLoop *(*lo } } -void BM_mesh_calc_tessellation_with_partial(BMesh *bm, - BMLoop *(*looptris)[3], - const BMPartialUpdate *bmpinfo) +void BM_mesh_calc_tessellation_with_partial_ex(BMesh *bm, + BMLoop *(*looptris)[3], + const BMPartialUpdate *bmpinfo, + const struct BMeshCalcTessellation_Params *params) { BLI_assert(bmpinfo->params.do_tessellate); BM_mesh_elem_index_ensure(bm, BM_LOOP | BM_FACE); if (bmpinfo->faces_len < BM_FACE_TESSELLATE_THREADED_LIMIT) { - bm_mesh_calc_tessellation_with_partial__single_threaded(looptris, bmpinfo); + bm_mesh_calc_tessellation_with_partial__single_threaded(looptris, bmpinfo, params); } else { - bm_mesh_calc_tessellation_with_partial__multi_threaded(looptris, bmpinfo); + bm_mesh_calc_tessellation_with_partial__multi_threaded(looptris, bmpinfo, params); } } +void BM_mesh_calc_tessellation_with_partial(BMesh *bm, + BMLoop *(*looptris)[3], + const BMPartialUpdate *bmpinfo) +{ + BM_mesh_calc_tessellation_with_partial_ex(bm, looptris, bmpinfo, false); +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/bmesh/intern/bmesh_mesh_tessellate.h b/source/blender/bmesh/intern/bmesh_mesh_tessellate.h index f68a91cb988..9a6a20d7568 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_tessellate.h +++ b/source/blender/bmesh/intern/bmesh_mesh_tessellate.h @@ -22,9 +22,25 @@ struct BMPartialUpdate; +struct BMeshCalcTessellation_Params { + /** + * When calculating normals as well as tessellation, calculate normals after tessellation + * for improved performance. See #BMeshCalcTessellation_Params + */ + bool face_normals; +}; + +void BM_mesh_calc_tessellation_ex(BMesh *bm, + BMLoop *(*looptris)[3], + const struct BMeshCalcTessellation_Params *params); void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3]); + void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3]); +void BM_mesh_calc_tessellation_with_partial_ex(BMesh *bm, + BMLoop *(*looptris)[3], + const struct BMPartialUpdate *bmpinfo, + const struct BMeshCalcTessellation_Params *params); void BM_mesh_calc_tessellation_with_partial(BMesh *bm, BMLoop *(*looptris)[3], const struct BMPartialUpdate *bmpinfo); diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index b76c35c7d7a..0e2be5eb568 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -36,6 +36,7 @@ struct BMFace; struct BMLoop; struct BMVert; struct BMesh; +struct BMeshNormalsUpdate_Params; struct Base; struct Depsgraph; struct ID; @@ -76,6 +77,8 @@ struct BMFace *EDBM_verts_mirror_get_face(struct BMEditMesh *em, struct BMFace * void EDBM_verts_mirror_cache_clear(struct BMEditMesh *em, struct BMVert *v); void EDBM_verts_mirror_cache_end(struct BMEditMesh *em); +void EDBM_mesh_normals_update_ex(struct BMEditMesh *em, + const struct BMeshNormalsUpdate_Params *params); void EDBM_mesh_normals_update(struct BMEditMesh *em); void EDBM_mesh_clear(struct BMEditMesh *em); diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index c8f8f12ba90..071ca818120 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -1405,9 +1405,17 @@ bool EDBM_mesh_reveal(BMEditMesh *em, bool select) /** \name Update API * \{ */ +void EDBM_mesh_normals_update_ex(BMEditMesh *em, const struct BMeshNormalsUpdate_Params *params) +{ + BM_mesh_normals_update_ex(em->bm, params); +} + void EDBM_mesh_normals_update(BMEditMesh *em) { - BM_mesh_normals_update(em->bm); + EDBM_mesh_normals_update_ex(em, + &(const struct BMeshNormalsUpdate_Params){ + .face_normals = true, + }); } void EDBM_stats_update(BMEditMesh *em) @@ -1449,12 +1457,18 @@ void EDBM_update(Mesh *mesh, const struct EDBMUpdate_Params *params) DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, &mesh->id); - if (params->calc_normals) { - EDBM_mesh_normals_update(em); + if (params->calc_normals && params->calc_looptri) { + /* Calculating both has some performance gains. */ + BKE_editmesh_looptri_and_normals_calc(em); } + else { + if (params->calc_normals) { + EDBM_mesh_normals_update(em); + } - if (params->calc_looptri) { - BKE_editmesh_looptri_calc(em); + if (params->calc_looptri) { + BKE_editmesh_looptri_calc(em); + } } if (params->is_destructive) { diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 5be572baec5..c8923bb55c1 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -794,9 +794,7 @@ bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag BMEditMesh *em = BKE_editmesh_from_object(ob); if (LIKELY(em)) { - /* order doesn't matter */ - EDBM_mesh_normals_update(em); - BKE_editmesh_looptri_calc(em); + BKE_editmesh_looptri_and_normals_calc(em); } WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_MESH, NULL); diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index d56ee17a73f..7122fd09892 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -350,8 +350,7 @@ static bool object_hook_index_array(Main *bmain, em = me->edit_mesh; - EDBM_mesh_normals_update(em); - BKE_editmesh_looptri_calc(em); + BKE_editmesh_looptri_and_normals_calc(em); /* check selected vertices first */ if (return_editmesh_indexar(em, r_tot, r_indexar, r_cent) == 0) { diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index f3433833b5f..cdf12bcb5df 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -153,8 +153,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) em = me->edit_mesh; - EDBM_mesh_normals_update(em); - BKE_editmesh_looptri_calc(em); + BKE_editmesh_looptri_and_normals_calc(em); /* Make sure the evaluated mesh is updated. * diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index 422370cb13b..4c674136b6a 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -1842,13 +1842,11 @@ void recalcData_mesh(TransInfo *t) * 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) { - EDBM_mesh_normals_update(em); - BKE_editmesh_looptri_calc(em); + BKE_editmesh_looptri_and_normals_calc(em); } else { BMPartialUpdate *partial_update_cache = tc_mesh_ensure_partial_update(t, tc); - BM_mesh_normals_update_with_partial(em->bm, partial_update_cache); - BKE_editmesh_looptri_calc_with_partial(em, partial_update_cache); + BKE_editmesh_looptri_and_normals_calc_with_partial(em, partial_update_cache); } } } diff --git a/source/blender/editors/transform/transform_convert_mesh_skin.c b/source/blender/editors/transform/transform_convert_mesh_skin.c index 7c61da31f72..69b44998980 100644 --- a/source/blender/editors/transform/transform_convert_mesh_skin.c +++ b/source/blender/editors/transform/transform_convert_mesh_skin.c @@ -300,8 +300,7 @@ void recalcData_mesh_skin(TransInfo *t) FOREACH_TRANS_DATA_CONTAINER (t, tc) { DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY); BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); - EDBM_mesh_normals_update(em); - BKE_editmesh_looptri_calc(em); + BKE_editmesh_looptri_and_normals_calc(em); } } /** \} */ diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index b339682222c..8ad739b5c1a 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -476,8 +476,7 @@ static void rna_Object_active_shape_update(Main *bmain, Scene *UNUSED(scene), Po DEG_id_tag_update(&me->id, 0); - EDBM_mesh_normals_update(em); - BKE_editmesh_looptri_calc(em); + BKE_editmesh_looptri_and_normals_calc(em); break; } case OB_CURVE: -- cgit v1.2.3