diff options
Diffstat (limited to 'source/blender/blenkernel/intern/mesh_mapping.c')
-rw-r--r-- | source/blender/blenkernel/intern/mesh_mapping.c | 185 |
1 files changed, 164 insertions, 21 deletions
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c index a472b6e5bc1..8562988b5e1 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.c +++ b/source/blender/blenkernel/intern/mesh_mapping.c @@ -393,6 +393,60 @@ void BKE_mesh_vert_edge_vert_map_create( } /** + * Generates a map where the key is the edge and the value is a list of loops that use that edge. + * Loops indices of a same poly are contiguous and in winding order. + * The lists are allocated from one memory pool. + */ +void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map, int **r_mem, + const MEdge *UNUSED(medge), const int totedge, + const MPoly *mpoly, const int totpoly, + const MLoop *mloop, const int totloop) +{ + MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totedge, "edge-poly map"); + int *indices = MEM_mallocN(sizeof(int) * (size_t)totloop * 2, "edge-poly map mem"); + int *index_step; + const MPoly *mp; + int i; + + /* count face users */ + for (i = 0, mp = mpoly; i < totpoly; mp++, i++) { + const MLoop *ml; + int j = mp->totloop; + for (ml = &mloop[mp->loopstart]; j--; ml++) { + map[ml->e].count += 2; + } + } + + /* create offsets */ + index_step = indices; + for (i = 0; i < totedge; i++) { + map[i].indices = index_step; + index_step += map[i].count; + + /* re-count, using this as an index below */ + map[i].count = 0; + } + + /* assign loop-edge users */ + for (i = 0, mp = mpoly; i < totpoly; mp++, i++) { + const MLoop *ml; + MeshElemMap *map_ele; + const int max_loop = mp->loopstart + mp->totloop; + int j = mp->loopstart; + for (ml = &mloop[j]; j < max_loop; j++, ml++) { + map_ele = &map[ml->e]; + map_ele->indices[map_ele->count++] = j; + map_ele->indices[map_ele->count++] = j + 1; + } + /* last edge/loop of poly, must point back to first loop! */ + map_ele->indices[map_ele->count - 1] = mp->loopstart; + } + + *r_map = map; + *r_mem = indices; +} + +/** * Generates a map where the key is the edge and the value is a list of polygons that use that edge. * The lists are allocated from one memory pool. */ @@ -539,12 +593,12 @@ void BKE_mesh_origindex_map_create_looptri( */ typedef bool (*MeshRemap_CheckIslandBoundary)( const struct MPoly *mpoly, const struct MLoop *mloop, const struct MEdge *medge, - const int nbr_egde_users); + const int nbr_egde_users, void *user_data); static void poly_edge_loop_islands_calc( const MEdge *medge, const int totedge, const MPoly *mpoly, const int totpoly, const MLoop *mloop, const int totloop, MeshElemMap *edge_poly_map, - const bool use_bitflags, MeshRemap_CheckIslandBoundary edge_boundary_check, + const bool use_bitflags, MeshRemap_CheckIslandBoundary edge_boundary_check, void *edge_boundary_check_data, int **r_poly_groups, int *r_totgroup, BLI_bitmap **r_edge_borders, int *r_totedgeborder) { int *poly_groups; @@ -626,7 +680,7 @@ static void poly_edge_loop_islands_calc( const MeshElemMap *map_ele = &edge_poly_map[me_idx]; const int *p = map_ele->indices; int i = map_ele->count; - if (!edge_boundary_check(mp, ml, me, i)) { + if (!edge_boundary_check(mp, ml, me, i, edge_boundary_check_data)) { for (; i--; p++) { /* if we meet other non initialized its a bug */ BLI_assert(ELEM(poly_groups[*p], 0, poly_group_id)); @@ -718,7 +772,7 @@ static void poly_edge_loop_islands_calc( } static bool poly_is_island_boundary_smooth_cb( - const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me, const int nbr_egde_users) + const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me, const int nbr_egde_users, void *UNUSED(user_data)) { /* Edge is sharp if its poly is sharp, or edge itself is sharp, or edge is not used by exactly two polygons. */ return (!(mp->flag & ME_SMOOTH) || (me->flag & ME_SHARP) || (nbr_egde_users != 2)); @@ -741,7 +795,7 @@ int *BKE_mesh_calc_smoothgroups(const MEdge *medge, const int totedge, poly_edge_loop_islands_calc( medge, totedge, mpoly, totpoly, mloop, totloop, NULL, use_bitflags, - poly_is_island_boundary_smooth_cb, &poly_groups, r_totgroup, NULL, NULL); + poly_is_island_boundary_smooth_cb, NULL, &poly_groups, r_totgroup, NULL, NULL); return poly_groups; } @@ -848,28 +902,60 @@ void BKE_mesh_loop_islands_add( * Would make things much more complex though, and each UVMap would then need its own mesh mapping, * not sure we want that at all! */ +typedef struct MeshCheckIslandBoundaryUv { + const MLoop *loops; + const MLoopUV *luvs; + const MeshElemMap *edge_loop_map; +} MeshCheckIslandBoundaryUv; + static bool mesh_check_island_boundary_uv( - const MPoly *UNUSED(mp), const MLoop *UNUSED(ml), const MEdge *me, const int UNUSED(nbr_egde_users)) + const MPoly *UNUSED(mp), const MLoop *ml, const MEdge *me, + const int UNUSED(nbr_egde_users), void *user_data) { - /* Edge is UV boundary if tagged as seam. */ - return (me->flag & ME_SEAM) != 0; + if (user_data) { + const MeshCheckIslandBoundaryUv *data = user_data; + const MLoop *loops = data->loops; + const MLoopUV *luvs = data->luvs; + const MeshElemMap *edge_to_loops = &data->edge_loop_map[ml->e]; + + BLI_assert(edge_to_loops->count >= 2 && (edge_to_loops->count % 2) == 0); + + const unsigned int v1 = loops[edge_to_loops->indices[0]].v; + const unsigned int v2 = loops[edge_to_loops->indices[1]].v; + const float *uvco_v1 = luvs[edge_to_loops->indices[0]].uv; + const float *uvco_v2 = luvs[edge_to_loops->indices[1]].uv; + for (int i = 2; i < edge_to_loops->count; i += 2) { + if (loops[edge_to_loops->indices[i]].v == v1) { + if (!equals_v2v2(uvco_v1, luvs[edge_to_loops->indices[i]].uv) || + !equals_v2v2(uvco_v2, luvs[edge_to_loops->indices[i + 1]].uv)) + { + return true; + } + } + else { + BLI_assert(loops[edge_to_loops->indices[i]].v == v2); + UNUSED_VARS_NDEBUG(v2); + if (!equals_v2v2(uvco_v2, luvs[edge_to_loops->indices[i]].uv) || + !equals_v2v2(uvco_v1, luvs[edge_to_loops->indices[i + 1]].uv)) + { + return true; + } + } + } + return false; + } + else { + /* Edge is UV boundary if tagged as seam. */ + return (me->flag & ME_SEAM) != 0; + } } -/** - * Calculate UV islands. - * - * \note Currently we only consider edges tagges as seams as UV boundaries. This has the advantages of simplicity, - * and being valid/common to all UV maps. However, it means actual UV islands whithout matching UV seams - * will not be handled correctly... - * - * \note All this could be optimized... - * Not sure it would be worth the more complex code, though, those loops are supposed to be really quick to do... - */ -bool BKE_mesh_calc_islands_loop_poly_uv( +static bool mesh_calc_islands_loop_poly_uv( MVert *UNUSED(verts), const int UNUSED(totvert), MEdge *edges, const int totedge, MPoly *polys, const int totpoly, MLoop *loops, const int totloop, + const MLoopUV *luvs, MeshIslandStore *r_island_store) { int *poly_groups = NULL; @@ -879,6 +965,11 @@ bool BKE_mesh_calc_islands_loop_poly_uv( MeshElemMap *edge_poly_map; int *edge_poly_mem; + MeshElemMap *edge_loop_map; + int *edge_loop_mem; + + MeshCheckIslandBoundaryUv edge_boundary_check_data; + int *poly_indices; int *loop_indices; int num_pidx, num_lidx; @@ -899,9 +990,18 @@ bool BKE_mesh_calc_islands_loop_poly_uv( BKE_mesh_edge_poly_map_create(&edge_poly_map, &edge_poly_mem, edges, totedge, polys, totpoly, loops, totloop); + if (luvs) { + BKE_mesh_edge_loop_map_create(&edge_loop_map, &edge_loop_mem, + edges, totedge, polys, totpoly, loops, totloop); + edge_boundary_check_data.loops = loops; + edge_boundary_check_data.luvs = luvs; + edge_boundary_check_data.edge_loop_map = edge_loop_map; + } + poly_edge_loop_islands_calc( - edges, totedge, polys, totpoly, loops, totloop, edge_poly_map, false, - mesh_check_island_boundary_uv, &poly_groups, &num_poly_groups, &edge_borders, &num_edge_borders); + edges, totedge, polys, totpoly, loops, totloop, edge_poly_map, false, + mesh_check_island_boundary_uv, luvs ? &edge_boundary_check_data : NULL, + &poly_groups, &num_poly_groups, &edge_borders, &num_edge_borders); if (!num_poly_groups) { /* Should never happen... */ @@ -958,6 +1058,11 @@ bool BKE_mesh_calc_islands_loop_poly_uv( MEM_freeN(edge_poly_map); MEM_freeN(edge_poly_mem); + if (luvs) { + MEM_freeN(edge_loop_map); + MEM_freeN(edge_loop_mem); + } + MEM_freeN(poly_indices); MEM_freeN(loop_indices); MEM_freeN(poly_groups); @@ -973,4 +1078,42 @@ bool BKE_mesh_calc_islands_loop_poly_uv( return true; } +/** + * Calculate 'generic' UV islands, i.e. based only on actual geometry data (edge seams), not some UV layers coordinates. + */ +bool BKE_mesh_calc_islands_loop_poly_edgeseam( + MVert *verts, const int totvert, + MEdge *edges, const int totedge, + MPoly *polys, const int totpoly, + MLoop *loops, const int totloop, + MeshIslandStore *r_island_store) +{ + return mesh_calc_islands_loop_poly_uv( + verts, totvert, edges, totedge, polys, totpoly, loops, totloop, NULL, r_island_store); +} + +/** + * Calculate UV islands. + * + * \note If no MLoopUV layer is passed, we only consider edges tagged as seams as UV boundaries. + * This has the advantages of simplicity, and being valid/common to all UV maps. + * However, it means actual UV islands whithout matching UV seams will not be handled correctly... + * If a valid UV layer is passed as \a luvs parameter, UV coordinates are also used to detect islands boundaries. + * + * \note All this could be optimized... + * Not sure it would be worth the more complex code, though, those loops are supposed to be really quick to do... + */ +bool BKE_mesh_calc_islands_loop_poly_uvmap( + MVert *verts, const int totvert, + MEdge *edges, const int totedge, + MPoly *polys, const int totpoly, + MLoop *loops, const int totloop, + const MLoopUV *luvs, + MeshIslandStore *r_island_store) +{ + BLI_assert(luvs != NULL); + return mesh_calc_islands_loop_poly_uv( + verts, totvert, edges, totedge, polys, totpoly, loops, totloop, luvs, r_island_store); +} + /** \} */ |