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  * The Original Code is Copyright (C) 2007 Blender Foundation.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup bmesh
22  *
23  * Functions for interpolating data across the surface of a mesh.
24  */
25 
26 #include "MEM_guardedalloc.h"
27 
28 #include "DNA_meshdata_types.h"
29 
30 #include "BLI_alloca.h"
31 #include "BLI_linklist.h"
32 #include "BLI_math.h"
33 #include "BLI_memarena.h"
34 #include "BLI_task.h"
35 
36 #include "BKE_customdata.h"
37 #include "BKE_multires.h"
38 
39 #include "bmesh.h"
40 #include "intern/bmesh_private.h"
41 
42 /* edge and vertex share, currently there's no need to have different logic */
bm_data_interp_from_elem(CustomData * data_layer,const BMElem * ele_src_1,const BMElem * ele_src_2,BMElem * ele_dst,const float fac)43 static void bm_data_interp_from_elem(CustomData *data_layer,
44                                      const BMElem *ele_src_1,
45                                      const BMElem *ele_src_2,
46                                      BMElem *ele_dst,
47                                      const float fac)
48 {
49   if (ele_src_1->head.data && ele_src_2->head.data) {
50     /* first see if we can avoid interpolation */
51     if (fac <= 0.0f) {
52       if (ele_src_1 == ele_dst) {
53         /* do nothing */
54       }
55       else {
56         CustomData_bmesh_free_block_data(data_layer, ele_dst->head.data);
57         CustomData_bmesh_copy_data(
58             data_layer, data_layer, ele_src_1->head.data, &ele_dst->head.data);
59       }
60     }
61     else if (fac >= 1.0f) {
62       if (ele_src_2 == ele_dst) {
63         /* do nothing */
64       }
65       else {
66         CustomData_bmesh_free_block_data(data_layer, ele_dst->head.data);
67         CustomData_bmesh_copy_data(
68             data_layer, data_layer, ele_src_2->head.data, &ele_dst->head.data);
69       }
70     }
71     else {
72       const void *src[2];
73       float w[2];
74 
75       src[0] = ele_src_1->head.data;
76       src[1] = ele_src_2->head.data;
77       w[0] = 1.0f - fac;
78       w[1] = fac;
79       CustomData_bmesh_interp(data_layer, src, w, NULL, 2, ele_dst->head.data);
80     }
81   }
82 }
83 
84 /**
85  * \brief Data, Interp From Verts
86  *
87  * Interpolates per-vertex data from two sources to \a v_dst
88  *
89  * \note This is an exact match to #BM_data_interp_from_edges
90  */
BM_data_interp_from_verts(BMesh * bm,const BMVert * v_src_1,const BMVert * v_src_2,BMVert * v_dst,const float fac)91 void BM_data_interp_from_verts(
92     BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, const float fac)
93 {
94   bm_data_interp_from_elem(
95       &bm->vdata, (const BMElem *)v_src_1, (const BMElem *)v_src_2, (BMElem *)v_dst, fac);
96 }
97 
98 /**
99  * \brief Data, Interp From Edges
100  *
101  * Interpolates per-edge data from two sources to \a e_dst.
102  *
103  * \note This is an exact match to #BM_data_interp_from_verts
104  */
BM_data_interp_from_edges(BMesh * bm,const BMEdge * e_src_1,const BMEdge * e_src_2,BMEdge * e_dst,const float fac)105 void BM_data_interp_from_edges(
106     BMesh *bm, const BMEdge *e_src_1, const BMEdge *e_src_2, BMEdge *e_dst, const float fac)
107 {
108   bm_data_interp_from_elem(
109       &bm->edata, (const BMElem *)e_src_1, (const BMElem *)e_src_2, (BMElem *)e_dst, fac);
110 }
111 
112 /**
113  * \brief Data Vert Average
114  *
115  * Sets all the customdata (e.g. vert, loop) associated with a vert
116  * to the average of the face regions surrounding it.
117  */
UNUSED_FUNCTION(BM_Data_Vert_Average)118 static void UNUSED_FUNCTION(BM_Data_Vert_Average)(BMesh *UNUSED(bm), BMFace *UNUSED(f))
119 {
120   // BMIter iter;
121 }
122 
123 /**
124  * \brief Data Face-Vert Edge Interp
125  *
126  * Walks around the faces of \a e and interpolates
127  * the loop data between two sources.
128  */
BM_data_interp_face_vert_edge(BMesh * bm,const BMVert * v_src_1,const BMVert * UNUSED (v_src_2),BMVert * v,BMEdge * e,const float fac)129 void BM_data_interp_face_vert_edge(BMesh *bm,
130                                    const BMVert *v_src_1,
131                                    const BMVert *UNUSED(v_src_2),
132                                    BMVert *v,
133                                    BMEdge *e,
134                                    const float fac)
135 {
136   float w[2];
137   BMLoop *l_v1 = NULL, *l_v = NULL, *l_v2 = NULL;
138   BMLoop *l_iter = NULL;
139 
140   if (!e->l) {
141     return;
142   }
143 
144   w[1] = 1.0f - fac;
145   w[0] = fac;
146 
147   l_iter = e->l;
148   do {
149     if (l_iter->v == v_src_1) {
150       l_v1 = l_iter;
151       l_v = l_v1->next;
152       l_v2 = l_v->next;
153     }
154     else if (l_iter->v == v) {
155       l_v1 = l_iter->next;
156       l_v = l_iter;
157       l_v2 = l_iter->prev;
158     }
159 
160     if (!l_v1 || !l_v2) {
161       return;
162     }
163 
164     const void *src[2];
165     src[0] = l_v1->head.data;
166     src[1] = l_v2->head.data;
167 
168     CustomData_bmesh_interp(&bm->ldata, src, w, NULL, 2, l_v->head.data);
169   } while ((l_iter = l_iter->radial_next) != e->l);
170 }
171 
172 /**
173  * \brief Data Interp From Face
174  *
175  * projects target onto source, and pulls interpolated customdata from
176  * source.
177  *
178  * \note Only handles loop customdata. multires is handled.
179  */
BM_face_interp_from_face_ex(BMesh * bm,BMFace * f_dst,const BMFace * f_src,const bool do_vertex,const void ** blocks_l,const void ** blocks_v,float (* cos_2d)[2],float axis_mat[3][3])180 void BM_face_interp_from_face_ex(BMesh *bm,
181                                  BMFace *f_dst,
182                                  const BMFace *f_src,
183                                  const bool do_vertex,
184                                  const void **blocks_l,
185                                  const void **blocks_v,
186                                  float (*cos_2d)[2],
187                                  float axis_mat[3][3])
188 {
189   BMLoop *l_iter;
190   BMLoop *l_first;
191 
192   float *w = BLI_array_alloca(w, f_src->len);
193   float co[2];
194   int i;
195 
196   if (f_src != f_dst) {
197     BM_elem_attrs_copy(bm, bm, f_src, f_dst);
198   }
199 
200   /* interpolate */
201   i = 0;
202   l_iter = l_first = BM_FACE_FIRST_LOOP(f_dst);
203   do {
204     mul_v2_m3v3(co, axis_mat, l_iter->v->co);
205     interp_weights_poly_v2(w, cos_2d, f_src->len, co);
206     CustomData_bmesh_interp(&bm->ldata, blocks_l, w, NULL, f_src->len, l_iter->head.data);
207     if (do_vertex) {
208       CustomData_bmesh_interp(&bm->vdata, blocks_v, w, NULL, f_src->len, l_iter->v->head.data);
209     }
210   } while ((void)i++, (l_iter = l_iter->next) != l_first);
211 }
212 
BM_face_interp_from_face(BMesh * bm,BMFace * f_dst,const BMFace * f_src,const bool do_vertex)213 void BM_face_interp_from_face(BMesh *bm, BMFace *f_dst, const BMFace *f_src, const bool do_vertex)
214 {
215   BMLoop *l_iter;
216   BMLoop *l_first;
217 
218   const void **blocks_l = BLI_array_alloca(blocks_l, f_src->len);
219   const void **blocks_v = do_vertex ? BLI_array_alloca(blocks_v, f_src->len) : NULL;
220   float(*cos_2d)[2] = BLI_array_alloca(cos_2d, f_src->len);
221   float axis_mat[3][3]; /* use normal to transform into 2d xy coords */
222   int i;
223 
224   /* convert the 3d coords into 2d for projection */
225   BLI_assert(BM_face_is_normal_valid(f_src));
226   axis_dominant_v3_to_m3(axis_mat, f_src->no);
227 
228   i = 0;
229   l_iter = l_first = BM_FACE_FIRST_LOOP(f_src);
230   do {
231     mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co);
232     blocks_l[i] = l_iter->head.data;
233     if (do_vertex) {
234       blocks_v[i] = l_iter->v->head.data;
235     }
236   } while ((void)i++, (l_iter = l_iter->next) != l_first);
237 
238   BM_face_interp_from_face_ex(bm, f_dst, f_src, do_vertex, blocks_l, blocks_v, cos_2d, axis_mat);
239 }
240 
241 /**
242  * \brief Multires Interpolation
243  *
244  * mdisps is a grid of displacements, ordered thus:
245  * <pre>
246  *      v1/center----v4/next -> x
247  *          |           |
248  *          |           |
249  *       v2/prev------v3/cur
250  *          |
251  *          V
252  *          y
253  * </pre>
254  */
compute_mdisp_quad(const BMLoop * l,const float l_f_center[3],float v1[3],float v2[3],float v3[3],float v4[3],float e1[3],float e2[3])255 static int compute_mdisp_quad(const BMLoop *l,
256                               const float l_f_center[3],
257                               float v1[3],
258                               float v2[3],
259                               float v3[3],
260                               float v4[3],
261                               float e1[3],
262                               float e2[3])
263 {
264   float n[3], p[3];
265 
266 #ifndef NDEBUG
267   {
268     float cent[3];
269     /* computer center */
270     BM_face_calc_center_median(l->f, cent);
271     BLI_assert(equals_v3v3(cent, l_f_center));
272   }
273 #endif
274 
275   mid_v3_v3v3(p, l->prev->v->co, l->v->co);
276   mid_v3_v3v3(n, l->next->v->co, l->v->co);
277 
278   copy_v3_v3(v1, l_f_center);
279   copy_v3_v3(v2, p);
280   copy_v3_v3(v3, l->v->co);
281   copy_v3_v3(v4, n);
282 
283   sub_v3_v3v3(e1, v2, v1);
284   sub_v3_v3v3(e2, v3, v4);
285 
286   return 1;
287 }
288 
quad_co(const float v1[3],const float v2[3],const float v3[3],const float v4[3],const float p[3],const float n[3],float r_uv[2])289 static bool quad_co(const float v1[3],
290                     const float v2[3],
291                     const float v3[3],
292                     const float v4[3],
293                     const float p[3],
294                     const float n[3],
295                     float r_uv[2])
296 {
297   float projverts[5][3], n2[3];
298   const float origin[2] = {0.0f, 0.0f};
299   int i;
300 
301   /* project points into 2d along normal */
302   copy_v3_v3(projverts[0], v1);
303   copy_v3_v3(projverts[1], v2);
304   copy_v3_v3(projverts[2], v3);
305   copy_v3_v3(projverts[3], v4);
306   copy_v3_v3(projverts[4], p);
307 
308   normal_quad_v3(n2, projverts[0], projverts[1], projverts[2], projverts[3]);
309 
310   if (dot_v3v3(n, n2) < -FLT_EPSILON) {
311     return false;
312   }
313 
314   /* rotate */
315   poly_rotate_plane(n, projverts, 5);
316 
317   /* subtract origin */
318   for (i = 0; i < 4; i++) {
319     sub_v2_v2(projverts[i], projverts[4]);
320   }
321 
322   if (!isect_point_quad_v2(origin, projverts[0], projverts[1], projverts[2], projverts[3])) {
323     return false;
324   }
325 
326   resolve_quad_uv_v2(r_uv, origin, projverts[0], projverts[3], projverts[2], projverts[1]);
327 
328   return true;
329 }
330 
mdisp_axis_from_quad(const float v1[3],const float v2[3],float UNUSED (v3[3]),const float v4[3],float r_axis_x[3],float r_axis_y[3])331 static void mdisp_axis_from_quad(const float v1[3],
332                                  const float v2[3],
333                                  float UNUSED(v3[3]),
334                                  const float v4[3],
335                                  float r_axis_x[3],
336                                  float r_axis_y[3])
337 {
338   sub_v3_v3v3(r_axis_x, v4, v1);
339   sub_v3_v3v3(r_axis_y, v2, v1);
340 
341   normalize_v3(r_axis_x);
342   normalize_v3(r_axis_y);
343 }
344 
345 /* tl is loop to project onto, l is loop whose internal displacement, co, is being
346  * projected.  x and y are location in loop's mdisps grid of point co. */
mdisp_in_mdispquad(BMLoop * l_src,BMLoop * l_dst,const float l_dst_f_center[3],const float p[3],int res,float r_axis_x[3],float r_axis_y[3],float r_uv[2])347 static bool mdisp_in_mdispquad(BMLoop *l_src,
348                                BMLoop *l_dst,
349                                const float l_dst_f_center[3],
350                                const float p[3],
351                                int res,
352                                float r_axis_x[3],
353                                float r_axis_y[3],
354                                float r_uv[2])
355 {
356   float v1[3], v2[3], c[3], v3[3], v4[3], e1[3], e2[3];
357   float eps = FLT_EPSILON * 4000;
358 
359   if (is_zero_v3(l_src->v->no)) {
360     BM_vert_normal_update_all(l_src->v);
361   }
362   if (is_zero_v3(l_dst->v->no)) {
363     BM_vert_normal_update_all(l_dst->v);
364   }
365 
366   compute_mdisp_quad(l_dst, l_dst_f_center, v1, v2, v3, v4, e1, e2);
367 
368   /* expand quad a bit */
369   mid_v3_v3v3v3v3(c, v1, v2, v3, v4);
370 
371   sub_v3_v3(v1, c);
372   sub_v3_v3(v2, c);
373   sub_v3_v3(v3, c);
374   sub_v3_v3(v4, c);
375   mul_v3_fl(v1, 1.0f + eps);
376   mul_v3_fl(v2, 1.0f + eps);
377   mul_v3_fl(v3, 1.0f + eps);
378   mul_v3_fl(v4, 1.0f + eps);
379   add_v3_v3(v1, c);
380   add_v3_v3(v2, c);
381   add_v3_v3(v3, c);
382   add_v3_v3(v4, c);
383 
384   if (!quad_co(v1, v2, v3, v4, p, l_src->v->no, r_uv)) {
385     return 0;
386   }
387 
388   mul_v2_fl(r_uv, (float)(res - 1));
389 
390   mdisp_axis_from_quad(v1, v2, v3, v4, r_axis_x, r_axis_y);
391 
392   return 1;
393 }
394 
bm_loop_flip_equotion(float mat[2][2],float b[2],const float target_axis_x[3],const float target_axis_y[3],const float coord[3],int i,int j)395 static float bm_loop_flip_equotion(float mat[2][2],
396                                    float b[2],
397                                    const float target_axis_x[3],
398                                    const float target_axis_y[3],
399                                    const float coord[3],
400                                    int i,
401                                    int j)
402 {
403   mat[0][0] = target_axis_x[i];
404   mat[0][1] = target_axis_y[i];
405   mat[1][0] = target_axis_x[j];
406   mat[1][1] = target_axis_y[j];
407   b[0] = coord[i];
408   b[1] = coord[j];
409 
410   return cross_v2v2(mat[0], mat[1]);
411 }
412 
bm_loop_flip_disp(const float source_axis_x[3],const float source_axis_y[3],const float target_axis_x[3],const float target_axis_y[3],float disp[3])413 static void bm_loop_flip_disp(const float source_axis_x[3],
414                               const float source_axis_y[3],
415                               const float target_axis_x[3],
416                               const float target_axis_y[3],
417                               float disp[3])
418 {
419   float vx[3], vy[3], coord[3];
420   float n[3], vec[3];
421   float b[2], mat[2][2], d;
422 
423   mul_v3_v3fl(vx, source_axis_x, disp[0]);
424   mul_v3_v3fl(vy, source_axis_y, disp[1]);
425   add_v3_v3v3(coord, vx, vy);
426 
427   /* project displacement from source grid plane onto target grid plane */
428   cross_v3_v3v3(n, target_axis_x, target_axis_y);
429   project_v3_v3v3(vec, coord, n);
430   sub_v3_v3v3(coord, coord, vec);
431 
432   d = bm_loop_flip_equotion(mat, b, target_axis_x, target_axis_y, coord, 0, 1);
433 
434   if (fabsf(d) < 1e-4f) {
435     d = bm_loop_flip_equotion(mat, b, target_axis_x, target_axis_y, coord, 0, 2);
436     if (fabsf(d) < 1e-4f) {
437       d = bm_loop_flip_equotion(mat, b, target_axis_x, target_axis_y, coord, 1, 2);
438     }
439   }
440 
441   disp[0] = (b[0] * mat[1][1] - mat[0][1] * b[1]) / d;
442   disp[1] = (mat[0][0] * b[1] - b[0] * mat[1][0]) / d;
443 }
444 
445 typedef struct BMLoopInterpMultiresData {
446   BMLoop *l_dst;
447   BMLoop *l_src_first;
448   int cd_loop_mdisp_offset;
449 
450   MDisps *md_dst;
451   const float *f_src_center;
452 
453   float *axis_x, *axis_y;
454   float *v1, *v4;
455   float *e1, *e2;
456 
457   int res;
458   float d;
459 } BMLoopInterpMultiresData;
460 
loop_interp_multires_cb(void * __restrict userdata,const int ix,const TaskParallelTLS * __restrict UNUSED (tls))461 static void loop_interp_multires_cb(void *__restrict userdata,
462                                     const int ix,
463                                     const TaskParallelTLS *__restrict UNUSED(tls))
464 {
465   BMLoopInterpMultiresData *data = userdata;
466 
467   BMLoop *l_first = data->l_src_first;
468   BMLoop *l_dst = data->l_dst;
469   const int cd_loop_mdisp_offset = data->cd_loop_mdisp_offset;
470 
471   MDisps *md_dst = data->md_dst;
472   const float *f_src_center = data->f_src_center;
473 
474   float *axis_x = data->axis_x;
475   float *axis_y = data->axis_y;
476 
477   float *v1 = data->v1;
478   float *v4 = data->v4;
479   float *e1 = data->e1;
480   float *e2 = data->e2;
481 
482   const int res = data->res;
483   const float d = data->d;
484 
485   float x = d * ix, y;
486   int iy;
487   for (y = 0.0f, iy = 0; iy < res; y += d, iy++) {
488     BMLoop *l_iter = l_first;
489     float co1[3], co2[3], co[3];
490 
491     madd_v3_v3v3fl(co1, v1, e1, y);
492     madd_v3_v3v3fl(co2, v4, e2, y);
493     interp_v3_v3v3(co, co1, co2, x);
494 
495     do {
496       MDisps *md_src;
497       float src_axis_x[3], src_axis_y[3];
498       float uv[2];
499 
500       md_src = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_mdisp_offset);
501 
502       if (mdisp_in_mdispquad(l_dst, l_iter, f_src_center, co, res, src_axis_x, src_axis_y, uv)) {
503         old_mdisps_bilinear(md_dst->disps[iy * res + ix], md_src->disps, res, uv[0], uv[1]);
504         bm_loop_flip_disp(src_axis_x, src_axis_y, axis_x, axis_y, md_dst->disps[iy * res + ix]);
505 
506         break;
507       }
508     } while ((l_iter = l_iter->next) != l_first);
509   }
510 }
511 
BM_loop_interp_multires_ex(BMesh * UNUSED (bm),BMLoop * l_dst,const BMFace * f_src,const float f_dst_center[3],const float f_src_center[3],const int cd_loop_mdisp_offset)512 void BM_loop_interp_multires_ex(BMesh *UNUSED(bm),
513                                 BMLoop *l_dst,
514                                 const BMFace *f_src,
515                                 const float f_dst_center[3],
516                                 const float f_src_center[3],
517                                 const int cd_loop_mdisp_offset)
518 {
519   MDisps *md_dst;
520   float v1[3], v2[3], v3[3], v4[3] = {0.0f, 0.0f, 0.0f}, e1[3], e2[3];
521   float axis_x[3], axis_y[3];
522 
523   /* ignore 2-edged faces */
524   if (UNLIKELY(l_dst->f->len < 3)) {
525     return;
526   }
527 
528   md_dst = BM_ELEM_CD_GET_VOID_P(l_dst, cd_loop_mdisp_offset);
529   compute_mdisp_quad(l_dst, f_dst_center, v1, v2, v3, v4, e1, e2);
530 
531   /* if no disps data allocate a new grid, the size of the first grid in f_src. */
532   if (!md_dst->totdisp) {
533     const MDisps *md_src = BM_ELEM_CD_GET_VOID_P(BM_FACE_FIRST_LOOP(f_src), cd_loop_mdisp_offset);
534 
535     md_dst->totdisp = md_src->totdisp;
536     md_dst->level = md_src->level;
537     if (md_dst->totdisp) {
538       md_dst->disps = MEM_callocN(sizeof(float[3]) * md_dst->totdisp, __func__);
539     }
540     else {
541       return;
542     }
543   }
544 
545   mdisp_axis_from_quad(v1, v2, v3, v4, axis_x, axis_y);
546 
547   const int res = (int)sqrt(md_dst->totdisp);
548   BMLoopInterpMultiresData data = {
549       .l_dst = l_dst,
550       .l_src_first = BM_FACE_FIRST_LOOP(f_src),
551       .cd_loop_mdisp_offset = cd_loop_mdisp_offset,
552       .md_dst = md_dst,
553       .f_src_center = f_src_center,
554       .axis_x = axis_x,
555       .axis_y = axis_y,
556       .v1 = v1,
557       .v4 = v4,
558       .e1 = e1,
559       .e2 = e2,
560       .res = res,
561       .d = 1.0f / (float)(res - 1),
562   };
563   TaskParallelSettings settings;
564   BLI_parallel_range_settings_defaults(&settings);
565   settings.use_threading = (res > 5);
566   BLI_task_parallel_range(0, res, &data, loop_interp_multires_cb, &settings);
567 }
568 
569 /**
570  * project the multires grid in target onto f_src's set of multires grids
571  */
BM_loop_interp_multires(BMesh * bm,BMLoop * l_dst,const BMFace * f_src)572 void BM_loop_interp_multires(BMesh *bm, BMLoop *l_dst, const BMFace *f_src)
573 {
574   const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
575 
576   if (cd_loop_mdisp_offset != -1) {
577     float f_dst_center[3];
578     float f_src_center[3];
579 
580     BM_face_calc_center_median(l_dst->f, f_dst_center);
581     BM_face_calc_center_median(f_src, f_src_center);
582 
583     BM_loop_interp_multires_ex(bm, l_dst, f_src, f_dst_center, f_src_center, cd_loop_mdisp_offset);
584   }
585 }
586 
BM_face_interp_multires_ex(BMesh * bm,BMFace * f_dst,const BMFace * f_src,const float f_dst_center[3],const float f_src_center[3],const int cd_loop_mdisp_offset)587 void BM_face_interp_multires_ex(BMesh *bm,
588                                 BMFace *f_dst,
589                                 const BMFace *f_src,
590                                 const float f_dst_center[3],
591                                 const float f_src_center[3],
592                                 const int cd_loop_mdisp_offset)
593 {
594   BMLoop *l_iter, *l_first;
595   l_iter = l_first = BM_FACE_FIRST_LOOP(f_dst);
596   do {
597     BM_loop_interp_multires_ex(
598         bm, l_iter, f_src, f_dst_center, f_src_center, cd_loop_mdisp_offset);
599   } while ((l_iter = l_iter->next) != l_first);
600 }
601 
BM_face_interp_multires(BMesh * bm,BMFace * f_dst,const BMFace * f_src)602 void BM_face_interp_multires(BMesh *bm, BMFace *f_dst, const BMFace *f_src)
603 {
604   const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
605 
606   if (cd_loop_mdisp_offset != -1) {
607     float f_dst_center[3];
608     float f_src_center[3];
609 
610     BM_face_calc_center_median(f_dst, f_dst_center);
611     BM_face_calc_center_median(f_src, f_src_center);
612 
613     BM_face_interp_multires_ex(bm, f_dst, f_src, f_dst_center, f_src_center, cd_loop_mdisp_offset);
614   }
615 }
616 
617 /**
618  * smooths boundaries between multires grids,
619  * including some borders in adjacent faces
620  */
BM_face_multires_bounds_smooth(BMesh * bm,BMFace * f)621 void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
622 {
623   const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
624   BMLoop *l;
625   BMIter liter;
626 
627   if (cd_loop_mdisp_offset == -1) {
628     return;
629   }
630 
631   BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
632     MDisps *mdp = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_mdisp_offset);
633     MDisps *mdl = BM_ELEM_CD_GET_VOID_P(l, cd_loop_mdisp_offset);
634     MDisps *mdn = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_mdisp_offset);
635     float co1[3];
636     int sides;
637     int y;
638 
639     /**
640      * mdisps is a grid of displacements, ordered thus:
641      * <pre>
642      *                    v4/next
643      *                      |
644      *  |      v1/cent-----mid2 ---> x
645      *  |         |         |
646      *  |         |         |
647      * v2/prev---mid1-----v3/cur
648      *            |
649      *            V
650      *            y
651      * </pre>
652      */
653 
654     sides = (int)sqrt(mdp->totdisp);
655     for (y = 0; y < sides; y++) {
656       mid_v3_v3v3(co1, mdn->disps[y * sides], mdl->disps[y]);
657 
658       copy_v3_v3(mdn->disps[y * sides], co1);
659       copy_v3_v3(mdl->disps[y], co1);
660     }
661   }
662 
663   BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
664     MDisps *mdl1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_mdisp_offset);
665     MDisps *mdl2;
666     float co1[3], co2[3], co[3];
667     int sides;
668     int y;
669 
670     /**
671      * mdisps is a grid of displacements, ordered thus:
672      * <pre>
673      *                    v4/next
674      *                      |
675      *  |      v1/cent-----mid2 ---> x
676      *  |         |         |
677      *  |         |         |
678      * v2/prev---mid1-----v3/cur
679      *            |
680      *            V
681      *            y
682      * </pre>
683      */
684 
685     if (l->radial_next == l) {
686       continue;
687     }
688 
689     if (l->radial_next->v == l->v) {
690       mdl2 = BM_ELEM_CD_GET_VOID_P(l->radial_next, cd_loop_mdisp_offset);
691     }
692     else {
693       mdl2 = BM_ELEM_CD_GET_VOID_P(l->radial_next->next, cd_loop_mdisp_offset);
694     }
695 
696     sides = (int)sqrt(mdl1->totdisp);
697     for (y = 0; y < sides; y++) {
698       int a1, a2, o1, o2;
699 
700       if (l->v != l->radial_next->v) {
701         a1 = sides * y + sides - 2;
702         a2 = (sides - 2) * sides + y;
703 
704         o1 = sides * y + sides - 1;
705         o2 = (sides - 1) * sides + y;
706       }
707       else {
708         a1 = sides * y + sides - 2;
709         a2 = sides * y + sides - 2;
710         o1 = sides * y + sides - 1;
711         o2 = sides * y + sides - 1;
712       }
713 
714       /* magic blending numbers, hardcoded! */
715       add_v3_v3v3(co1, mdl1->disps[a1], mdl2->disps[a2]);
716       mul_v3_fl(co1, 0.18);
717 
718       add_v3_v3v3(co2, mdl1->disps[o1], mdl2->disps[o2]);
719       mul_v3_fl(co2, 0.32);
720 
721       add_v3_v3v3(co, co1, co2);
722 
723       copy_v3_v3(mdl1->disps[o1], co);
724       copy_v3_v3(mdl2->disps[o2], co);
725     }
726   }
727 }
728 
729 /**
730  * projects a single loop, target, onto f_src for customdata interpolation. multires is handled.
731  * if do_vertex is true, target's vert data will also get interpolated.
732  */
BM_loop_interp_from_face(BMesh * bm,BMLoop * l_dst,const BMFace * f_src,const bool do_vertex,const bool do_multires)733 void BM_loop_interp_from_face(
734     BMesh *bm, BMLoop *l_dst, const BMFace *f_src, const bool do_vertex, const bool do_multires)
735 {
736   BMLoop *l_iter;
737   BMLoop *l_first;
738   const void **vblocks = do_vertex ? BLI_array_alloca(vblocks, f_src->len) : NULL;
739   const void **blocks = BLI_array_alloca(blocks, f_src->len);
740   float(*cos_2d)[2] = BLI_array_alloca(cos_2d, f_src->len);
741   float *w = BLI_array_alloca(w, f_src->len);
742   float axis_mat[3][3]; /* use normal to transform into 2d xy coords */
743   float co[2];
744   int i;
745 
746   /* Convert the 3d coords into 2d for projection. */
747   float axis_dominant[3];
748   if (!is_zero_v3(f_src->no)) {
749     BLI_assert(BM_face_is_normal_valid(f_src));
750     copy_v3_v3(axis_dominant, f_src->no);
751   }
752   else {
753     /* Rare case in which all the vertices of the face are aligned.
754      * Get a random axis that is orthogonal to the tangent. */
755     float vec[3];
756     BM_face_calc_tangent_auto(f_src, vec);
757     ortho_v3_v3(axis_dominant, vec);
758     normalize_v3(axis_dominant);
759   }
760   axis_dominant_v3_to_m3(axis_mat, axis_dominant);
761 
762   i = 0;
763   l_iter = l_first = BM_FACE_FIRST_LOOP(f_src);
764   do {
765     mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co);
766     blocks[i] = l_iter->head.data;
767 
768     if (do_vertex) {
769       vblocks[i] = l_iter->v->head.data;
770     }
771   } while ((void)i++, (l_iter = l_iter->next) != l_first);
772 
773   mul_v2_m3v3(co, axis_mat, l_dst->v->co);
774 
775   /* interpolate */
776   interp_weights_poly_v2(w, cos_2d, f_src->len, co);
777   CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, f_src->len, l_dst->head.data);
778   if (do_vertex) {
779     CustomData_bmesh_interp(&bm->vdata, vblocks, w, NULL, f_src->len, l_dst->v->head.data);
780   }
781 
782   if (do_multires) {
783     BM_loop_interp_multires(bm, l_dst, f_src);
784   }
785 }
786 
BM_vert_interp_from_face(BMesh * bm,BMVert * v_dst,const BMFace * f_src)787 void BM_vert_interp_from_face(BMesh *bm, BMVert *v_dst, const BMFace *f_src)
788 {
789   BMLoop *l_iter;
790   BMLoop *l_first;
791   const void **blocks = BLI_array_alloca(blocks, f_src->len);
792   float(*cos_2d)[2] = BLI_array_alloca(cos_2d, f_src->len);
793   float *w = BLI_array_alloca(w, f_src->len);
794   float axis_mat[3][3]; /* use normal to transform into 2d xy coords */
795   float co[2];
796   int i;
797 
798   /* convert the 3d coords into 2d for projection */
799   BLI_assert(BM_face_is_normal_valid(f_src));
800   axis_dominant_v3_to_m3(axis_mat, f_src->no);
801 
802   i = 0;
803   l_iter = l_first = BM_FACE_FIRST_LOOP(f_src);
804   do {
805     mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co);
806     blocks[i] = l_iter->v->head.data;
807   } while ((void)i++, (l_iter = l_iter->next) != l_first);
808 
809   mul_v2_m3v3(co, axis_mat, v_dst->co);
810 
811   /* interpolate */
812   interp_weights_poly_v2(w, cos_2d, f_src->len, co);
813   CustomData_bmesh_interp(&bm->vdata, blocks, w, NULL, f_src->len, v_dst->head.data);
814 }
815 
update_data_blocks(BMesh * bm,CustomData * olddata,CustomData * data)816 static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
817 {
818   BMIter iter;
819   BLI_mempool *oldpool = olddata->pool;
820   void *block;
821 
822   if (data == &bm->vdata) {
823     BMVert *eve;
824 
825     CustomData_bmesh_init_pool(data, bm->totvert, BM_VERT);
826 
827     BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
828       block = NULL;
829       CustomData_bmesh_set_default(data, &block);
830       CustomData_bmesh_copy_data(olddata, data, eve->head.data, &block);
831       CustomData_bmesh_free_block(olddata, &eve->head.data);
832       eve->head.data = block;
833     }
834   }
835   else if (data == &bm->edata) {
836     BMEdge *eed;
837 
838     CustomData_bmesh_init_pool(data, bm->totedge, BM_EDGE);
839 
840     BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
841       block = NULL;
842       CustomData_bmesh_set_default(data, &block);
843       CustomData_bmesh_copy_data(olddata, data, eed->head.data, &block);
844       CustomData_bmesh_free_block(olddata, &eed->head.data);
845       eed->head.data = block;
846     }
847   }
848   else if (data == &bm->ldata) {
849     BMIter liter;
850     BMFace *efa;
851     BMLoop *l;
852 
853     CustomData_bmesh_init_pool(data, bm->totloop, BM_LOOP);
854     BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
855       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
856         block = NULL;
857         CustomData_bmesh_set_default(data, &block);
858         CustomData_bmesh_copy_data(olddata, data, l->head.data, &block);
859         CustomData_bmesh_free_block(olddata, &l->head.data);
860         l->head.data = block;
861       }
862     }
863   }
864   else if (data == &bm->pdata) {
865     BMFace *efa;
866 
867     CustomData_bmesh_init_pool(data, bm->totface, BM_FACE);
868 
869     BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
870       block = NULL;
871       CustomData_bmesh_set_default(data, &block);
872       CustomData_bmesh_copy_data(olddata, data, efa->head.data, &block);
873       CustomData_bmesh_free_block(olddata, &efa->head.data);
874       efa->head.data = block;
875     }
876   }
877   else {
878     /* should never reach this! */
879     BLI_assert(0);
880   }
881 
882   if (oldpool) {
883     /* this should never happen but can when dissolve fails - T28960. */
884     BLI_assert(data->pool != oldpool);
885 
886     BLI_mempool_destroy(oldpool);
887   }
888 }
889 
BM_data_layer_add(BMesh * bm,CustomData * data,int type)890 void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
891 {
892   CustomData olddata;
893 
894   olddata = *data;
895   olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers) : NULL;
896 
897   /* the pool is now owned by olddata and must not be shared */
898   data->pool = NULL;
899 
900   CustomData_add_layer(data, type, CD_DEFAULT, NULL, 0);
901 
902   update_data_blocks(bm, &olddata, data);
903   if (olddata.layers) {
904     MEM_freeN(olddata.layers);
905   }
906 }
907 
BM_data_layer_add_named(BMesh * bm,CustomData * data,int type,const char * name)908 void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name)
909 {
910   CustomData olddata;
911 
912   olddata = *data;
913   olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers) : NULL;
914 
915   /* the pool is now owned by olddata and must not be shared */
916   data->pool = NULL;
917 
918   CustomData_add_layer_named(data, type, CD_DEFAULT, NULL, 0, name);
919 
920   update_data_blocks(bm, &olddata, data);
921   if (olddata.layers) {
922     MEM_freeN(olddata.layers);
923   }
924 }
925 
BM_data_layer_free(BMesh * bm,CustomData * data,int type)926 void BM_data_layer_free(BMesh *bm, CustomData *data, int type)
927 {
928   CustomData olddata;
929   bool has_layer;
930 
931   olddata = *data;
932   olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers) : NULL;
933 
934   /* the pool is now owned by olddata and must not be shared */
935   data->pool = NULL;
936 
937   has_layer = CustomData_free_layer_active(data, type, 0);
938   /* assert because its expensive to realloc - better not do if layer isnt present */
939   BLI_assert(has_layer != false);
940   UNUSED_VARS_NDEBUG(has_layer);
941 
942   update_data_blocks(bm, &olddata, data);
943   if (olddata.layers) {
944     MEM_freeN(olddata.layers);
945   }
946 }
947 
BM_data_layer_free_n(BMesh * bm,CustomData * data,int type,int n)948 void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n)
949 {
950   CustomData olddata;
951   bool has_layer;
952 
953   olddata = *data;
954   olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers) : NULL;
955 
956   /* the pool is now owned by olddata and must not be shared */
957   data->pool = NULL;
958 
959   has_layer = CustomData_free_layer(data, type, 0, CustomData_get_layer_index_n(data, type, n));
960   /* assert because its expensive to realloc - better not do if layer isnt present */
961   BLI_assert(has_layer != false);
962   UNUSED_VARS_NDEBUG(has_layer);
963 
964   update_data_blocks(bm, &olddata, data);
965   if (olddata.layers) {
966     MEM_freeN(olddata.layers);
967   }
968 }
969 
BM_data_layer_copy(BMesh * bm,CustomData * data,int type,int src_n,int dst_n)970 void BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int dst_n)
971 {
972   BMIter iter;
973 
974   if (&bm->vdata == data) {
975     BMVert *eve;
976 
977     BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
978       void *ptr = CustomData_bmesh_get_n(data, eve->head.data, type, src_n);
979       CustomData_bmesh_set_n(data, eve->head.data, type, dst_n, ptr);
980     }
981   }
982   else if (&bm->edata == data) {
983     BMEdge *eed;
984 
985     BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
986       void *ptr = CustomData_bmesh_get_n(data, eed->head.data, type, src_n);
987       CustomData_bmesh_set_n(data, eed->head.data, type, dst_n, ptr);
988     }
989   }
990   else if (&bm->pdata == data) {
991     BMFace *efa;
992 
993     BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
994       void *ptr = CustomData_bmesh_get_n(data, efa->head.data, type, src_n);
995       CustomData_bmesh_set_n(data, efa->head.data, type, dst_n, ptr);
996     }
997   }
998   else if (&bm->ldata == data) {
999     BMIter liter;
1000     BMFace *efa;
1001     BMLoop *l;
1002 
1003     BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
1004       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1005         void *ptr = CustomData_bmesh_get_n(data, l->head.data, type, src_n);
1006         CustomData_bmesh_set_n(data, l->head.data, type, dst_n, ptr);
1007       }
1008     }
1009   }
1010   else {
1011     /* should never reach this! */
1012     BLI_assert(0);
1013   }
1014 }
1015 
BM_elem_float_data_get(CustomData * cd,void * element,int type)1016 float BM_elem_float_data_get(CustomData *cd, void *element, int type)
1017 {
1018   const float *f = CustomData_bmesh_get(cd, ((BMHeader *)element)->data, type);
1019   return f ? *f : 0.0f;
1020 }
1021 
BM_elem_float_data_set(CustomData * cd,void * element,int type,const float val)1022 void BM_elem_float_data_set(CustomData *cd, void *element, int type, const float val)
1023 {
1024   float *f = CustomData_bmesh_get(cd, ((BMHeader *)element)->data, type);
1025   if (f) {
1026     *f = val;
1027   }
1028 }
1029 
1030 /** \name Loop interpolation functions: BM_vert_loop_groups_data_layer_***
1031  *
1032  * Handling loop custom-data such as UV's, while keeping contiguous fans is rather tedious.
1033  * Especially when a verts loops can have multiple CustomData layers,
1034  * and each layer can have multiple (different) contiguous fans.
1035  * Said differently, a single vertices loops may span multiple UV islands.
1036  *
1037  * These functions snapshot vertices loops, storing each contiguous fan in its own group.
1038  * The caller can manipulate the loops, then re-combine the CustomData values.
1039  *
1040  * While these functions don't explicitly handle multiple layers at once,
1041  * the caller can simply store its own list.
1042  *
1043  * \note Currently they are averaged back together (weighted by loop angle)
1044  * but we could copy add other methods to re-combine CustomData-Loop-Fans.
1045  *
1046  * \{ */
1047 
1048 struct LoopWalkCtx {
1049   /* same for all groups */
1050   int type;
1051   int cd_layer_offset;
1052   const float *loop_weights;
1053   MemArena *arena;
1054 
1055   /* --- Per loop fan vars --- */
1056 
1057   /* reference for this contiguous fan */
1058   const void *data_ref;
1059   int data_len;
1060 
1061   /* accumulate 'LoopGroupCD.weight' to make unit length */
1062   float weight_accum;
1063 
1064   /* both arrays the size of the 'BM_vert_face_count(v)'
1065    * each contiguous fan gets a slide of these arrays */
1066   void **data_array;
1067   int *data_index_array;
1068   float *weight_array;
1069 };
1070 
1071 /* Store vars to pass into 'CustomData_bmesh_interp' */
1072 struct LoopGroupCD {
1073   /* direct customdata pointer array */
1074   void **data;
1075   /* weights (aligned with 'data') */
1076   float *data_weights;
1077   /* index-in-face */
1078   int *data_index;
1079   /* number of loops in the fan */
1080   int data_len;
1081 };
1082 
bm_loop_walk_add(struct LoopWalkCtx * lwc,BMLoop * l)1083 static void bm_loop_walk_add(struct LoopWalkCtx *lwc, BMLoop *l)
1084 {
1085   const int i = BM_elem_index_get(l);
1086   const float w = lwc->loop_weights[i];
1087   BM_elem_flag_disable(l, BM_ELEM_INTERNAL_TAG);
1088   lwc->data_array[lwc->data_len] = BM_ELEM_CD_GET_VOID_P(l, lwc->cd_layer_offset);
1089   lwc->data_index_array[lwc->data_len] = i;
1090   lwc->weight_array[lwc->data_len] = w;
1091   lwc->weight_accum += w;
1092 
1093   lwc->data_len += 1;
1094 }
1095 
1096 /**
1097  * called recursively, keep stack-usage minimal.
1098  *
1099  * \note called for fan matching so we're pretty much safe not to break the stack
1100  */
bm_loop_walk_data(struct LoopWalkCtx * lwc,BMLoop * l_walk)1101 static void bm_loop_walk_data(struct LoopWalkCtx *lwc, BMLoop *l_walk)
1102 {
1103   int i;
1104 
1105   BLI_assert(CustomData_data_equals(
1106       lwc->type, lwc->data_ref, BM_ELEM_CD_GET_VOID_P(l_walk, lwc->cd_layer_offset)));
1107   BLI_assert(BM_elem_flag_test(l_walk, BM_ELEM_INTERNAL_TAG));
1108 
1109   bm_loop_walk_add(lwc, l_walk);
1110 
1111   /* recurse around this loop-fan (in both directions) */
1112   for (i = 0; i < 2; i++) {
1113     BMLoop *l_other = ((i == 0) ? l_walk : l_walk->prev)->radial_next;
1114     if (l_other->radial_next != l_other) {
1115       if (l_other->v != l_walk->v) {
1116         l_other = l_other->next;
1117       }
1118       BLI_assert(l_other->v == l_walk->v);
1119       if (BM_elem_flag_test(l_other, BM_ELEM_INTERNAL_TAG)) {
1120         if (CustomData_data_equals(
1121                 lwc->type, lwc->data_ref, BM_ELEM_CD_GET_VOID_P(l_other, lwc->cd_layer_offset))) {
1122           bm_loop_walk_data(lwc, l_other);
1123         }
1124       }
1125     }
1126   }
1127 }
1128 
BM_vert_loop_groups_data_layer_create(BMesh * bm,BMVert * v,const int layer_n,const float * loop_weights,MemArena * arena)1129 LinkNode *BM_vert_loop_groups_data_layer_create(
1130     BMesh *bm, BMVert *v, const int layer_n, const float *loop_weights, MemArena *arena)
1131 {
1132   struct LoopWalkCtx lwc;
1133   LinkNode *groups = NULL;
1134   BMLoop *l;
1135   BMIter liter;
1136   int loop_num;
1137 
1138   lwc.type = bm->ldata.layers[layer_n].type;
1139   lwc.cd_layer_offset = bm->ldata.layers[layer_n].offset;
1140   lwc.loop_weights = loop_weights;
1141   lwc.arena = arena;
1142 
1143   /* Enable 'BM_ELEM_INTERNAL_TAG', leaving the flag clean on completion. */
1144   loop_num = 0;
1145   BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
1146     BM_elem_flag_enable(l, BM_ELEM_INTERNAL_TAG);
1147     BM_elem_index_set(l, loop_num); /* set_dirty! */
1148     loop_num++;
1149   }
1150   bm->elem_index_dirty |= BM_LOOP;
1151 
1152   lwc.data_len = 0;
1153   lwc.data_array = BLI_memarena_alloc(lwc.arena, sizeof(void *) * loop_num);
1154   lwc.data_index_array = BLI_memarena_alloc(lwc.arena, sizeof(int) * loop_num);
1155   lwc.weight_array = BLI_memarena_alloc(lwc.arena, sizeof(float) * loop_num);
1156 
1157   BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
1158     if (BM_elem_flag_test(l, BM_ELEM_INTERNAL_TAG)) {
1159       struct LoopGroupCD *lf = BLI_memarena_alloc(lwc.arena, sizeof(*lf));
1160       int len_prev = lwc.data_len;
1161 
1162       lwc.data_ref = BM_ELEM_CD_GET_VOID_P(l, lwc.cd_layer_offset);
1163 
1164       /* assign len-last */
1165       lf->data = &lwc.data_array[lwc.data_len];
1166       lf->data_index = &lwc.data_index_array[lwc.data_len];
1167       lf->data_weights = &lwc.weight_array[lwc.data_len];
1168       lwc.weight_accum = 0.0f;
1169 
1170       /* new group */
1171       bm_loop_walk_data(&lwc, l);
1172       lf->data_len = lwc.data_len - len_prev;
1173 
1174       if (LIKELY(lwc.weight_accum != 0.0f)) {
1175         mul_vn_fl(lf->data_weights, lf->data_len, 1.0f / lwc.weight_accum);
1176       }
1177       else {
1178         copy_vn_fl(lf->data_weights, lf->data_len, 1.0f / (float)lf->data_len);
1179       }
1180 
1181       BLI_linklist_prepend_arena(&groups, lf, lwc.arena);
1182     }
1183   }
1184 
1185   BLI_assert(lwc.data_len == loop_num);
1186 
1187   return groups;
1188 }
1189 
bm_vert_loop_groups_data_layer_merge__single(BMesh * bm,void * lf_p,int layer_n,void * data_tmp)1190 static void bm_vert_loop_groups_data_layer_merge__single(BMesh *bm,
1191                                                          void *lf_p,
1192                                                          int layer_n,
1193                                                          void *data_tmp)
1194 {
1195   struct LoopGroupCD *lf = lf_p;
1196   const int type = bm->ldata.layers[layer_n].type;
1197   int i;
1198   const float *data_weights;
1199 
1200   data_weights = lf->data_weights;
1201 
1202   CustomData_bmesh_interp_n(
1203       &bm->ldata, (const void **)lf->data, data_weights, NULL, lf->data_len, data_tmp, layer_n);
1204 
1205   for (i = 0; i < lf->data_len; i++) {
1206     CustomData_copy_elements(type, data_tmp, lf->data[i], 1);
1207   }
1208 }
1209 
bm_vert_loop_groups_data_layer_merge_weights__single(BMesh * bm,void * lf_p,const int layer_n,void * data_tmp,const float * loop_weights)1210 static void bm_vert_loop_groups_data_layer_merge_weights__single(
1211     BMesh *bm, void *lf_p, const int layer_n, void *data_tmp, const float *loop_weights)
1212 {
1213   struct LoopGroupCD *lf = lf_p;
1214   const int type = bm->ldata.layers[layer_n].type;
1215   int i;
1216   const float *data_weights;
1217 
1218   /* re-weight */
1219   float *temp_weights = BLI_array_alloca(temp_weights, lf->data_len);
1220   float weight_accum = 0.0f;
1221 
1222   for (i = 0; i < lf->data_len; i++) {
1223     float w = loop_weights[lf->data_index[i]] * lf->data_weights[i];
1224     temp_weights[i] = w;
1225     weight_accum += w;
1226   }
1227 
1228   if (LIKELY(weight_accum != 0.0f)) {
1229     mul_vn_fl(temp_weights, lf->data_len, 1.0f / weight_accum);
1230     data_weights = temp_weights;
1231   }
1232   else {
1233     data_weights = lf->data_weights;
1234   }
1235 
1236   CustomData_bmesh_interp_n(
1237       &bm->ldata, (const void **)lf->data, data_weights, NULL, lf->data_len, data_tmp, layer_n);
1238 
1239   for (i = 0; i < lf->data_len; i++) {
1240     CustomData_copy_elements(type, data_tmp, lf->data[i], 1);
1241   }
1242 }
1243 
1244 /**
1245  * Take existing custom data and merge each fan's data.
1246  */
BM_vert_loop_groups_data_layer_merge(BMesh * bm,LinkNode * groups,const int layer_n)1247 void BM_vert_loop_groups_data_layer_merge(BMesh *bm, LinkNode *groups, const int layer_n)
1248 {
1249   const int type = bm->ldata.layers[layer_n].type;
1250   const int size = CustomData_sizeof(type);
1251   void *data_tmp = alloca(size);
1252 
1253   do {
1254     bm_vert_loop_groups_data_layer_merge__single(bm, groups->link, layer_n, data_tmp);
1255   } while ((groups = groups->next));
1256 }
1257 
1258 /**
1259  * A version of #BM_vert_loop_groups_data_layer_merge
1260  * that takes an array of loop-weights (aligned with #BM_LOOPS_OF_VERT iterator)
1261  */
BM_vert_loop_groups_data_layer_merge_weights(BMesh * bm,LinkNode * groups,const int layer_n,const float * loop_weights)1262 void BM_vert_loop_groups_data_layer_merge_weights(BMesh *bm,
1263                                                   LinkNode *groups,
1264                                                   const int layer_n,
1265                                                   const float *loop_weights)
1266 {
1267   const int type = bm->ldata.layers[layer_n].type;
1268   const int size = CustomData_sizeof(type);
1269   void *data_tmp = alloca(size);
1270 
1271   do {
1272     bm_vert_loop_groups_data_layer_merge_weights__single(
1273         bm, groups->link, layer_n, data_tmp, loop_weights);
1274   } while ((groups = groups->next));
1275 }
1276 
1277 /** \} */
1278