Undo: support implicit-sharing in memfile undo step #106903

Merged
Jacques Lucke merged 78 commits from JacquesLucke/blender:implicit-sharing-undo into main 2024-02-29 17:15:09 +01:00
12 changed files with 91 additions and 86 deletions
Showing only changes of commit 0b1379f00a - Show all commits

View File

@ -167,28 +167,31 @@ void CustomData_copy(const struct CustomData *source,
* Initializes a CustomData object with the same layers as source. The data is not copied from the
* source. Instead, the new layers are initialized using the given `alloctype`.
*/
void CustomData_copy_new(const struct CustomData *source,
struct CustomData *dest,
eCustomDataMask mask,
eCDAllocType alloctype,
int totelem);
void CustomData_copy_layout(const struct CustomData *source,
struct CustomData *dest,
eCustomDataMask mask,
eCDAllocType alloctype,
int totelem);
/* BMESH_TODO, not really a public function but readfile.c needs it */
void CustomData_update_typemap(struct CustomData *data);
/**
* Same as the above, except that this will preserve existing layers, and only
* add the layers that were not there yet.
* Copies all layers from source to destination that don't exist there yet.
*/
bool CustomData_merge(const struct CustomData *source,
struct CustomData *dest,
eCustomDataMask mask,
int totelem);
bool CustomData_merge_new(const struct CustomData *source,
struct CustomData *dest,
eCustomDataMask mask,
eCDAllocType alloctype,
int totelem);
/**
* Copies all layers from source to destination that don't exist there yet. The layer data is not
* copied. Instead the newly created layers are initialized using the given `alloctype`.
*/
bool CustomData_merge_layout(const struct CustomData *source,
struct CustomData *dest,
eCustomDataMask mask,
eCDAllocType alloctype,
int totelem);
/**
* Reallocate custom data to a new element count. If the new size is larger, the new values use

View File

@ -207,11 +207,12 @@ void DM_from_template(DerivedMesh *dm,
int numPolys)
{
const CustomData_MeshMasks *mask = &CD_MASK_DERIVEDMESH;
CustomData_copy_new(&source->vertData, &dm->vertData, mask->vmask, CD_SET_DEFAULT, numVerts);
CustomData_copy_new(&source->edgeData, &dm->edgeData, mask->emask, CD_SET_DEFAULT, numEdges);
CustomData_copy_new(&source->faceData, &dm->faceData, mask->fmask, CD_SET_DEFAULT, numTessFaces);
CustomData_copy_new(&source->loopData, &dm->loopData, mask->lmask, CD_SET_DEFAULT, numLoops);
CustomData_copy_new(&source->polyData, &dm->polyData, mask->pmask, CD_SET_DEFAULT, numPolys);
CustomData_copy_layout(&source->vertData, &dm->vertData, mask->vmask, CD_SET_DEFAULT, numVerts);
CustomData_copy_layout(&source->edgeData, &dm->edgeData, mask->emask, CD_SET_DEFAULT, numEdges);
CustomData_copy_layout(
&source->faceData, &dm->faceData, mask->fmask, CD_SET_DEFAULT, numTessFaces);
CustomData_copy_layout(&source->loopData, &dm->loopData, mask->lmask, CD_SET_DEFAULT, numLoops);
CustomData_copy_layout(&source->polyData, &dm->polyData, mask->pmask, CD_SET_DEFAULT, numPolys);
dm->poly_offsets = static_cast<int *>(MEM_dupallocN(source->poly_offsets));
dm->type = type;

View File

@ -2317,11 +2317,11 @@ bool CustomData_merge(const CustomData *source,
return customdata_merge_internal(source, dest, mask, CD_ASSIGN, totelem);
}
bool CustomData_merge_new(const CustomData *source,
CustomData *dest,
const eCustomDataMask mask,
const eCDAllocType alloctype,
const int totelem)
bool CustomData_merge_layout(const CustomData *source,
CustomData *dest,
const eCustomDataMask mask,
const eCDAllocType alloctype,
const int totelem)
{
return customdata_merge_internal(source, dest, mask, alloctype, totelem);
}
@ -2454,11 +2454,11 @@ void CustomData_copy(const CustomData *source, CustomData *dest, eCustomDataMask
CustomData_merge(source, dest, mask, totelem);
}
void CustomData_copy_new(const struct CustomData *source,
struct CustomData *dest,
eCustomDataMask mask,
eCDAllocType alloctype,
int totelem)
void CustomData_copy_layout(const struct CustomData *source,
struct CustomData *dest,
eCustomDataMask mask,
eCDAllocType alloctype,
int totelem)
{
CustomData_reset(dest);
@ -2466,7 +2466,7 @@ void CustomData_copy_new(const struct CustomData *source,
dest->external = static_cast<CustomDataExternal *>(MEM_dupallocN(source->external));
}
CustomData_merge_new(source, dest, mask, alloctype, totelem);
CustomData_merge_layout(source, dest, mask, alloctype, totelem);
}
static void customData_free_layer__internal(CustomDataLayer *layer, const int totelem)
@ -3717,7 +3717,7 @@ bool CustomData_bmesh_merge_new(const CustomData *source,
destold.layers = static_cast<CustomDataLayer *>(MEM_dupallocN(destold.layers));
}
if (CustomData_merge_new(source, dest, mask, alloctype, 0) == false) {
if (CustomData_merge_layout(source, dest, mask, alloctype, 0) == false) {
if (destold.layers) {
MEM_freeN(destold.layers);
}

View File

@ -1095,12 +1095,13 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
BKE_mesh_copy_parameters_for_eval(me_dst, me_src);
CustomData_copy_new(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_SET_DEFAULT, verts_len);
CustomData_copy_new(&me_src->edata, &me_dst->edata, mask.emask, CD_SET_DEFAULT, edges_len);
CustomData_copy_new(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_SET_DEFAULT, loops_len);
CustomData_copy_new(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_SET_DEFAULT, polys_len);
CustomData_copy_layout(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_SET_DEFAULT, verts_len);
CustomData_copy_layout(&me_src->edata, &me_dst->edata, mask.emask, CD_SET_DEFAULT, edges_len);
CustomData_copy_layout(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_SET_DEFAULT, loops_len);
CustomData_copy_layout(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_SET_DEFAULT, polys_len);
if (do_tessface) {
CustomData_copy_new(&me_src->fdata, &me_dst->fdata, mask.fmask, CD_SET_DEFAULT, tessface_len);
CustomData_copy_layout(
&me_src->fdata, &me_dst->fdata, mask.fmask, CD_SET_DEFAULT, tessface_len);
}
else {
mesh_tessface_clear_intern(me_dst, false);

View File

@ -656,15 +656,15 @@ static void merge_vertex_loop_poly_customdata_layers(Mesh *target, MeshesToIMesh
for (int mesh_index = 1; mesh_index < mim.meshes.size(); ++mesh_index) {
const Mesh *me = mim.meshes[mesh_index];
if (me->totvert) {
CustomData_merge_new(
CustomData_merge_layout(
&me->vdata, &target->vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, target->totvert);
}
if (me->totloop) {
CustomData_merge_new(
CustomData_merge_layout(
&me->ldata, &target->ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, target->totloop);
}
if (me->totpoly) {
CustomData_merge_new(
CustomData_merge_layout(
&me->pdata, &target->pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, target->totpoly);
}
}
@ -675,7 +675,7 @@ static void merge_edge_customdata_layers(Mesh *target, MeshesToIMeshInfo &mim)
for (int mesh_index = 0; mesh_index < mim.meshes.size(); ++mesh_index) {
const Mesh *me = mim.meshes[mesh_index];
if (me->totedge) {
CustomData_merge_new(
CustomData_merge_layout(
&me->edata, &target->edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, target->totedge);
}
}

View File

@ -2286,7 +2286,7 @@ void BKE_mesh_legacy_convert_polys_to_offsets(Mesh *mesh)
});
CustomData old_poly_data = mesh->pdata;
CustomData_reset(&mesh->pdata);
CustomData_copy_new(
CustomData_copy_layout(
&old_poly_data, &mesh->pdata, CD_MASK_MESH.pmask, CD_CONSTRUCT, mesh->totpoly);
int offset = 0;

View File

@ -220,11 +220,11 @@ static void vertex_interpolation_init(const SubdivMeshContext *ctx,
else {
vertex_interpolation->vertex_data = &vertex_interpolation->vertex_data_storage;
/* Allocate storage for loops corresponding to ptex corners. */
CustomData_copy_new(&ctx->coarse_mesh->vdata,
&vertex_interpolation->vertex_data_storage,
CD_MASK_EVERYTHING.vmask,
CD_SET_DEFAULT,
4);
CustomData_copy_layout(&ctx->coarse_mesh->vdata,
&vertex_interpolation->vertex_data_storage,
CD_MASK_EVERYTHING.vmask,
CD_SET_DEFAULT,
4);
/* Initialize indices. */
vertex_interpolation->vertex_indices[0] = 0;
vertex_interpolation->vertex_indices[1] = 1;
@ -350,11 +350,11 @@ static void loop_interpolation_init(const SubdivMeshContext *ctx,
else {
loop_interpolation->loop_data = &loop_interpolation->loop_data_storage;
/* Allocate storage for loops corresponding to ptex corners. */
CustomData_copy_new(&ctx->coarse_mesh->ldata,
&loop_interpolation->loop_data_storage,
CD_MASK_EVERYTHING.lmask,
CD_SET_DEFAULT,
4);
CustomData_copy_layout(&ctx->coarse_mesh->ldata,
&loop_interpolation->loop_data_storage,
CD_MASK_EVERYTHING.lmask,
CD_SET_DEFAULT,
4);
/* Initialize indices. */
loop_interpolation->loop_indices[0] = 0;
loop_interpolation->loop_indices[1] = 1;

View File

@ -517,16 +517,16 @@ void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst,
&me_src->ldata, CD_MASK_BMESH.pmask);
if (i == 0) {
CustomData_copy_new(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0);
CustomData_copy_new(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0);
CustomData_copy_new(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0);
CustomData_copy_new(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0);
CustomData_copy_layout(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0);
CustomData_copy_layout(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0);
CustomData_copy_layout(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0);
CustomData_copy_layout(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0);
}
else {
CustomData_merge_new(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0);
CustomData_merge_new(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0);
CustomData_merge_new(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0);
CustomData_merge_new(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0);
CustomData_merge_layout(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0);
CustomData_merge_layout(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0);
CustomData_merge_layout(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0);
CustomData_merge_layout(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0);
}
MEM_SAFE_FREE(mesh_vdata.layers);
@ -554,10 +554,10 @@ void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTem
allocsize = &bm_mesh_allocsize_default;
}
CustomData_copy_new(&bm_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0);
CustomData_copy_new(&bm_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0);
CustomData_copy_new(&bm_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0);
CustomData_copy_new(&bm_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0);
CustomData_copy_layout(&bm_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0);
CustomData_copy_layout(&bm_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0);
CustomData_copy_layout(&bm_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0);
CustomData_copy_layout(&bm_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0);
CustomData_bmesh_init_pool(&bm_dst->vdata, allocsize->totvert, BM_VERT);
CustomData_bmesh_init_pool(&bm_dst->edata, allocsize->totedge, BM_EDGE);

View File

@ -268,10 +268,10 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
if (me->totvert == 0) {
if (is_new) {
/* No verts? still copy custom-data layout. */
CustomData_copy_new(&mesh_vdata, &bm->vdata, mask.vmask, CD_CONSTRUCT, 0);
CustomData_copy_new(&mesh_edata, &bm->edata, mask.emask, CD_CONSTRUCT, 0);
CustomData_copy_new(&mesh_pdata, &bm->pdata, mask.pmask, CD_CONSTRUCT, 0);
CustomData_copy_new(&mesh_ldata, &bm->ldata, mask.lmask, CD_CONSTRUCT, 0);
CustomData_copy_layout(&mesh_vdata, &bm->vdata, mask.vmask, CD_CONSTRUCT, 0);
CustomData_copy_layout(&mesh_edata, &bm->edata, mask.emask, CD_CONSTRUCT, 0);
CustomData_copy_layout(&mesh_pdata, &bm->pdata, mask.pmask, CD_CONSTRUCT, 0);
CustomData_copy_layout(&mesh_ldata, &bm->ldata, mask.lmask, CD_CONSTRUCT, 0);
CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT);
CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE);
@ -287,10 +287,10 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
}
if (is_new) {
CustomData_copy_new(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, 0);
CustomData_copy_new(&mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, 0);
CustomData_copy_new(&mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, 0);
CustomData_copy_new(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, 0);
CustomData_copy_layout(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, 0);
CustomData_copy_layout(&mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, 0);
CustomData_copy_layout(&mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, 0);
CustomData_copy_layout(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, 0);
}
else {
CustomData_bmesh_merge_new(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, bm, BM_VERT);
@ -1400,10 +1400,10 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
{
CustomData_MeshMasks mask = CD_MASK_MESH;
CustomData_MeshMasks_update(&mask, &params->cd_mask_extra);
CustomData_copy_new(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert);
CustomData_copy_new(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge);
CustomData_copy_new(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop);
CustomData_copy_new(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly);
CustomData_copy_layout(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert);
CustomData_copy_layout(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge);
CustomData_copy_layout(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop);
CustomData_copy_layout(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly);
}
bool need_select_vert = false;
@ -1615,10 +1615,10 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
CustomData_MeshMasks_update(&mask, cd_mask_extra);
}
mask.vmask &= ~CD_MASK_SHAPEKEY;
CustomData_merge_new(&bm->vdata, &me->vdata, mask.vmask, CD_CONSTRUCT, me->totvert);
CustomData_merge_new(&bm->edata, &me->edata, mask.emask, CD_CONSTRUCT, me->totedge);
CustomData_merge_new(&bm->ldata, &me->ldata, mask.lmask, CD_CONSTRUCT, me->totloop);
CustomData_merge_new(&bm->pdata, &me->pdata, mask.pmask, CD_CONSTRUCT, me->totpoly);
CustomData_merge_layout(&bm->vdata, &me->vdata, mask.vmask, CD_CONSTRUCT, me->totvert);
CustomData_merge_layout(&bm->edata, &me->edata, mask.emask, CD_CONSTRUCT, me->totedge);
CustomData_merge_layout(&bm->ldata, &me->ldata, mask.lmask, CD_CONSTRUCT, me->totloop);
CustomData_merge_layout(&bm->pdata, &me->pdata, mask.pmask, CD_CONSTRUCT, me->totpoly);
me->runtime->deformed_only = true;

