Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/intern/mesh.c186
1 files changed, 64 insertions, 122 deletions
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index b89541173e1..2e725cbfbfd 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -2059,6 +2059,12 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type)
(me->mselect[me->totselect - 1].type == type));
}
+/**
+ * Compute 'split' (aka loop, or per face corner's) normals.
+ *
+ * \param r_lnors_spacearr Allows to get computed loop normal space array. That data, among other things,
+ * contains 'smooth fan' info, useful e.g. to split geometry along sharp edges...
+ */
void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr)
{
float (*r_loopnors)[3];
@@ -2094,7 +2100,10 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
BKE_mesh_normals_loop_split(
mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge,
mesh->mloop, r_loopnors, mesh->totloop, mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly,
- (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, r_lnors_spacearr, clnors, NULL);
+ /* Note that we enforce computing clnors when the clnor space array is requested by caller here.
+ * However, we obviously only use the autosmooth angle threshold only in case autosmooth is enabled. */
+ r_lnors_spacearr != NULL, (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : (float)M_PI,
+ r_lnors_spacearr, clnors, NULL);
if (free_polynors) {
MEM_freeN(polynors);
@@ -2126,118 +2135,70 @@ typedef struct SplitFaceNewEdge {
/* Detect needed new vertices, and update accordingly loops' vertex indices.
* WARNING! Leaves mesh in invalid state. */
static int split_faces_prepare_new_verts(
- const Mesh *mesh, MLoopNorSpaceArray *lnors_spacearr, SplitFaceNewVert **new_verts, MemArena *memarena,
- bool *r_need_vnors_recalc)
+ const Mesh *mesh, MLoopNorSpaceArray *lnors_spacearr, SplitFaceNewVert **new_verts, MemArena *memarena)
{
- /* Note: if lnors_spacearr is NULL, ther is no autosmooth handling, and we only split out flat polys. */
+ /* This is now mandatory, trying to do the job in simple way without that data is doomed to fail, even when only
+ * dealing with smooth/flat faces one can find cases that no simple algorithm can handle properly. */
+ BLI_assert(lnors_spacearr != NULL);
+
const int num_loops = mesh->totloop;
int num_verts = mesh->totvert;
MVert *mvert = mesh->mvert;
MLoop *mloop = mesh->mloop;
BLI_bitmap *verts_used = BLI_BITMAP_NEW(num_verts, __func__);
+ BLI_bitmap *done_loops = BLI_BITMAP_NEW(num_loops, __func__);
- if (lnors_spacearr) {
- BLI_bitmap *done_loops = BLI_BITMAP_NEW(num_loops, __func__);
-
- MLoop *ml = mloop;
- MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr;
- for (int loop_idx = 0; loop_idx < num_loops; loop_idx++, ml++, lnor_space++) {
- if (!BLI_BITMAP_TEST(done_loops, loop_idx)) {
- const int vert_idx = ml->v;
- const bool vert_used = BLI_BITMAP_TEST_BOOL(verts_used, vert_idx);
- /* If vert is already used by another smooth fan, we need a new vert for this one. */
- const int new_vert_idx = vert_used ? num_verts++ : vert_idx;
-
- BLI_assert(*lnor_space);
-
- if ((*lnor_space)->loops) {
- for (LinkNode *lnode = (*lnor_space)->loops; lnode; lnode = lnode->next) {
- const int ml_fan_idx = GET_INT_FROM_POINTER(lnode->link);
- BLI_BITMAP_ENABLE(done_loops, ml_fan_idx);
- if (vert_used) {
- mloop[ml_fan_idx].v = new_vert_idx;
- }
- }
- }
- else {
- /* Single loop in this fan... */
- BLI_BITMAP_ENABLE(done_loops, loop_idx);
+ MLoop *ml = mloop;
+ MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr;
+
+ for (int loop_idx = 0; loop_idx < num_loops; loop_idx++, ml++, lnor_space++) {
+ if (!BLI_BITMAP_TEST(done_loops, loop_idx)) {
+ const int vert_idx = ml->v;
+ const bool vert_used = BLI_BITMAP_TEST_BOOL(verts_used, vert_idx);
+ /* If vert is already used by another smooth fan, we need a new vert for this one. */
+ const int new_vert_idx = vert_used ? num_verts++ : vert_idx;
+
+ BLI_assert(*lnor_space);
+
+ if ((*lnor_space)->loops) {
+ for (LinkNode *lnode = (*lnor_space)->loops; lnode; lnode = lnode->next) {
+ const int ml_fan_idx = GET_INT_FROM_POINTER(lnode->link);
+ BLI_BITMAP_ENABLE(done_loops, ml_fan_idx);
if (vert_used) {
- ml->v = new_vert_idx;
+ mloop[ml_fan_idx].v = new_vert_idx;
}
}
-
- if (!vert_used) {
- BLI_BITMAP_ENABLE(verts_used, vert_idx);
- /* We need to update that vertex's normal here, we won't go over it again. */
- /* This is important! *DO NOT* set vnor to final computed lnor, vnor should always be defined to
- * 'automatic normal' value computed from its polys, not some custom normal.
- * Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */
- normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor);
- }
- else {
- /* Add new vert to list. */
- SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert));
- new_vert->orig_index = vert_idx;
- new_vert->new_index = new_vert_idx;
- new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */
- new_vert->next = *new_verts;
- *new_verts = new_vert;
- }
}
- }
-
- MEM_freeN(done_loops);
- }
- else {
- /* No loop normal spaces available, we only split out flat polys. */
- const int num_polys = mesh->totpoly;
- const MPoly *mpoly = mesh->mpoly;
-
- /* We do that in two loops, to keep original edges/verts to smooth polys preferencially. */
- const MPoly *mp = mpoly;
- for (int i = 0; i < num_polys; i++, mp++) {
- if (mp->flag & ME_SMOOTH) {
- const MLoop *ml = &mloop[mp->loopstart];
- for (int j = 0; j < mp->totloop; j++, ml++) {
- /* Just mark the vertex as used/reserved, that way neighbor flat polys, if any,
- * will have to create their own. */
- BLI_BITMAP_ENABLE(verts_used, ml->v);
+ else {
+ /* Single loop in this fan... */
+ BLI_BITMAP_ENABLE(done_loops, loop_idx);
+ if (vert_used) {
+ ml->v = new_vert_idx;
}
}
- }
- mp = mpoly;
- for (int i = 0; i < num_polys; i++, mp++) {
- if (!(mp->flag & ME_SMOOTH)) {
- MLoop *ml = &mloop[mp->loopstart];
- for (int j = 0; j < mp->totloop; j++, ml++) {
- const int vert_idx = ml->v;
-
- if (BLI_BITMAP_TEST(verts_used, vert_idx)) {
- /* Add new vert to list. */
- const int new_vert_idx = num_verts++;
- ml->v = new_vert_idx;
-
- SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert));
- new_vert->orig_index = vert_idx;
- new_vert->new_index = new_vert_idx;
- new_vert->vnor = NULL; /* See note below about normals. */
- new_vert->next = *new_verts;
- *new_verts = new_vert;
- }
- else {
- BLI_BITMAP_ENABLE(verts_used, vert_idx);
- }
- }
- /* Note: there is no way to get new normals for smooth vertices here (and we don't have direct access
- * to poly normals either for flat ones), so we'll have to recompute all vnors at the end... */
- *r_need_vnors_recalc = true;
+ if (!vert_used) {
+ BLI_BITMAP_ENABLE(verts_used, vert_idx);
+ /* We need to update that vertex's normal here, we won't go over it again. */
+ /* This is important! *DO NOT* set vnor to final computed lnor, vnor should always be defined to
+ * 'automatic normal' value computed from its polys, not some custom normal.
+ * Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */
+ normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor);
+ }
+ else {
+ /* Add new vert to list. */
+ SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert));
+ new_vert->orig_index = vert_idx;
+ new_vert->new_index = new_vert_idx;
+ new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */
+ new_vert->next = *new_verts;
+ *new_verts = new_vert;
}
}
}
+ MEM_freeN(done_loops);
MEM_freeN(verts_used);
return num_verts - mesh->totvert;
@@ -2356,27 +2317,17 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
}
BKE_mesh_tessface_clear(mesh);
- MLoopNorSpaceArray *lnors_spacearr = NULL;
- MemArena *memarena;
- bool need_vnors_recalc = false;
-
- if (mesh->flag & ME_AUTOSMOOTH) {
- lnors_spacearr = MEM_callocN(sizeof(*lnors_spacearr), __func__);
- /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */
- BKE_mesh_calc_normals_split_ex(mesh, lnors_spacearr);
- /* Stealing memarena from loop normals space array. */
- memarena = lnors_spacearr->mem;
- }
- else {
- /* We still have to split out flat faces... */
- memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- }
+ MLoopNorSpaceArray lnors_spacearr = {NULL};
+ /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */
+ BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr);
+ /* Stealing memarena from loop normals space array. */
+ MemArena *memarena = lnors_spacearr.mem;
SplitFaceNewVert *new_verts = NULL;
SplitFaceNewEdge *new_edges = NULL;
/* Detect loop normal spaces (a.k.a. smooth fans) that will need a new vert. */
- const int num_new_verts = split_faces_prepare_new_verts(mesh, lnors_spacearr, &new_verts, memarena, &need_vnors_recalc);
+ const int num_new_verts = split_faces_prepare_new_verts(mesh, &lnors_spacearr, &new_verts, memarena);
if (num_new_verts > 0) {
/* Reminder: beyond this point, there is no way out, mesh is in invalid state (due to early-reassignment of
@@ -2388,9 +2339,9 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
/* Reallocate all vert and edge related data. */
mesh->totvert += num_new_verts;
- mesh->totedge += num_new_edges;
CustomData_realloc(&mesh->vdata, mesh->totvert);
if (do_edges) {
+ mesh->totedge += num_new_edges;
CustomData_realloc(&mesh->edata, mesh->totedge);
}
/* Update pointers to a newly allocated memory. */
@@ -2410,18 +2361,9 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop);
}
- if (lnors_spacearr) {
- /* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */
- BKE_lnor_spacearr_free(lnors_spacearr);
- MEM_freeN(lnors_spacearr);
- }
- else {
- BLI_memarena_free(memarena);
- }
+ /* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */
+ BKE_lnor_spacearr_free(&lnors_spacearr);
- if (need_vnors_recalc) {
- BKE_mesh_calc_normals(mesh);
- }
#ifdef VALIDATE_MESH
BKE_mesh_validate(mesh, true, true);
#endif