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