View File

@ -1144,7 +1144,7 @@ static void mesh_add_verts(Mesh *mesh, int len)
int totvert = mesh->totvert + len;
CustomData vdata;
CustomData_copy_new(&mesh->vdata, &vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert);
CustomData_copy_layout(&mesh->vdata, &vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert);
CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert);
if (!CustomData_get_layer_named(&vdata, CD_PROP_FLOAT3, "position")) {
@ -1178,7 +1178,7 @@ static void mesh_add_edges(Mesh *mesh, int len)
totedge = mesh->totedge + len;
/* Update custom-data. */
CustomData_copy_new(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge);
CustomData_copy_layout(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge);
CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge);
if (!CustomData_has_layer(&edata, CD_MEDGE)) {
@ -1211,7 +1211,7 @@ static void mesh_add_loops(Mesh *mesh, int len)
totloop = mesh->totloop + len; /* new face count */
/* update customdata */
CustomData_copy_new(&mesh->ldata, &ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop);
CustomData_copy_layout(&mesh->ldata, &ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop);
CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop);
if (!CustomData_get_layer_named(&ldata, CD_PROP_INT32, ".corner_vert")) {
@ -1248,7 +1248,7 @@ static void mesh_add_polys(Mesh *mesh, int len)
totpoly = mesh->totpoly + len; /* new face count */
/* update customdata */
CustomData_copy_new(&mesh->pdata, &pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly);
CustomData_copy_layout(&mesh->pdata, &pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly);
CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly);
mesh->poly_offset_indices = static_cast<int *>(

View File

@ -105,7 +105,7 @@ static void join_mesh_single(Depsgraph *depsgraph,
if (me->totvert) {
/* standard data */
CustomData_merge_new(&me->vdata, vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert);
CustomData_merge_layout(&me->vdata, vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert);
CustomData_copy_data_named(&me->vdata, vdata, 0, *vertofs, me->totvert);
/* vertex groups */
@ -205,7 +205,7 @@ static void join_mesh_single(Depsgraph *depsgraph,
}
if (me->totedge) {
CustomData_merge_new(&me->edata, edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge);
CustomData_merge_layout(&me->edata, edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge);
CustomData_copy_data_named(&me->edata, edata, 0, *edgeofs, me->totedge);
for (a = 0; a < me->totedge; a++, edge++) {
@ -226,7 +226,7 @@ static void join_mesh_single(Depsgraph *depsgraph,
}
}
CustomData_merge_new(&me->ldata, ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop);
CustomData_merge_layout(&me->ldata, ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop);
CustomData_copy_data_named(&me->ldata, ldata, 0, *loopofs, me->totloop);
for (a = 0; a < me->totloop; a++) {
@ -250,7 +250,7 @@ static void join_mesh_single(Depsgraph *depsgraph,
}
}
CustomData_merge_new(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly);
CustomData_merge_layout(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly);
CustomData_copy_data_named(&me->pdata, pdata, 0, *polyofs, me->totpoly);
/* Apply matmap. In case we don't have material indices yet, create them if more than one

View File

@ -550,7 +550,7 @@ void MeshImporter::mesh_add_edges(Mesh *mesh, int len)
totedge = mesh->totedge + len;
/* Update custom-data. */
CustomData_copy_new(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge);
CustomData_copy_layout(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge);
CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge);
if (!CustomData_has_layer(&edata, CD_MEDGE)) {