1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 /** \file
18  * \ingroup bke
19  *
20  * Functions for accessing mesh connectivity data.
21  * eg: polys connected to verts, UV's connected to verts.
22  */
23 
24 #include "MEM_guardedalloc.h"
25 
26 #include "DNA_meshdata_types.h"
27 #include "DNA_vec_types.h"
28 
29 #include "BLI_bitmap.h"
30 #include "BLI_buffer.h"
31 #include "BLI_math.h"
32 #include "BLI_utildefines.h"
33 
34 #include "BKE_customdata.h"
35 #include "BKE_mesh_mapping.h"
36 #include "BLI_memarena.h"
37 
38 #include "BLI_strict_flags.h"
39 
40 /* -------------------------------------------------------------------- */
41 /** \name Mesh Connectivity Mapping
42  * \{ */
43 
44 /* ngon version wip, based on BM_uv_vert_map_create */
45 /* this replaces the non bmesh function (in trunk) which takes MTFace's,
46  * if we ever need it back we could but for now this replaces it because its unused. */
47 
BKE_mesh_uv_vert_map_create(const MPoly * mpoly,const MLoop * mloop,const MLoopUV * mloopuv,unsigned int totpoly,unsigned int totvert,const float limit[2],const bool selected,const bool use_winding)48 UvVertMap *BKE_mesh_uv_vert_map_create(const MPoly *mpoly,
49                                        const MLoop *mloop,
50                                        const MLoopUV *mloopuv,
51                                        unsigned int totpoly,
52                                        unsigned int totvert,
53                                        const float limit[2],
54                                        const bool selected,
55                                        const bool use_winding)
56 {
57   UvVertMap *vmap;
58   UvMapVert *buf;
59   const MPoly *mp;
60   unsigned int a;
61   int i, totuv, nverts;
62 
63   bool *winding = NULL;
64   BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, 32);
65 
66   totuv = 0;
67 
68   /* generate UvMapVert array */
69   mp = mpoly;
70   for (a = 0; a < totpoly; a++, mp++) {
71     if (!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL))) {
72       totuv += mp->totloop;
73     }
74   }
75 
76   if (totuv == 0) {
77     return NULL;
78   }
79 
80   vmap = (UvVertMap *)MEM_callocN(sizeof(*vmap), "UvVertMap");
81   buf = vmap->buf = (UvMapVert *)MEM_callocN(sizeof(*vmap->buf) * (size_t)totuv, "UvMapVert");
82   vmap->vert = (UvMapVert **)MEM_callocN(sizeof(*vmap->vert) * totvert, "UvMapVert*");
83   if (use_winding) {
84     winding = MEM_callocN(sizeof(*winding) * totpoly, "winding");
85   }
86 
87   if (!vmap->vert || !vmap->buf) {
88     BKE_mesh_uv_vert_map_free(vmap);
89     return NULL;
90   }
91 
92   mp = mpoly;
93   for (a = 0; a < totpoly; a++, mp++) {
94     if (!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL))) {
95       float(*tf_uv)[2] = NULL;
96 
97       if (use_winding) {
98         tf_uv = (float(*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, (size_t)mp->totloop);
99       }
100 
101       nverts = mp->totloop;
102 
103       for (i = 0; i < nverts; i++) {
104         buf->loop_of_poly_index = (unsigned short)i;
105         buf->poly_index = a;
106         buf->separate = 0;
107         buf->next = vmap->vert[mloop[mp->loopstart + i].v];
108         vmap->vert[mloop[mp->loopstart + i].v] = buf;
109 
110         if (use_winding) {
111           copy_v2_v2(tf_uv[i], mloopuv[mpoly[a].loopstart + i].uv);
112         }
113 
114         buf++;
115       }
116 
117       if (use_winding) {
118         winding[a] = cross_poly_v2(tf_uv, (unsigned int)nverts) > 0;
119       }
120     }
121   }
122 
123   /* sort individual uvs for each vert */
124   for (a = 0; a < totvert; a++) {
125     UvMapVert *newvlist = NULL, *vlist = vmap->vert[a];
126     UvMapVert *iterv, *v, *lastv, *next;
127     const float *uv, *uv2;
128     float uvdiff[2];
129 
130     while (vlist) {
131       v = vlist;
132       vlist = vlist->next;
133       v->next = newvlist;
134       newvlist = v;
135 
136       uv = mloopuv[mpoly[v->poly_index].loopstart + v->loop_of_poly_index].uv;
137       lastv = NULL;
138       iterv = vlist;
139 
140       while (iterv) {
141         next = iterv->next;
142 
143         uv2 = mloopuv[mpoly[iterv->poly_index].loopstart + iterv->loop_of_poly_index].uv;
144         sub_v2_v2v2(uvdiff, uv2, uv);
145 
146         if (fabsf(uv[0] - uv2[0]) < limit[0] && fabsf(uv[1] - uv2[1]) < limit[1] &&
147             (!use_winding || winding[iterv->poly_index] == winding[v->poly_index])) {
148           if (lastv) {
149             lastv->next = next;
150           }
151           else {
152             vlist = next;
153           }
154           iterv->next = newvlist;
155           newvlist = iterv;
156         }
157         else {
158           lastv = iterv;
159         }
160 
161         iterv = next;
162       }
163 
164       newvlist->separate = 1;
165     }
166 
167     vmap->vert[a] = newvlist;
168   }
169 
170   if (use_winding) {
171     MEM_freeN(winding);
172   }
173 
174   BLI_buffer_free(&tf_uv_buf);
175 
176   return vmap;
177 }
178 
BKE_mesh_uv_vert_map_get_vert(UvVertMap * vmap,unsigned int v)179 UvMapVert *BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v)
180 {
181   return vmap->vert[v];
182 }
183 
BKE_mesh_uv_vert_map_free(UvVertMap * vmap)184 void BKE_mesh_uv_vert_map_free(UvVertMap *vmap)
185 {
186   if (vmap) {
187     if (vmap->vert) {
188       MEM_freeN(vmap->vert);
189     }
190     if (vmap->buf) {
191       MEM_freeN(vmap->buf);
192     }
193     MEM_freeN(vmap);
194   }
195 }
196 
197 /**
198  * Generates a map where the key is the vertex and the value is a list
199  * of polys or loops that use that vertex as a corner. The lists are allocated
200  * from one memory pool.
201  *
202  * Wrapped by #BKE_mesh_vert_poly_map_create & BKE_mesh_vert_loop_map_create
203  */
mesh_vert_poly_or_loop_map_create(MeshElemMap ** r_map,int ** r_mem,const MPoly * mpoly,const MLoop * mloop,int totvert,int totpoly,int totloop,const bool do_loops)204 static void mesh_vert_poly_or_loop_map_create(MeshElemMap **r_map,
205                                               int **r_mem,
206                                               const MPoly *mpoly,
207                                               const MLoop *mloop,
208                                               int totvert,
209                                               int totpoly,
210                                               int totloop,
211                                               const bool do_loops)
212 {
213   MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, __func__);
214   int *indices, *index_iter;
215   int i, j;
216 
217   indices = index_iter = MEM_mallocN(sizeof(int) * (size_t)totloop, __func__);
218 
219   /* Count number of polys for each vertex */
220   for (i = 0; i < totpoly; i++) {
221     const MPoly *p = &mpoly[i];
222 
223     for (j = 0; j < p->totloop; j++) {
224       map[mloop[p->loopstart + j].v].count++;
225     }
226   }
227 
228   /* Assign indices mem */
229   for (i = 0; i < totvert; i++) {
230     map[i].indices = index_iter;
231     index_iter += map[i].count;
232 
233     /* Reset 'count' for use as index in last loop */
234     map[i].count = 0;
235   }
236 
237   /* Find the users */
238   for (i = 0; i < totpoly; i++) {
239     const MPoly *p = &mpoly[i];
240 
241     for (j = 0; j < p->totloop; j++) {
242       unsigned int v = mloop[p->loopstart + j].v;
243 
244       map[v].indices[map[v].count] = do_loops ? p->loopstart + j : i;
245       map[v].count++;
246     }
247   }
248 
249   *r_map = map;
250   *r_mem = indices;
251 }
252 
253 /**
254  * Generates a map where the key is the vertex and the value
255  * is a list of polys that use that vertex as a corner.
256  * The lists are allocated from one memory pool.
257  */
BKE_mesh_vert_poly_map_create(MeshElemMap ** r_map,int ** r_mem,const MPoly * mpoly,const MLoop * mloop,int totvert,int totpoly,int totloop)258 void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
259                                    int **r_mem,
260                                    const MPoly *mpoly,
261                                    const MLoop *mloop,
262                                    int totvert,
263                                    int totpoly,
264                                    int totloop)
265 {
266   mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, false);
267 }
268 
269 /**
270  * Generates a map where the key is the vertex and the value
271  * is a list of loops that use that vertex as a corner.
272  * The lists are allocated from one memory pool.
273  */
BKE_mesh_vert_loop_map_create(MeshElemMap ** r_map,int ** r_mem,const MPoly * mpoly,const MLoop * mloop,int totvert,int totpoly,int totloop)274 void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
275                                    int **r_mem,
276                                    const MPoly *mpoly,
277                                    const MLoop *mloop,
278                                    int totvert,
279                                    int totpoly,
280                                    int totloop)
281 {
282   mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, true);
283 }
284 
285 /**
286  * Generates a map where the key is the edge and the value
287  * is a list of looptris that use that edge.
288  * The lists are allocated from one memory pool.
289  */
BKE_mesh_vert_looptri_map_create(MeshElemMap ** r_map,int ** r_mem,const MVert * UNUSED (mvert),const int totvert,const MLoopTri * mlooptri,const int totlooptri,const MLoop * mloop,const int UNUSED (totloop))290 void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
291                                       int **r_mem,
292                                       const MVert *UNUSED(mvert),
293                                       const int totvert,
294                                       const MLoopTri *mlooptri,
295                                       const int totlooptri,
296                                       const MLoop *mloop,
297                                       const int UNUSED(totloop))
298 {
299   MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, __func__);
300   int *indices = MEM_mallocN(sizeof(int) * (size_t)totlooptri * 3, __func__);
301   int *index_step;
302   const MLoopTri *mlt;
303   int i;
304 
305   /* count face users */
306   for (i = 0, mlt = mlooptri; i < totlooptri; mlt++, i++) {
307     for (int j = 3; j--;) {
308       map[mloop[mlt->tri[j]].v].count++;
309     }
310   }
311 
312   /* create offsets */
313   index_step = indices;
314   for (i = 0; i < totvert; i++) {
315     map[i].indices = index_step;
316     index_step += map[i].count;
317 
318     /* re-count, using this as an index below */
319     map[i].count = 0;
320   }
321 
322   /* assign looptri-edge users */
323   for (i = 0, mlt = mlooptri; i < totlooptri; mlt++, i++) {
324     for (int j = 3; j--;) {
325       MeshElemMap *map_ele = &map[mloop[mlt->tri[j]].v];
326       map_ele->indices[map_ele->count++] = i;
327     }
328   }
329 
330   *r_map = map;
331   *r_mem = indices;
332 }
333 
334 /**
335  * Generates a map where the key is the vertex and the value
336  * is a list of edges that use that vertex as an endpoint.
337  * The lists are allocated from one memory pool.
338  */
BKE_mesh_vert_edge_map_create(MeshElemMap ** r_map,int ** r_mem,const MEdge * medge,int totvert,int totedge)339 void BKE_mesh_vert_edge_map_create(
340     MeshElemMap **r_map, int **r_mem, const MEdge *medge, int totvert, int totedge)
341 {
342   MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, "vert-edge map");
343   int *indices = MEM_mallocN(sizeof(int[2]) * (size_t)totedge, "vert-edge map mem");
344   int *i_pt = indices;
345 
346   int i;
347 
348   /* Count number of edges for each vertex */
349   for (i = 0; i < totedge; i++) {
350     map[medge[i].v1].count++;
351     map[medge[i].v2].count++;
352   }
353 
354   /* Assign indices mem */
355   for (i = 0; i < totvert; i++) {
356     map[i].indices = i_pt;
357     i_pt += map[i].count;
358 
359     /* Reset 'count' for use as index in last loop */
360     map[i].count = 0;
361   }
362 
363   /* Find the users */
364   for (i = 0; i < totedge; i++) {
365     const unsigned int v[2] = {medge[i].v1, medge[i].v2};
366 
367     map[v[0]].indices[map[v[0]].count] = i;
368     map[v[1]].indices[map[v[1]].count] = i;
369 
370     map[v[0]].count++;
371     map[v[1]].count++;
372   }
373 
374   *r_map = map;
375   *r_mem = indices;
376 }
377 
378 /**
379  * A version of #BKE_mesh_vert_edge_map_create that references connected vertices directly
380  * (not their edges).
381  */
BKE_mesh_vert_edge_vert_map_create(MeshElemMap ** r_map,int ** r_mem,const MEdge * medge,int totvert,int totedge)382 void BKE_mesh_vert_edge_vert_map_create(
383     MeshElemMap **r_map, int **r_mem, const MEdge *medge, int totvert, int totedge)
384 {
385   MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, "vert-edge map");
386   int *indices = MEM_mallocN(sizeof(int[2]) * (size_t)totedge, "vert-edge map mem");
387   int *i_pt = indices;
388 
389   int i;
390 
391   /* Count number of edges for each vertex */
392   for (i = 0; i < totedge; i++) {
393     map[medge[i].v1].count++;
394     map[medge[i].v2].count++;
395   }
396 
397   /* Assign indices mem */
398   for (i = 0; i < totvert; i++) {
399     map[i].indices = i_pt;
400     i_pt += map[i].count;
401 
402     /* Reset 'count' for use as index in last loop */
403     map[i].count = 0;
404   }
405 
406   /* Find the users */
407   for (i = 0; i < totedge; i++) {
408     const unsigned int v[2] = {medge[i].v1, medge[i].v2};
409 
410     map[v[0]].indices[map[v[0]].count] = (int)v[1];
411     map[v[1]].indices[map[v[1]].count] = (int)v[0];
412 
413     map[v[0]].count++;
414     map[v[1]].count++;
415   }
416 
417   *r_map = map;
418   *r_mem = indices;
419 }
420 
421 /**
422  * Generates a map where the key is the edge and the value is a list of loops that use that edge.
423  * Loops indices of a same poly are contiguous and in winding order.
424  * The lists are allocated from one memory pool.
425  */
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)426 void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
427                                    int **r_mem,
428                                    const MEdge *UNUSED(medge),
429                                    const int totedge,
430                                    const MPoly *mpoly,
431                                    const int totpoly,
432                                    const MLoop *mloop,
433                                    const int totloop)
434 {
435   MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totedge, "edge-poly map");
436   int *indices = MEM_mallocN(sizeof(int) * (size_t)totloop * 2, "edge-poly map mem");
437   int *index_step;
438   const MPoly *mp;
439   int i;
440 
441   /* count face users */
442   for (i = 0, mp = mpoly; i < totpoly; mp++, i++) {
443     const MLoop *ml;
444     int j = mp->totloop;
445     for (ml = &mloop[mp->loopstart]; j--; ml++) {
446       map[ml->e].count += 2;
447     }
448   }
449 
450   /* create offsets */
451   index_step = indices;
452   for (i = 0; i < totedge; i++) {
453     map[i].indices = index_step;
454     index_step += map[i].count;
455 
456     /* re-count, using this as an index below */
457     map[i].count = 0;
458   }
459 
460   /* assign loop-edge users */
461   for (i = 0, mp = mpoly; i < totpoly; mp++, i++) {
462     const MLoop *ml;
463     MeshElemMap *map_ele;
464     const int max_loop = mp->loopstart + mp->totloop;
465     int j = mp->loopstart;
466     for (ml = &mloop[j]; j < max_loop; j++, ml++) {
467       map_ele = &map[ml->e];
468       map_ele->indices[map_ele->count++] = j;
469       map_ele->indices[map_ele->count++] = j + 1;
470     }
471     /* last edge/loop of poly, must point back to first loop! */
472     map_ele->indices[map_ele->count - 1] = mp->loopstart;
473   }
474 
475   *r_map = map;
476   *r_mem = indices;
477 }
478 
479 /**
480  * Generates a map where the key is the edge and the value
481  * is a list of polygons that use that edge.
482  * The lists are allocated from one memory pool.
483  */
BKE_mesh_edge_poly_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)484 void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
485                                    int **r_mem,
486                                    const MEdge *UNUSED(medge),
487                                    const int totedge,
488                                    const MPoly *mpoly,
489                                    const int totpoly,
490                                    const MLoop *mloop,
491                                    const int totloop)
492 {
493   MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totedge, "edge-poly map");
494   int *indices = MEM_mallocN(sizeof(int) * (size_t)totloop, "edge-poly map mem");
495   int *index_step;
496   const MPoly *mp;
497   int i;
498 
499   /* count face users */
500   for (i = 0, mp = mpoly; i < totpoly; mp++, i++) {
501     const MLoop *ml;
502     int j = mp->totloop;
503     for (ml = &mloop[mp->loopstart]; j--; ml++) {
504       map[ml->e].count++;
505     }
506   }
507 
508   /* create offsets */
509   index_step = indices;
510   for (i = 0; i < totedge; i++) {
511     map[i].indices = index_step;
512     index_step += map[i].count;
513 
514     /* re-count, using this as an index below */
515     map[i].count = 0;
516   }
517 
518   /* assign poly-edge users */
519   for (i = 0, mp = mpoly; i < totpoly; mp++, i++) {
520     const MLoop *ml;
521     int j = mp->totloop;
522     for (ml = &mloop[mp->loopstart]; j--; ml++) {
523       MeshElemMap *map_ele = &map[ml->e];
524       map_ele->indices[map_ele->count++] = i;
525     }
526   }
527 
528   *r_map = map;
529   *r_mem = indices;
530 }
531 
532 /**
533  * This function creates a map so the source-data (vert/edge/loop/poly)
534  * can loop over the destination data (using the destination arrays origindex).
535  *
536  * This has the advantage that it can operate on any data-types.
537  *
538  * \param totsource: The total number of elements the that \a final_origindex points to.
539  * \param totfinal: The size of \a final_origindex
540  * \param final_origindex: The size of the final array.
541  *
542  * \note ``totsource`` could be ``totpoly``,
543  *       ``totfinal`` could be ``tottessface`` and ``final_origindex`` its ORIGINDEX customdata.
544  *       This would allow an MPoly to loop over its tessfaces.
545  */
BKE_mesh_origindex_map_create(MeshElemMap ** r_map,int ** r_mem,const int totsource,const int * final_origindex,const int totfinal)546 void BKE_mesh_origindex_map_create(MeshElemMap **r_map,
547                                    int **r_mem,
548                                    const int totsource,
549                                    const int *final_origindex,
550                                    const int totfinal)
551 {
552   MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totsource, "poly-tessface map");
553   int *indices = MEM_mallocN(sizeof(int) * (size_t)totfinal, "poly-tessface map mem");
554   int *index_step;
555   int i;
556 
557   /* count face users */
558   for (i = 0; i < totfinal; i++) {
559     if (final_origindex[i] != ORIGINDEX_NONE) {
560       BLI_assert(final_origindex[i] < totsource);
561       map[final_origindex[i]].count++;
562     }
563   }
564 
565   /* create offsets */
566   index_step = indices;
567   for (i = 0; i < totsource; i++) {
568     map[i].indices = index_step;
569     index_step += map[i].count;
570 
571     /* re-count, using this as an index below */
572     map[i].count = 0;
573   }
574 
575   /* assign poly-tessface users */
576   for (i = 0; i < totfinal; i++) {
577     if (final_origindex[i] != ORIGINDEX_NONE) {
578       MeshElemMap *map_ele = &map[final_origindex[i]];
579       map_ele->indices[map_ele->count++] = i;
580     }
581   }
582 
583   *r_map = map;
584   *r_mem = indices;
585 }
586 
587 /**
588  * A version of #BKE_mesh_origindex_map_create that takes a looptri array.
589  * Making a poly -> looptri map.
590  */
BKE_mesh_origindex_map_create_looptri(MeshElemMap ** r_map,int ** r_mem,const MPoly * mpoly,const int mpoly_num,const MLoopTri * looptri,const int looptri_num)591 void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
592                                            int **r_mem,
593                                            const MPoly *mpoly,
594                                            const int mpoly_num,
595                                            const MLoopTri *looptri,
596                                            const int looptri_num)
597 {
598   MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)mpoly_num, "poly-tessface map");
599   int *indices = MEM_mallocN(sizeof(int) * (size_t)looptri_num, "poly-tessface map mem");
600   int *index_step;
601   int i;
602 
603   /* create offsets */
604   index_step = indices;
605   for (i = 0; i < mpoly_num; i++) {
606     map[i].indices = index_step;
607     index_step += ME_POLY_TRI_TOT(&mpoly[i]);
608   }
609 
610   /* assign poly-tessface users */
611   for (i = 0; i < looptri_num; i++) {
612     MeshElemMap *map_ele = &map[looptri[i].poly];
613     map_ele->indices[map_ele->count++] = i;
614   }
615 
616   *r_map = map;
617   *r_mem = indices;
618 }
619 
620 /** \} */
621 
622 /* -------------------------------------------------------------------- */
623 /** \name Mesh loops/poly islands.
624  * Used currently for UVs and 'smooth groups'.
625  * \{ */
626 
627 /**
628  * Callback deciding whether the given poly/loop/edge define an island boundary or not.
629  */
630 typedef bool (*MeshRemap_CheckIslandBoundary)(const struct MPoly *mpoly,
631                                               const struct MLoop *mloop,
632                                               const struct MEdge *medge,
633                                               const int nbr_egde_users,
634                                               const struct MPoly *mpoly_array,
635                                               const struct MeshElemMap *edge_poly_map,
636                                               void *user_data);
637 
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,void * edge_boundary_check_data,int ** r_poly_groups,int * r_totgroup,BLI_bitmap ** r_edge_borders,int * r_totedgeborder)638 static void poly_edge_loop_islands_calc(const MEdge *medge,
639                                         const int totedge,
640                                         const MPoly *mpoly,
641                                         const int totpoly,
642                                         const MLoop *mloop,
643                                         const int totloop,
644                                         MeshElemMap *edge_poly_map,
645                                         const bool use_bitflags,
646                                         MeshRemap_CheckIslandBoundary edge_boundary_check,
647                                         void *edge_boundary_check_data,
648                                         int **r_poly_groups,
649                                         int *r_totgroup,
650                                         BLI_bitmap **r_edge_borders,
651                                         int *r_totedgeborder)
652 {
653   int *poly_groups;
654   int *poly_stack;
655 
656   BLI_bitmap *edge_borders = NULL;
657   int num_edgeborders = 0;
658 
659   int poly_prev = 0;
660   const int temp_poly_group_id = 3; /* Placeholder value. */
661 
662   /* Group we could not find any available bit, will be reset to 0 at end. */
663   const int poly_group_id_overflowed = 5;
664 
665   int tot_group = 0;
666   bool group_id_overflow = false;
667 
668   /* map vars */
669   int *edge_poly_mem = NULL;
670 
671   if (totpoly == 0) {
672     *r_totgroup = 0;
673     *r_poly_groups = NULL;
674     if (r_edge_borders) {
675       *r_edge_borders = NULL;
676       *r_totedgeborder = 0;
677     }
678     return;
679   }
680 
681   if (r_edge_borders) {
682     edge_borders = BLI_BITMAP_NEW(totedge, __func__);
683     *r_totedgeborder = 0;
684   }
685 
686   if (!edge_poly_map) {
687     BKE_mesh_edge_poly_map_create(
688         &edge_poly_map, &edge_poly_mem, medge, totedge, mpoly, totpoly, mloop, totloop);
689   }
690 
691   poly_groups = MEM_callocN(sizeof(int) * (size_t)totpoly, __func__);
692   poly_stack = MEM_mallocN(sizeof(int) * (size_t)totpoly, __func__);
693 
694   while (true) {
695     int poly;
696     int bit_poly_group_mask = 0;
697     int poly_group_id;
698     int ps_curr_idx = 0, ps_end_idx = 0; /* stack indices */
699 
700     for (poly = poly_prev; poly < totpoly; poly++) {
701       if (poly_groups[poly] == 0) {
702         break;
703       }
704     }
705 
706     if (poly == totpoly) {
707       /* all done */
708       break;
709     }
710 
711     poly_group_id = use_bitflags ? temp_poly_group_id : ++tot_group;
712 
713     /* start searching from here next time */
714     poly_prev = poly + 1;
715 
716     poly_groups[poly] = poly_group_id;
717     poly_stack[ps_end_idx++] = poly;
718 
719     while (ps_curr_idx != ps_end_idx) {
720       const MPoly *mp;
721       const MLoop *ml;
722       int j;
723 
724       poly = poly_stack[ps_curr_idx++];
725       BLI_assert(poly_groups[poly] == poly_group_id);
726 
727       mp = &mpoly[poly];
728       for (ml = &mloop[mp->loopstart], j = mp->totloop; j--; ml++) {
729         /* loop over poly users */
730         const int me_idx = (int)ml->e;
731         const MEdge *me = &medge[me_idx];
732         const MeshElemMap *map_ele = &edge_poly_map[me_idx];
733         const int *p = map_ele->indices;
734         int i = map_ele->count;
735         if (!edge_boundary_check(mp, ml, me, i, mpoly, map_ele, edge_boundary_check_data)) {
736           for (; i--; p++) {
737             /* if we meet other non initialized its a bug */
738             BLI_assert(ELEM(poly_groups[*p], 0, poly_group_id));
739 
740             if (poly_groups[*p] == 0) {
741               poly_groups[*p] = poly_group_id;
742               poly_stack[ps_end_idx++] = *p;
743             }
744           }
745         }
746         else {
747           if (edge_borders && !BLI_BITMAP_TEST(edge_borders, me_idx)) {
748             BLI_BITMAP_ENABLE(edge_borders, me_idx);
749             num_edgeborders++;
750           }
751           if (use_bitflags) {
752             /* Find contiguous smooth groups already assigned,
753              * these are the values we can't reuse! */
754             for (; i--; p++) {
755               int bit = poly_groups[*p];
756               if (!ELEM(bit, 0, poly_group_id, poly_group_id_overflowed) &&
757                   !(bit_poly_group_mask & bit)) {
758                 bit_poly_group_mask |= bit;
759               }
760             }
761           }
762         }
763       }
764     }
765     /* And now, we have all our poly from current group in poly_stack
766      * (from 0 to (ps_end_idx - 1)),
767      * as well as all smoothgroups bits we can't use in bit_poly_group_mask.
768      */
769     if (use_bitflags) {
770       int i, *p, gid_bit = 0;
771       poly_group_id = 1;
772 
773       /* Find first bit available! */
774       for (; (poly_group_id & bit_poly_group_mask) && (gid_bit < 32); gid_bit++) {
775         poly_group_id <<= 1; /* will 'overflow' on last possible iteration. */
776       }
777       if (UNLIKELY(gid_bit > 31)) {
778         /* All bits used in contiguous smooth groups, we can't do much!
779          * Note: this is *very* unlikely - theoretically, four groups are enough,
780          *       I don't think we can reach this goal with such a simple algo,
781          *       but I don't think either we'll never need all 32 groups!
782          */
783         printf(
784             "Warning, could not find an available id for current smooth group, faces will me "
785             "marked "
786             "as out of any smooth group...\n");
787 
788         /* Can't use 0, will have to set them to this value later. */
789         poly_group_id = poly_group_id_overflowed;
790 
791         group_id_overflow = true;
792       }
793       if (gid_bit > tot_group) {
794         tot_group = gid_bit;
795       }
796       /* And assign the final smooth group id to that poly group! */
797       for (i = ps_end_idx, p = poly_stack; i--; p++) {
798         poly_groups[*p] = poly_group_id;
799       }
800     }
801   }
802 
803   if (use_bitflags) {
804     /* used bits are zero-based. */
805     tot_group++;
806   }
807 
808   if (UNLIKELY(group_id_overflow)) {
809     int i = totpoly, *gid = poly_groups;
810     for (; i--; gid++) {
811       if (*gid == poly_group_id_overflowed) {
812         *gid = 0;
813       }
814     }
815     /* Using 0 as group id adds one more group! */
816     tot_group++;
817   }
818 
819   if (edge_poly_mem) {
820     MEM_freeN(edge_poly_map);
821     MEM_freeN(edge_poly_mem);
822   }
823   MEM_freeN(poly_stack);
824 
825   *r_totgroup = tot_group;
826   *r_poly_groups = poly_groups;
827   if (r_edge_borders) {
828     *r_edge_borders = edge_borders;
829     *r_totedgeborder = num_edgeborders;
830   }
831 }
832 
poly_is_island_boundary_smooth_cb(const MPoly * mp,const MLoop * UNUSED (ml),const MEdge * me,const int nbr_egde_users,const MPoly * mpoly_array,const MeshElemMap * edge_poly_map,void * UNUSED (user_data))833 static bool poly_is_island_boundary_smooth_cb(const MPoly *mp,
834                                               const MLoop *UNUSED(ml),
835                                               const MEdge *me,
836                                               const int nbr_egde_users,
837                                               const MPoly *mpoly_array,
838                                               const MeshElemMap *edge_poly_map,
839                                               void *UNUSED(user_data))
840 {
841   /* Edge is sharp if one of its polys is flat, or edge itself is sharp,
842    * or edge is not used by exactly two polygons. */
843   if ((mp->flag & ME_SMOOTH) && !(me->flag & ME_SHARP) && (nbr_egde_users == 2)) {
844     /* In that case, edge appears to be smooth, but we need to check its other poly too. */
845     const MPoly *mp_other = (mp == &mpoly_array[edge_poly_map->indices[0]]) ?
846                                 &mpoly_array[edge_poly_map->indices[1]] :
847                                 &mpoly_array[edge_poly_map->indices[0]];
848     return (mp_other->flag & ME_SMOOTH) == 0;
849   }
850   return true;
851 }
852 
853 /**
854  * Calculate smooth groups from sharp edges.
855  *
856  * \param r_totgroup: The total number of groups, 1 or more.
857  * \return Polygon aligned array of group index values (bitflags if use_bitflags is true),
858  * starting at 1 (0 being used as 'invalid' flag).
859  * Note it's callers's responsibility to MEM_freeN returned array.
860  */
BKE_mesh_calc_smoothgroups(const MEdge * medge,const int totedge,const MPoly * mpoly,const int totpoly,const MLoop * mloop,const int totloop,int * r_totgroup,const bool use_bitflags)861 int *BKE_mesh_calc_smoothgroups(const MEdge *medge,
862                                 const int totedge,
863                                 const MPoly *mpoly,
864                                 const int totpoly,
865                                 const MLoop *mloop,
866                                 const int totloop,
867                                 int *r_totgroup,
868                                 const bool use_bitflags)
869 {
870   int *poly_groups = NULL;
871 
872   poly_edge_loop_islands_calc(medge,
873                               totedge,
874                               mpoly,
875                               totpoly,
876                               mloop,
877                               totloop,
878                               NULL,
879                               use_bitflags,
880                               poly_is_island_boundary_smooth_cb,
881                               NULL,
882                               &poly_groups,
883                               r_totgroup,
884                               NULL,
885                               NULL);
886 
887   return poly_groups;
888 }
889 
890 #define MISLAND_DEFAULT_BUFSIZE 64
891 
BKE_mesh_loop_islands_init(MeshIslandStore * island_store,const short item_type,const int items_num,const short island_type,const short innercut_type)892 void BKE_mesh_loop_islands_init(MeshIslandStore *island_store,
893                                 const short item_type,
894                                 const int items_num,
895                                 const short island_type,
896                                 const short innercut_type)
897 {
898   MemArena *mem = island_store->mem;
899 
900   if (mem == NULL) {
901     mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
902     island_store->mem = mem;
903   }
904   /* else memarena should be cleared */
905 
906   BLI_assert(
907       ELEM(item_type, MISLAND_TYPE_VERT, MISLAND_TYPE_EDGE, MISLAND_TYPE_POLY, MISLAND_TYPE_LOOP));
908   BLI_assert(ELEM(
909       island_type, MISLAND_TYPE_VERT, MISLAND_TYPE_EDGE, MISLAND_TYPE_POLY, MISLAND_TYPE_LOOP));
910 
911   island_store->item_type = item_type;
912   island_store->items_to_islands_num = items_num;
913   island_store->items_to_islands = BLI_memarena_alloc(
914       mem, sizeof(*island_store->items_to_islands) * (size_t)items_num);
915 
916   island_store->island_type = island_type;
917   island_store->islands_num_alloc = MISLAND_DEFAULT_BUFSIZE;
918   island_store->islands = BLI_memarena_alloc(
919       mem, sizeof(*island_store->islands) * island_store->islands_num_alloc);
920 
921   island_store->innercut_type = innercut_type;
922   island_store->innercuts = BLI_memarena_alloc(
923       mem, sizeof(*island_store->innercuts) * island_store->islands_num_alloc);
924 }
925 
BKE_mesh_loop_islands_clear(MeshIslandStore * island_store)926 void BKE_mesh_loop_islands_clear(MeshIslandStore *island_store)
927 {
928   island_store->item_type = MISLAND_TYPE_NONE;
929   island_store->items_to_islands_num = 0;
930   island_store->items_to_islands = NULL;
931 
932   island_store->island_type = MISLAND_TYPE_NONE;
933   island_store->islands_num = 0;
934   island_store->islands = NULL;
935 
936   island_store->innercut_type = MISLAND_TYPE_NONE;
937   island_store->innercuts = NULL;
938 
939   if (island_store->mem) {
940     BLI_memarena_clear(island_store->mem);
941   }
942 
943   island_store->islands_num_alloc = 0;
944 }
945 
BKE_mesh_loop_islands_free(MeshIslandStore * island_store)946 void BKE_mesh_loop_islands_free(MeshIslandStore *island_store)
947 {
948   if (island_store->mem) {
949     BLI_memarena_free(island_store->mem);
950     island_store->mem = NULL;
951   }
952 }
953 
BKE_mesh_loop_islands_add(MeshIslandStore * island_store,const int item_num,const int * items_indices,const int num_island_items,int * island_item_indices,const int num_innercut_items,int * innercut_item_indices)954 void BKE_mesh_loop_islands_add(MeshIslandStore *island_store,
955                                const int item_num,
956                                const int *items_indices,
957                                const int num_island_items,
958                                int *island_item_indices,
959                                const int num_innercut_items,
960                                int *innercut_item_indices)
961 {
962   MemArena *mem = island_store->mem;
963 
964   MeshElemMap *isld, *innrcut;
965   const int curr_island_idx = island_store->islands_num++;
966   const size_t curr_num_islands = (size_t)island_store->islands_num;
967   int i = item_num;
968 
969   while (i--) {
970     island_store->items_to_islands[items_indices[i]] = curr_island_idx;
971   }
972 
973   if (UNLIKELY(curr_num_islands > island_store->islands_num_alloc)) {
974     MeshElemMap **islds, **innrcuts;
975 
976     island_store->islands_num_alloc *= 2;
977     islds = BLI_memarena_alloc(mem, sizeof(*islds) * island_store->islands_num_alloc);
978     memcpy(islds, island_store->islands, sizeof(*islds) * (curr_num_islands - 1));
979     island_store->islands = islds;
980 
981     innrcuts = BLI_memarena_alloc(mem, sizeof(*innrcuts) * island_store->islands_num_alloc);
982     memcpy(innrcuts, island_store->innercuts, sizeof(*innrcuts) * (curr_num_islands - 1));
983     island_store->innercuts = innrcuts;
984   }
985 
986   island_store->islands[curr_island_idx] = isld = BLI_memarena_alloc(mem, sizeof(*isld));
987   isld->count = num_island_items;
988   isld->indices = BLI_memarena_alloc(mem, sizeof(*isld->indices) * (size_t)num_island_items);
989   memcpy(isld->indices, island_item_indices, sizeof(*isld->indices) * (size_t)num_island_items);
990 
991   island_store->innercuts[curr_island_idx] = innrcut = BLI_memarena_alloc(mem, sizeof(*innrcut));
992   innrcut->count = num_innercut_items;
993   innrcut->indices = BLI_memarena_alloc(mem,
994                                         sizeof(*innrcut->indices) * (size_t)num_innercut_items);
995   memcpy(innrcut->indices,
996          innercut_item_indices,
997          sizeof(*innrcut->indices) * (size_t)num_innercut_items);
998 }
999 
1000 /* TODO: I'm not sure edge seam flag is enough to define UV islands?
1001  *       Maybe we should also consider UVmaps values
1002  *       themselves (i.e. different UV-edges for a same mesh-edge => boundary edge too?).
1003  *       Would make things much more complex though,
1004  *       and each UVMap would then need its own mesh mapping, not sure we want that at all!
1005  */
1006 typedef struct MeshCheckIslandBoundaryUv {
1007   const MLoop *loops;
1008   const MLoopUV *luvs;
1009   const MeshElemMap *edge_loop_map;
1010 } MeshCheckIslandBoundaryUv;
1011 
mesh_check_island_boundary_uv(const MPoly * UNUSED (mp),const MLoop * ml,const MEdge * me,const int UNUSED (nbr_egde_users),const MPoly * UNUSED (mpoly_array),const MeshElemMap * UNUSED (edge_poly_map),void * user_data)1012 static bool mesh_check_island_boundary_uv(const MPoly *UNUSED(mp),
1013                                           const MLoop *ml,
1014                                           const MEdge *me,
1015                                           const int UNUSED(nbr_egde_users),
1016                                           const MPoly *UNUSED(mpoly_array),
1017                                           const MeshElemMap *UNUSED(edge_poly_map),
1018                                           void *user_data)
1019 {
1020   if (user_data) {
1021     const MeshCheckIslandBoundaryUv *data = user_data;
1022     const MLoop *loops = data->loops;
1023     const MLoopUV *luvs = data->luvs;
1024     const MeshElemMap *edge_to_loops = &data->edge_loop_map[ml->e];
1025 
1026     BLI_assert(edge_to_loops->count >= 2 && (edge_to_loops->count % 2) == 0);
1027 
1028     const unsigned int v1 = loops[edge_to_loops->indices[0]].v;
1029     const unsigned int v2 = loops[edge_to_loops->indices[1]].v;
1030     const float *uvco_v1 = luvs[edge_to_loops->indices[0]].uv;
1031     const float *uvco_v2 = luvs[edge_to_loops->indices[1]].uv;
1032     for (int i = 2; i < edge_to_loops->count; i += 2) {
1033       if (loops[edge_to_loops->indices[i]].v == v1) {
1034         if (!equals_v2v2(uvco_v1, luvs[edge_to_loops->indices[i]].uv) ||
1035             !equals_v2v2(uvco_v2, luvs[edge_to_loops->indices[i + 1]].uv)) {
1036           return true;
1037         }
1038       }
1039       else {
1040         BLI_assert(loops[edge_to_loops->indices[i]].v == v2);
1041         UNUSED_VARS_NDEBUG(v2);
1042         if (!equals_v2v2(uvco_v2, luvs[edge_to_loops->indices[i]].uv) ||
1043             !equals_v2v2(uvco_v1, luvs[edge_to_loops->indices[i + 1]].uv)) {
1044           return true;
1045         }
1046       }
1047     }
1048     return false;
1049   }
1050 
1051   /* Edge is UV boundary if tagged as seam. */
1052   return (me->flag & ME_SEAM) != 0;
1053 }
1054 
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)1055 static bool mesh_calc_islands_loop_poly_uv(MVert *UNUSED(verts),
1056                                            const int UNUSED(totvert),
1057                                            MEdge *edges,
1058                                            const int totedge,
1059                                            MPoly *polys,
1060                                            const int totpoly,
1061                                            MLoop *loops,
1062                                            const int totloop,
1063                                            const MLoopUV *luvs,
1064                                            MeshIslandStore *r_island_store)
1065 {
1066   int *poly_groups = NULL;
1067   int num_poly_groups;
1068 
1069   /* map vars */
1070   MeshElemMap *edge_poly_map;
1071   int *edge_poly_mem;
1072 
1073   MeshElemMap *edge_loop_map;
1074   int *edge_loop_mem;
1075 
1076   MeshCheckIslandBoundaryUv edge_boundary_check_data;
1077 
1078   int *poly_indices;
1079   int *loop_indices;
1080   int num_pidx, num_lidx;
1081 
1082   /* Those are used to detect 'inner cuts', i.e. edges that are borders,
1083    * and yet have two or more polys of a same group using them
1084    * (typical case: seam used to unwrap properly a cylinder). */
1085   BLI_bitmap *edge_borders = NULL;
1086   int num_edge_borders = 0;
1087   char *edge_border_count = NULL;
1088   int *edge_innercut_indices = NULL;
1089   int num_einnercuts = 0;
1090 
1091   int grp_idx, p_idx, pl_idx, l_idx;
1092 
1093   BKE_mesh_loop_islands_clear(r_island_store);
1094   BKE_mesh_loop_islands_init(
1095       r_island_store, MISLAND_TYPE_LOOP, totloop, MISLAND_TYPE_POLY, MISLAND_TYPE_EDGE);
1096 
1097   BKE_mesh_edge_poly_map_create(
1098       &edge_poly_map, &edge_poly_mem, edges, totedge, polys, totpoly, loops, totloop);
1099 
1100   if (luvs) {
1101     BKE_mesh_edge_loop_map_create(
1102         &edge_loop_map, &edge_loop_mem, edges, totedge, polys, totpoly, loops, totloop);
1103     edge_boundary_check_data.loops = loops;
1104     edge_boundary_check_data.luvs = luvs;
1105     edge_boundary_check_data.edge_loop_map = edge_loop_map;
1106   }
1107 
1108   poly_edge_loop_islands_calc(edges,
1109                               totedge,
1110                               polys,
1111                               totpoly,
1112                               loops,
1113                               totloop,
1114                               edge_poly_map,
1115                               false,
1116                               mesh_check_island_boundary_uv,
1117                               luvs ? &edge_boundary_check_data : NULL,
1118                               &poly_groups,
1119                               &num_poly_groups,
1120                               &edge_borders,
1121                               &num_edge_borders);
1122 
1123   if (!num_poly_groups) {
1124     /* Should never happen... */
1125     MEM_freeN(edge_poly_map);
1126     MEM_freeN(edge_poly_mem);
1127 
1128     if (edge_borders) {
1129       MEM_freeN(edge_borders);
1130     }
1131     return false;
1132   }
1133 
1134   if (num_edge_borders) {
1135     edge_border_count = MEM_mallocN(sizeof(*edge_border_count) * (size_t)totedge, __func__);
1136     edge_innercut_indices = MEM_mallocN(sizeof(*edge_innercut_indices) * (size_t)num_edge_borders,
1137                                         __func__);
1138   }
1139 
1140   poly_indices = MEM_mallocN(sizeof(*poly_indices) * (size_t)totpoly, __func__);
1141   loop_indices = MEM_mallocN(sizeof(*loop_indices) * (size_t)totloop, __func__);
1142 
1143   /* Note: here we ignore '0' invalid group - this should *never* happen in this case anyway? */
1144   for (grp_idx = 1; grp_idx <= num_poly_groups; grp_idx++) {
1145     num_pidx = num_lidx = 0;
1146     if (num_edge_borders) {
1147       num_einnercuts = 0;
1148       memset(edge_border_count, 0, sizeof(*edge_border_count) * (size_t)totedge);
1149     }
1150 
1151     for (p_idx = 0; p_idx < totpoly; p_idx++) {
1152       MPoly *mp;
1153 
1154       if (poly_groups[p_idx] != grp_idx) {
1155         continue;
1156       }
1157 
1158       mp = &polys[p_idx];
1159       poly_indices[num_pidx++] = p_idx;
1160       for (l_idx = mp->loopstart, pl_idx = 0; pl_idx < mp->totloop; l_idx++, pl_idx++) {
1161         MLoop *ml = &loops[l_idx];
1162         loop_indices[num_lidx++] = l_idx;
1163         if (num_edge_borders && BLI_BITMAP_TEST(edge_borders, ml->e) &&
1164             (edge_border_count[ml->e] < 2)) {
1165           edge_border_count[ml->e]++;
1166           if (edge_border_count[ml->e] == 2) {
1167             edge_innercut_indices[num_einnercuts++] = (int)ml->e;
1168           }
1169         }
1170       }
1171     }
1172 
1173     BKE_mesh_loop_islands_add(r_island_store,
1174                               num_lidx,
1175                               loop_indices,
1176                               num_pidx,
1177                               poly_indices,
1178                               num_einnercuts,
1179                               edge_innercut_indices);
1180   }
1181 
1182   MEM_freeN(edge_poly_map);
1183   MEM_freeN(edge_poly_mem);
1184 
1185   if (luvs) {
1186     MEM_freeN(edge_loop_map);
1187     MEM_freeN(edge_loop_mem);
1188   }
1189 
1190   MEM_freeN(poly_indices);
1191   MEM_freeN(loop_indices);
1192   MEM_freeN(poly_groups);
1193 
1194   if (edge_borders) {
1195     MEM_freeN(edge_borders);
1196   }
1197 
1198   if (num_edge_borders) {
1199     MEM_freeN(edge_border_count);
1200     MEM_freeN(edge_innercut_indices);
1201   }
1202   return true;
1203 }
1204 
1205 /**
1206  * Calculate 'generic' UV islands, i.e. based only on actual geometry data (edge seams),
1207  * not some UV layers coordinates.
1208  */
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)1209 bool BKE_mesh_calc_islands_loop_poly_edgeseam(MVert *verts,
1210                                               const int totvert,
1211                                               MEdge *edges,
1212                                               const int totedge,
1213                                               MPoly *polys,
1214                                               const int totpoly,
1215                                               MLoop *loops,
1216                                               const int totloop,
1217                                               MeshIslandStore *r_island_store)
1218 {
1219   return mesh_calc_islands_loop_poly_uv(
1220       verts, totvert, edges, totedge, polys, totpoly, loops, totloop, NULL, r_island_store);
1221 }
1222 
1223 /**
1224  * Calculate UV islands.
1225  *
1226  * \note If no MLoopUV layer is passed, we only consider edges tagged as seams as UV boundaries.
1227  * This has the advantages of simplicity, and being valid/common to all UV maps.
1228  * However, it means actual UV islands without matching UV seams will not be handled correctly...
1229  * If a valid UV layer is passed as \a luvs parameter,
1230  * UV coordinates are also used to detect islands boundaries.
1231  *
1232  * \note All this could be optimized...
1233  * Not sure it would be worth the more complex code, though,
1234  * those loops are supposed to be really quick to do...
1235  */
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)1236 bool BKE_mesh_calc_islands_loop_poly_uvmap(MVert *verts,
1237                                            const int totvert,
1238                                            MEdge *edges,
1239                                            const int totedge,
1240                                            MPoly *polys,
1241                                            const int totpoly,
1242                                            MLoop *loops,
1243                                            const int totloop,
1244                                            const MLoopUV *luvs,
1245                                            MeshIslandStore *r_island_store)
1246 {
1247   BLI_assert(luvs != NULL);
1248   return mesh_calc_islands_loop_poly_uv(
1249       verts, totvert, edges, totedge, polys, totpoly, loops, totloop, luvs, r_island_store);
1250 }
1251 
1252 /** \} */
1253