2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2007 Blender Foundation.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): Geoffrey Bantle.
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/bmesh/intern/bmesh_interp.c
31 * Functions for interpolating data across the surface of a mesh.
34 #include "MEM_guardedalloc.h"
36 #include "DNA_mesh_types.h"
37 #include "DNA_meshdata_types.h"
39 #include "BKE_customdata.h"
40 #include "BKE_utildefines.h"
41 #include "BKE_multires.h"
43 #include "BLI_array.h"
45 #include "BLI_cellalloc.h"
48 #include "bmesh_private.h"
51 * bmesh_data_interp_from_verts
53 * Interpolates per-vertex data from two sources to a target.
58 void BM_Data_Interp_From_Verts(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, float fac)
62 if (v1->head.data && v2->head.data) {
63 src[0]= v1->head.data;
64 src[1]= v2->head.data;
67 CustomData_bmesh_interp(&bm->vdata, src, w, NULL, 2, v->head.data);
74 Sets all the customdata (e.g. vert, loop) associated with a vert
75 to the average of the face regions surrounding it.
79 static void UNUSED_FUNCTION(BM_Data_Vert_Average)(BMesh *UNUSED(bm), BMFace *UNUSED(f))
85 * bmesh_data_facevert_edgeinterp
87 * Walks around the faces of an edge and interpolates the per-face-edge
88 * data between two sources to a target.
94 void BM_Data_Facevert_Edgeinterp(BMesh *bm, BMVert *v1, BMVert *UNUSED(v2), BMVert *v, BMEdge *e1, float fac)
98 BMLoop *l=NULL, *v1loop = NULL, *vloop = NULL, *v2loop = NULL;
108 vloop = v1loop->next;
109 v2loop = vloop->next;
117 if (!v1loop || !v2loop)
120 src[0] = v1loop->head.data;
121 src[1] = v2loop->head.data;
123 CustomData_bmesh_interp(&bm->ldata, src,w, NULL, 2, vloop->head.data);
128 void BM_loops_to_corners(BMesh *bm, Mesh *me, int findex,
129 BMFace *f, int numTex, int numCol)
140 for(i=0; i < numTex; i++) {
141 texface = CustomData_get_n(&me->fdata, CD_MTFACE, findex, i);
142 texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i);
144 texface->tpage = texpoly->tpage;
145 texface->flag = texpoly->flag;
146 texface->transp = texpoly->transp;
147 texface->mode = texpoly->mode;
148 texface->tile = texpoly->tile;
149 texface->unwrap = texpoly->unwrap;
152 BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
153 mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
154 texface->uv[j][0] = mloopuv->uv[0];
155 texface->uv[j][1] = mloopuv->uv[1];
162 for(i=0; i < numCol; i++) {
163 mcol = CustomData_get_n(&me->fdata, CD_MCOL, findex, i);
166 BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
167 mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i);
168 mcol[j].r = mloopcol->r;
169 mcol[j].g = mloopcol->g;
170 mcol[j].b = mloopcol->b;
171 mcol[j].a = mloopcol->a;
179 * BM_data_interp_from_face
181 * projects target onto source, and pulls interpolated customdata from
187 void BM_face_interp_from_face(BMesh *bm, BMFace *target, BMFace *source)
193 float (*cos)[3]=NULL, *w=NULL;
194 BLI_array_fixedstack_declare(cos, BM_NGON_STACK_SIZE, source->len, __func__);
195 BLI_array_fixedstack_declare(w, BM_NGON_STACK_SIZE, source->len, __func__);
196 BLI_array_fixedstack_declare(blocks, BM_NGON_STACK_SIZE, source->len, __func__);
199 BM_Copy_Attributes(bm, bm, source, target);
202 l2 = l_first = bm_firstfaceloop(source);
204 copy_v3_v3(cos[i], l2->v->co);
205 blocks[i] = l2->head.data;
207 } while ((l2 = l2->next) != l_first);
210 l1 = l_first = bm_firstfaceloop(target);
212 interp_weights_poly_v3(w, cos, source->len, l1->v->co);
213 CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, source->len, l1->head.data);
215 } while ((l1 = l1->next) != l_first);
217 BLI_array_fixedstack_free(cos);
218 BLI_array_fixedstack_free(w);
219 BLI_array_fixedstack_free(blocks);
222 /****some math stuff for dealing with doubles, put here to
223 avoid merge errors - joeedh ****/
225 #define VECMUL(a, b) (((a)[0] = (a)[0] * (b)), ((a)[1] = (a)[1] * (b)), ((a)[2] = (a)[2] * (b)))
226 #define VECADD2(a, b) (((a)[0] = (a)[0] + (b)[0]), ((a)[1] = (a)[1] + (b)[1]), ((a)[2] = (a)[2] + (b)[2]))
227 #define VECSUB2(a, b) (((a)[0] = (a)[0] - (b)[0]), ((a)[1] = (a)[1] - (b)[1]), ((a)[2] = (a)[2] - (b)[2]))
229 /* find closest point to p on line through l1,l2 and return lambda,
230 * where (0 <= lambda <= 1) when cp is in the line segement l1,l2
232 static double closest_to_line_v3_d(double cp[3], const double p[3], const double l1[3], const double l2[3])
234 double h[3],u[3],lambda;
237 lambda =INPR(u,h)/INPR(u,u);
238 cp[0] = l1[0] + u[0] * lambda;
239 cp[1] = l1[1] + u[1] * lambda;
240 cp[2] = l1[2] + u[2] * lambda;
244 /* point closest to v1 on line v2-v3 in 3D */
245 static void UNUSED_FUNCTION(closest_to_line_segment_v3_d)(double *closest, double v1[3], double v2[3], double v3[3])
247 double lambda, cp[3];
249 lambda= closest_to_line_v3_d(cp,v1, v2, v3);
252 VECCOPY(closest, v2);
253 } else if(lambda >= 1.0) {
254 VECCOPY(closest, v3);
256 VECCOPY(closest, cp);
260 static double UNUSED_FUNCTION(len_v3_d)(const double a[3])
262 return sqrt(INPR(a, a));
265 static double UNUSED_FUNCTION(len_v3v3_d)(const double a[3], const double b[3])
270 return sqrt(INPR(d, d));
273 static void cent_quad_v3_d(double *cent, double *v1, double *v2, double *v3, double *v4)
275 cent[0]= 0.25*(v1[0]+v2[0]+v3[0]+v4[0]);
276 cent[1]= 0.25*(v1[1]+v2[1]+v3[1]+v4[1]);
277 cent[2]= 0.25*(v1[2]+v2[2]+v3[2]+v4[2]);
280 static void UNUSED_FUNCTION(cent_tri_v3_d)(double *cent, double *v1, double *v2, double *v3)
282 cent[0]= 0.33333*(v1[0]+v2[0]+v3[0]);
283 cent[1]= 0.33333*(v1[1]+v2[1]+v3[1]);
284 cent[2]= 0.33333*(v1[2]+v2[2]+v3[2]);
287 static void UNUSED_FUNCTION(cross_v3_v3v3_d)(double r[3], const double a[3], const double b[3])
289 r[0]= a[1]*b[2] - a[2]*b[1];
290 r[1]= a[2]*b[0] - a[0]*b[2];
291 r[2]= a[0]*b[1] - a[1]*b[0];
294 /* distance v1 to line-piece v2-v3 */
295 static double UNUSED_FUNCTION(dist_to_line_segment_v2_d)(double v1[3], double v2[3], double v3[3])
297 double labda, rc[2], pt[2], len;
301 len= rc[0]*rc[0]+ rc[1]*rc[1];
305 return sqrt(rc[0]*rc[0]+ rc[1]*rc[1]);
308 labda= (rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]))/len;
313 else if(labda>=1.0) {
318 pt[0]= labda*rc[0]+v2[0];
319 pt[1]= labda*rc[1]+v2[1];
324 return sqrt(rc[0]*rc[0]+ rc[1]*rc[1]);
328 MINLINE double line_point_side_v2_d(const double *l1, const double *l2, const double *pt)
330 return ((l1[0]-pt[0]) * (l2[1]-pt[1])) -
331 ((l2[0]-pt[0]) * (l1[1]-pt[1]));
334 /* point in quad - only convex quads */
335 static int isect_point_quad_v2_d(double pt[2], double v1[2], double v2[2], double v3[2], double v4[2])
337 if (line_point_side_v2_d(v1,v2,pt)>=0.0) {
338 if (line_point_side_v2_d(v2,v3,pt)>=0.0) {
339 if (line_point_side_v2_d(v3,v4,pt)>=0.0) {
340 if (line_point_side_v2_d(v4,v1,pt)>=0.0) {
346 if (! (line_point_side_v2_d(v2,v3,pt)>=0.0)) {
347 if (! (line_point_side_v2_d(v3,v4,pt)>=0.0)) {
348 if (! (line_point_side_v2_d(v4,v1,pt)>=0.0)) {
358 /***** multires interpolation*****
360 mdisps is a grid of displacements, ordered thus:
362 v1/center----v4/next -> x
371 static int compute_mdisp_quad(BMLoop *l, double v1[3], double v2[3], double v3[3], double v4[3], double e1[3], double e2[3])
373 double cent[3] = {0.0, 0.0, 0.0}, n[3], p[3];
377 l2 = bm_firstfaceloop(l->f);
379 cent[0] += (double)l2->v->co[0];
380 cent[1] += (double)l2->v->co[1];
381 cent[2] += (double)l2->v->co[2];
383 } while (l2 != bm_firstfaceloop(l->f));
385 VECMUL(cent, (1.0/(double)l->f->len));
387 VECADD(p, l->prev->v->co, l->v->co);
389 VECADD(n, l->next->v->co, l->v->co);
394 VECCOPY(v3, l->v->co);
403 /*funnily enough, I think this is identical to face_to_crn_interp, heh*/
404 static double quad_coord(double aa[3], double bb[3], double cc[3], double dd[3], int a1, int a2)
408 x = aa[a1]*cc[a2]-cc[a1]*aa[a2];
409 y = aa[a1]*dd[a2]+bb[a1]*cc[a2]-cc[a1]*bb[a2]-dd[a1]*aa[a2];
410 z = bb[a1]*dd[a2]-dd[a1]*bb[a2];
412 if (fabs(2*(x-y+z)) > DBL_EPSILON*10.0) {
415 f1 = (sqrt(y*y-4.0*x*z) - y + 2.0*z) / (2.0*(x-y+z));
416 f2 = (-sqrt(y*y-4.0*x*z) - y + 2.0*z) / (2.0*(x-y+z));
421 CLAMP(f1, 0.0, 1.0+DBL_EPSILON);
424 CLAMP(f1, 0.0, 1.0+DBL_EPSILON);
426 if (isnan(f1) || f1 > 1.0 || f1 < 0.0) {
429 for (i=0; i<2; i++) {
430 if (fabsf(aa[i]) < FLT_EPSILON*100)
431 return aa[(i+1)%2] / fabs(bb[(i+1)%2] - aa[(i+1)%2]);
432 if (fabsf(cc[i]) < FLT_EPSILON*100)
433 return cc[(i+1)%2] / fabs(dd[(i+1)%2] - cc[(i+1)%2]);
441 static int quad_co(double *x, double *y, double v1[3], double v2[3], double v3[3], double v4[3], double p[3], float n[3])
443 float projverts[5][3], n2[3];
444 double dprojverts[4][3], origin[3]={0.0f, 0.0f, 0.0f};
447 /*project points into 2d along normal*/
448 VECCOPY(projverts[0], v1);
449 VECCOPY(projverts[1], v2);
450 VECCOPY(projverts[2], v3);
451 VECCOPY(projverts[3], v4);
452 VECCOPY(projverts[4], p);
454 normal_quad_v3(n2, projverts[0], projverts[1], projverts[2], projverts[3]);
456 if (INPR(n, n2) < -FLT_EPSILON)
460 poly_rotate_plane(n, projverts, 5);
463 for (i=0; i<5; i++) projverts[i][2] = 0.0f;
466 for (i=0; i<4; i++) {
467 VECSUB2(projverts[i], projverts[4]);
470 VECCOPY(dprojverts[0], projverts[0]);
471 VECCOPY(dprojverts[1], projverts[1]);
472 VECCOPY(dprojverts[2], projverts[2]);
473 VECCOPY(dprojverts[3], projverts[3]);
475 if (!isect_point_quad_v2_d(origin, dprojverts[0], dprojverts[1], dprojverts[2], dprojverts[3]))
478 *y = quad_coord(dprojverts[1], dprojverts[0], dprojverts[2], dprojverts[3], 0, 1);
479 *x = quad_coord(dprojverts[2], dprojverts[1], dprojverts[3], dprojverts[0], 0, 1);
485 /*tl is loop to project onto, l is loop whose internal displacement, co, is being
486 projected. x and y are location in loop's mdisps grid of point co.*/
487 static int mdisp_in_mdispquad(BMesh *bm, BMLoop *l, BMLoop *tl, double p[3], double *x, double *y, int res)
489 double v1[3], v2[3], c[3], v3[3], v4[3], e1[3], e2[3];
490 double eps = FLT_EPSILON*4000;
492 if (len_v3(l->v->no) == 0.0f)
493 BM_Vert_UpdateAllNormals(bm, l->v);
494 if (len_v3(tl->v->no) == 0.0f)
495 BM_Vert_UpdateAllNormals(bm, tl->v);
497 compute_mdisp_quad(tl, v1, v2, v3, v4, e1, e2);
499 /*expand quad a bit*/
500 cent_quad_v3_d(c, v1, v2, v3, v4);
502 VECSUB2(v1, c); VECSUB2(v2, c);
503 VECSUB2(v3, c); VECSUB2(v4, c);
504 VECMUL(v1, 1.0+eps); VECMUL(v2, 1.0+eps);
505 VECMUL(v3, 1.0+eps); VECMUL(v4, 1.0+eps);
506 VECADD2(v1, c); VECADD2(v2, c);
507 VECADD2(v3, c); VECADD2(v4, c);
509 if (!quad_co(x, y, v1, v2, v3, v4, p, l->v->no))
518 static void bmesh_loop_interp_mdisps(BMesh *bm, BMLoop *target, BMFace *source)
522 double x, y, d, v1[3], v2[3], v3[3], v4[3] = {0.0f, 0.0f, 0.0f}, e1[3], e2[3];
525 /*ignore 2-edged faces*/
526 if (target->f->len < 3)
529 if (!CustomData_has_layer(&bm->ldata, CD_MDISPS))
532 mdisps = CustomData_bmesh_get(&bm->ldata, target->head.data, CD_MDISPS);
533 compute_mdisp_quad(target, v1, v2, v3, v4, e1, e2);
535 /*if no disps data allocate a new grid, the size of the first grid in source.*/
536 if (!mdisps->totdisp) {
537 MDisps *md2 = CustomData_bmesh_get(&bm->ldata, bm_firstfaceloop(source)->head.data, CD_MDISPS);
539 mdisps->totdisp = md2->totdisp;
541 mdisps->disps = BLI_cellalloc_calloc(sizeof(float)*3*mdisps->totdisp, "mdisp->disps in bmesh_loop_intern_mdisps");
546 res = (int)sqrt(mdisps->totdisp);
547 d = 1.0/(double)(res-1);
548 for (x=0.0f, ix=0; ix<res; x += d, ix++) {
549 for (y=0.0f, iy=0; iy<res; y+= d, iy++) {
550 double co1[3], co2[3], co[3];
551 /* double xx, yy; */ /* UNUSED */
555 /* if (!iy) yy = y + (double)FLT_EPSILON*20; */
556 /* else yy = y - (double)FLT_EPSILON*20; */
565 /* if (!ix) xx = x + (double)FLT_EPSILON*20; */ /* UNUSED */
566 /* else xx = x - (double)FLT_EPSILON*20; */ /* UNUSED */
568 VECSUB(co, co2, co1);
572 l2 = bm_firstfaceloop(source);
577 md1 = CustomData_bmesh_get(&bm->ldata, target->head.data, CD_MDISPS);
578 md2 = CustomData_bmesh_get(&bm->ldata, l2->head.data, CD_MDISPS);
580 if (mdisp_in_mdispquad(bm, target, l2, co, &x2, &y2, res)) {
581 /* int ix2 = (int)x2; */ /* UNUSED */
582 /* int iy2 = (int)y2; */ /* UNUSED */
584 old_mdisps_bilinear(md1->disps[iy*res+ix], md2->disps, res, (float)x2, (float)y2);
587 } while (l2 != bm_firstfaceloop(source));
592 void BM_multires_smooth_bounds(BMesh *bm, BMFace *f)
597 if (!CustomData_has_layer(&bm->ldata, CD_MDISPS))
600 BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
601 MDisps *mdp = CustomData_bmesh_get(&bm->ldata, l->prev->head.data, CD_MDISPS);
602 MDisps *mdl = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MDISPS);
603 MDisps *mdn = CustomData_bmesh_get(&bm->ldata, l->next->head.data, CD_MDISPS);
609 mdisps is a grid of displacements, ordered thus:
613 | v1/cent-----mid2 ---> x
616 v2/prev---mid1-----v3/cur
622 sides = (int)sqrt(mdp->totdisp);
623 for (y=0; y<sides; y++) {
624 add_v3_v3v3(co1, mdn->disps[y*sides], mdl->disps[y]);
627 copy_v3_v3(mdn->disps[y*sides], co1);
628 copy_v3_v3(mdl->disps[y], co1);
632 BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
633 MDisps *mdl1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MDISPS);
635 float co1[3], co2[3], co[3];
640 mdisps is a grid of displacements, ordered thus:
644 | v1/cent-----mid2 ---> x
647 v2/prev---mid1-----v3/cur
653 if (l->radial_next == l)
656 if (l->radial_next->v == l->v)
657 mdl2 = CustomData_bmesh_get(&bm->ldata, l->radial_next->head.data, CD_MDISPS);
659 mdl2 = CustomData_bmesh_get(&bm->ldata, l->radial_next->next->head.data, CD_MDISPS);
661 sides = (int)sqrt(mdl1->totdisp);
662 for (y=0; y<sides; y++) {
665 if (l->v != l->radial_next->v) {
666 a1 = sides*y + sides-2;
667 a2 = (sides-2)*sides + y;
669 o1 = sides*y + sides-1;
670 o2 = (sides-1)*sides + y;
672 a1 = sides*y + sides-2;
673 a2 = sides*y + sides-2;
674 o1 = sides*y + sides-1;
675 o2 = sides*y + sides-1;
678 /*magic blending numbers, hardcoded!*/
679 add_v3_v3v3(co1, mdl1->disps[a1], mdl2->disps[a2]);
680 mul_v3_fl(co1, 0.18);
682 add_v3_v3v3(co2, mdl1->disps[o1], mdl2->disps[o2]);
683 mul_v3_fl(co2, 0.32);
685 add_v3_v3v3(co, co1, co2);
687 copy_v3_v3(mdl1->disps[o1], co);
688 copy_v3_v3(mdl2->disps[o2], co); //*/
693 void BM_loop_interp_multires(BMesh *bm, BMLoop *target, BMFace *source)
695 bmesh_loop_interp_mdisps(bm, target, source);
698 void BM_loop_interp_from_face(BMesh *bm, BMLoop *target, BMFace *source,
699 int do_vertex, int do_multires)
705 float (*cos)[3]=NULL, co[3], *w=NULL, cent[3] = {0.0f, 0.0f, 0.0f};
706 BLI_array_fixedstack_declare(cos, BM_NGON_STACK_SIZE, source->len, __func__);
707 BLI_array_fixedstack_declare(w, BM_NGON_STACK_SIZE, source->len, __func__);
708 BLI_array_fixedstack_declare(blocks, BM_NGON_STACK_SIZE, source->len, __func__);
709 BLI_array_fixedstack_declare(vblocks, BM_NGON_STACK_SIZE, do_vertex ? source->len : 0, __func__);
712 BM_Copy_Attributes(bm, bm, source, target->f);
715 l = l_first = bm_firstfaceloop(source);
717 copy_v3_v3(cos[i], l->v->co);
718 add_v3_v3(cent, cos[i]);
721 blocks[i] = l->head.data;
724 vblocks[i] = l->v->head.data;
728 } while ((l = l->next) != l_first);
730 /* find best projection of face XY, XZ or YZ: barycentric weights of
731 * the 2d projected coords are the same and faster to compute */
733 axis_dominant_v3(&ax, &ay, source->no);
735 /* scale source face coordinates a bit, so points sitting directonly on an
737 mul_v3_fl(cent, 1.0f/(float)source->len);
738 for (i=0; i<source->len; i++) {
739 float vec[3], tmp[3];
740 sub_v3_v3v3(vec, cent, cos[i]);
741 mul_v3_fl(vec, 0.001f);
742 add_v3_v3(cos[i], vec);
744 copy_v3_v3(tmp, cos[i]);
752 co[0] = target->v->co[ax];
753 co[1] = target->v->co[ay];
756 interp_weights_poly_v3(w, cos, source->len, co);
757 CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, source->len, target->head.data);
759 CustomData_bmesh_interp(&bm->vdata, vblocks, w, NULL, source->len, target->v->head.data);
760 BLI_array_fixedstack_free(vblocks);
763 BLI_array_fixedstack_free(cos);
764 BLI_array_fixedstack_free(w);
765 BLI_array_fixedstack_free(blocks);
768 if (CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
769 bmesh_loop_interp_mdisps(bm, target, source);
775 void BM_vert_interp_from_face(BMesh *bm, BMVert *v, BMFace *source)
780 float (*cos)[3]=NULL, *w=NULL, cent[3] = {0.0f, 0.0f, 0.0f};
781 BLI_array_fixedstack_declare(cos, BM_NGON_STACK_SIZE, source->len, __func__);
782 BLI_array_fixedstack_declare(w, BM_NGON_STACK_SIZE, source->len, __func__);
783 BLI_array_fixedstack_declare(blocks, BM_NGON_STACK_SIZE, source->len, __func__);
787 l = l_first = bm_firstfaceloop(source);
789 copy_v3_v3(cos[i], l->v->co);
790 add_v3_v3(cent, cos[i]);
793 blocks[i] = l->v->head.data;
795 } while ((l = l->next) != l_first);
797 /* scale source face coordinates a bit, so points sitting directonly on an
799 mul_v3_fl(cent, 1.0f/(float)source->len);
800 for (i = 0; i < source->len; i++) {
802 sub_v3_v3v3(vec, cent, cos[i]);
803 mul_v3_fl(vec, 0.01);
804 add_v3_v3(cos[i], vec);
808 interp_weights_poly_v3(w, cos, source->len, v->co);
809 CustomData_bmesh_interp(&bm->vdata, blocks, w, NULL, source->len, v->head.data);
811 BLI_array_fixedstack_free(cos);
812 BLI_array_fixedstack_free(w);
813 BLI_array_fixedstack_free(blocks);
816 static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
819 BLI_mempool *oldpool = olddata->pool;
822 CustomData_bmesh_init_pool(data, data==&bm->ldata ? 2048 : 512);
824 if (data == &bm->vdata) {
827 BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, 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;
835 else if (data == &bm->edata) {
838 BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
840 CustomData_bmesh_set_default(data, &block);
841 CustomData_bmesh_copy_data(olddata, data, eed->head.data, &block);
842 CustomData_bmesh_free_block(olddata, &eed->head.data);
843 eed->head.data= block;
846 else if (data == &bm->pdata || data == &bm->ldata) {
851 BM_ITER(efa, &iter, bm, BM_FACES_OF_MESH, NULL) {
852 if (data == &bm->pdata) {
854 CustomData_bmesh_set_default(data, &block);
855 CustomData_bmesh_copy_data(olddata, data, efa->head.data, &block);
856 CustomData_bmesh_free_block(olddata, &efa->head.data);
857 efa->head.data= block;
860 if (data == &bm->ldata) {
861 BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, efa) {
863 CustomData_bmesh_set_default(data, &block);
864 CustomData_bmesh_copy_data(olddata, data, l->head.data, &block);
865 CustomData_bmesh_free_block(olddata, &l->head.data);
873 /* this should never happen but can when dissolve fails - [#28960] */
874 BLI_assert(data->pool != oldpool);
876 BLI_mempool_destroy(oldpool);
880 void BM_add_data_layer(BMesh *bm, CustomData *data, int type)
885 olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
887 /* the pool is now owned by olddata and must not be shared */
890 CustomData_add_layer(data, type, CD_DEFAULT, NULL, 0);
892 update_data_blocks(bm, &olddata, data);
893 if (olddata.layers) MEM_freeN(olddata.layers);
896 void BM_add_data_layer_named(BMesh *bm, CustomData *data, int type, const char *name)
901 olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
903 /* the pool is now owned by olddata and must not be shared */
906 CustomData_add_layer_named(data, type, CD_DEFAULT, NULL, 0, name);
908 update_data_blocks(bm, &olddata, data);
909 if (olddata.layers) MEM_freeN(olddata.layers);
912 void BM_free_data_layer(BMesh *bm, CustomData *data, int type)
917 olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
919 /* the pool is now owned by olddata and must not be shared */
922 CustomData_free_layer_active(data, type, 0);
924 update_data_blocks(bm, &olddata, data);
925 if (olddata.layers) MEM_freeN(olddata.layers);
928 void BM_free_data_layer_n(BMesh *bm, CustomData *data, int type, int n)
933 olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
935 /* the pool is now owned by olddata and must not be shared */
938 CustomData_free_layer(data, type, 0, CustomData_get_layer_index_n(data, type, n));
940 update_data_blocks(bm, &olddata, data);
941 if (olddata.layers) MEM_freeN(olddata.layers);
944 float BM_GetCDf(CustomData *cd, void *element, int type)
946 float *f = CustomData_bmesh_get(cd, ((BMHeader*)element)->data, type);
947 return f ? *f : 0.0f;
950 void BM_SetCDf(CustomData *cd, void *element, int type, float val)
952 float *f = CustomData_bmesh_get(cd, ((BMHeader*)element)->data, type);