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:
Diffstat (limited to 'source/blender/blenkernel/intern/mesh_mapping.c')
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c185
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);
+}
+
/** \} */