WIP: uv-simple-select #1

Closed
Chris Blackbourn wants to merge 182 commits from uv-simple-select into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
3 changed files with 162 additions and 155 deletions
Showing only changes of commit 5297f851e9 - Show all commits

View File

@ -137,6 +137,7 @@ bool CustomData_has_referenced(const struct CustomData *data);
* implemented for mloopuv/mloopcol, for now. * implemented for mloopuv/mloopcol, for now.
*/ */
void CustomData_data_copy_value(int type, const void *source, void *dest); void CustomData_data_copy_value(int type, const void *source, void *dest);
void CustomData_data_set_default_value(int type, void *elem);
/** /**
* Mixes the "value" (e.g. mloopuv uv or mloopcol colors) from one block into * Mixes the "value" (e.g. mloopuv uv or mloopcol colors) from one block into
@ -506,6 +507,8 @@ void CustomData_clear_layer_flag(struct CustomData *data, int type, int flag);
void CustomData_bmesh_set_default(struct CustomData *data, void **block); void CustomData_bmesh_set_default(struct CustomData *data, void **block);
void CustomData_bmesh_free_block(struct CustomData *data, void **block); void CustomData_bmesh_free_block(struct CustomData *data, void **block);
void CustomData_bmesh_alloc_block(struct CustomData *data, void **block);
/** /**
* Same as #CustomData_bmesh_free_block but zero the memory rather than freeing. * Same as #CustomData_bmesh_free_block but zero the memory rather than freeing.
*/ */
@ -517,23 +520,6 @@ void CustomData_bmesh_free_block_data_exclude_by_type(struct CustomData *data,
void *block, void *block,
eCustomDataMask mask_exclude); eCustomDataMask mask_exclude);
/**
* Copy custom data to/from layers as in mesh/derived-mesh, to edit-mesh
* blocks of data. the CustomData's must not be compatible.
*
* \param use_default_init: initializes data which can't be copied,
* typically you'll want to use this if the BM_xxx create function
* is called with BM_CREATE_SKIP_CD flag
*/
void CustomData_to_bmesh_block(const struct CustomData *source,
struct CustomData *dest,
int src_index,
void **dest_block,
bool use_default_init);
void CustomData_from_bmesh_block(const struct CustomData *source,
struct CustomData *dest,
void *src_block,
int dest_index);
/** /**
* Query info over types. * Query info over types.

View File

@ -3654,7 +3654,7 @@ void CustomData_bmesh_free_block_data(CustomData *data, void *block)
} }
} }
static void CustomData_bmesh_alloc_block(CustomData *data, void **block) void CustomData_bmesh_alloc_block(CustomData *data, void **block)
{ {
if (*block) { if (*block) {
CustomData_bmesh_free_block(data, block); CustomData_bmesh_free_block(data, block);
@ -3689,19 +3689,23 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
} }
} }
static void CustomData_bmesh_set_default_n(CustomData *data, void **block, const int n) void CustomData_data_set_default_value(const int type, void *elem)
{ {
int offset = data->layers[n].offset; const LayerTypeInfo *typeInfo = layerType_getInfo(type);
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type);
if (typeInfo->set_default_value) { if (typeInfo->set_default_value) {
typeInfo->set_default_value(POINTER_OFFSET(*block, offset), 1); typeInfo->set_default_value(elem, 1);
} }
else { else {
memset(POINTER_OFFSET(*block, offset), 0, typeInfo->size); memset(elem, 0, typeInfo->size);
} }
} }
static void CustomData_bmesh_set_default_n(CustomData *data, void **block, const int n)
{
const int offset = data->layers[n].offset;
CustomData_data_set_default_value(data->layers[n].type, POINTER_OFFSET(*block, offset));
}
void CustomData_bmesh_set_default(CustomData *data, void **block) void CustomData_bmesh_set_default(CustomData *data, void **block)
{ {
if (*block == nullptr) { if (*block == nullptr) {
@ -3891,8 +3895,8 @@ void CustomData_data_copy_value(int type, const void *source, void *dest)
return; return;
} }
if (typeInfo->copyvalue) { if (typeInfo->copy) {
typeInfo->copyvalue(source, dest, CDT_MIX_NOMIX, 0.0f); typeInfo->copy(source, dest, 1);
} }
else { else {
memcpy(dest, source, typeInfo->size); memcpy(dest, source, typeInfo->size);
@ -4067,115 +4071,6 @@ void CustomData_bmesh_interp(CustomData *data,
} }
} }
void CustomData_to_bmesh_block(const CustomData *source,
CustomData *dest,
int src_index,
void **dest_block,
bool use_default_init)
{
if (*dest_block == nullptr) {
CustomData_bmesh_alloc_block(dest, dest_block);
}
/* copies a layer at a time */
int dest_i = 0;
for (int src_i = 0; src_i < source->totlayer; src_i++) {
/* find the first dest layer with type >= the source type
* (this should work because layers are ordered by type)
*/
while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
if (use_default_init) {
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
}
dest_i++;
}
/* if there are no more dest layers, we're done */
if (dest_i >= dest->totlayer) {
break;
}
/* if we found a matching layer, copy the data */
if (dest->layers[dest_i].type == source->layers[src_i].type) {
int offset = dest->layers[dest_i].offset;
const void *src_data = source->layers[src_i].data;
void *dest_data = POINTER_OFFSET(*dest_block, offset);
const LayerTypeInfo *typeInfo = layerType_getInfo(dest->layers[dest_i].type);
const size_t src_offset = size_t(src_index) * typeInfo->size;
if (typeInfo->copy) {
typeInfo->copy(POINTER_OFFSET(src_data, src_offset), dest_data, 1);
}
else {
memcpy(dest_data, POINTER_OFFSET(src_data, src_offset), typeInfo->size);
}
/* if there are multiple source & dest layers of the same type,
* we don't want to copy all source layers to the same dest, so
* increment dest_i
*/
dest_i++;
}
}
if (use_default_init) {
while (dest_i < dest->totlayer) {
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
dest_i++;
}
}
}
void CustomData_from_bmesh_block(const CustomData *source,
CustomData *dest,
void *src_block,
int dest_index)
{
/* copies a layer at a time */
int dest_i = 0;
for (int src_i = 0; src_i < source->totlayer; src_i++) {
if (source->layers[src_i].flag & CD_FLAG_NOCOPY) {
continue;
}
/* find the first dest layer with type >= the source type
* (this should work because layers are ordered by type)
*/
while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
dest_i++;
}
/* if there are no more dest layers, we're done */
if (dest_i >= dest->totlayer) {
return;
}
/* if we found a matching layer, copy the data */
if (dest->layers[dest_i].type == source->layers[src_i].type) {
const LayerTypeInfo *typeInfo = layerType_getInfo(dest->layers[dest_i].type);
int offset = source->layers[src_i].offset;
const void *src_data = POINTER_OFFSET(src_block, offset);
void *dst_data = POINTER_OFFSET(dest->layers[dest_i].data,
size_t(dest_index) * typeInfo->size);
if (typeInfo->copy) {
typeInfo->copy(src_data, dst_data, 1);
}
else {
memcpy(dst_data, src_data, typeInfo->size);
}
/* if there are multiple source & dest layers of the same type,
* we don't want to copy all source layers to the same dest, so
* increment dest_i
*/
dest_i++;
}
}
}
void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num) void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num)
{ {
const LayerTypeInfo *typeInfo = layerType_getInfo(type); const LayerTypeInfo *typeInfo = layerType_getInfo(type);

View File

@ -85,6 +85,7 @@
#include "BLI_span.hh" #include "BLI_span.hh"
#include "BLI_string_ref.hh" #include "BLI_string_ref.hh"
#include "BLI_task.hh" #include "BLI_task.hh"
#include "BLI_vector.hh"
#include "BKE_attribute.hh" #include "BKE_attribute.hh"
#include "BKE_customdata.h" #include "BKE_customdata.h"
@ -110,6 +111,7 @@ using blender::IndexRange;
using blender::MutableSpan; using blender::MutableSpan;
using blender::Span; using blender::Span;
using blender::StringRef; using blender::StringRef;
using blender::Vector;
static char bm_edge_flag_from_mflag(const short mflag) static char bm_edge_flag_from_mflag(const short mflag)
{ {
@ -164,6 +166,63 @@ static BMFace *bm_face_create_from_mpoly(BMesh &bm,
return BM_face_create(&bm, verts.data(), edges.data(), loops.size(), nullptr, BM_CREATE_SKIP_CD); return BM_face_create(&bm, verts.data(), edges.data(), loops.size(), nullptr, BM_CREATE_SKIP_CD);
} }
struct MeshToBMeshLayerInfo {
eCustomDataType type;
/** The layer's position in the BMesh element's data block. */
int bmesh_offset;
/** The mesh's #CustomDataLayer::data. When null, the BMesh block is set to its default value. */
const void *mesh_data;
/** The size of every custom data element. */
size_t elem_size;
};
/**
* Calculate the necessary information to copy every data layer from the Mesh to the BMesh.
*/
static Vector<MeshToBMeshLayerInfo> mesh_to_bm_copy_info_calc(const CustomData &mesh_data,
CustomData &bm_data)
{
Vector<MeshToBMeshLayerInfo> infos;
std::array<int, CD_NUMTYPES> per_type_index;
per_type_index.fill(0);
for (const int i : IndexRange(bm_data.totlayer)) {
CustomDataLayer &bm_layer = bm_data.layers[i];
const eCustomDataType type = eCustomDataType(bm_layer.type);
const int mesh_layer_index =
bm_layer.name[0] == '\0' ?
CustomData_get_layer_index_n(&mesh_data, type, per_type_index[type]) :
CustomData_get_named_layer_index(&mesh_data, type, bm_layer.name);
MeshToBMeshLayerInfo info{};
info.type = type;
info.bmesh_offset = bm_layer.offset;
info.mesh_data = (mesh_layer_index == -1) ? nullptr : mesh_data.layers[mesh_layer_index].data;
info.elem_size = CustomData_get_elem_size(&bm_layer);
infos.append(info);
per_type_index[type]++;
}
return infos;
}
static void mesh_attributes_copy_to_bmesh_block(CustomData &data,
const Span<MeshToBMeshLayerInfo> copy_info,
const int mesh_index,
BMHeader &header)
{
CustomData_bmesh_alloc_block(&data, &header.data);
for (const MeshToBMeshLayerInfo &info : copy_info) {
if (info.mesh_data) {
CustomData_data_copy_value(info.type,
POINTER_OFFSET(info.mesh_data, info.elem_size * mesh_index),
POINTER_OFFSET(header.data, info.bmesh_offset));
}
else {
CustomData_data_set_default_value(info.type, POINTER_OFFSET(header.data, info.bmesh_offset));
}
}
}
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params) void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
{ {
if (!me) { if (!me) {
@ -259,6 +318,11 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
CustomData_bmesh_merge(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, bm, BM_LOOP); CustomData_bmesh_merge(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, bm, BM_LOOP);
} }
const Vector<MeshToBMeshLayerInfo> vert_info = mesh_to_bm_copy_info_calc(mesh_vdata, bm->vdata);
const Vector<MeshToBMeshLayerInfo> edge_info = mesh_to_bm_copy_info_calc(mesh_edata, bm->edata);
const Vector<MeshToBMeshLayerInfo> poly_info = mesh_to_bm_copy_info_calc(mesh_pdata, bm->pdata);
const Vector<MeshToBMeshLayerInfo> loop_info = mesh_to_bm_copy_info_calc(mesh_ldata, bm->ldata);
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/* Shape Key */ /* Shape Key */
int tot_shape_keys = 0; int tot_shape_keys = 0;
@ -393,8 +457,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
copy_v3_v3(v->no, vert_normals[i]); copy_v3_v3(v->no, vert_normals[i]);
} }
/* Copy Custom Data */ mesh_attributes_copy_to_bmesh_block(bm->vdata, vert_info, i, v->head);
CustomData_to_bmesh_block(&mesh_vdata, &bm->vdata, i, &v->head.data, true);
/* Set shape key original index. */ /* Set shape key original index. */
if (cd_shape_keyindex_offset != -1) { if (cd_shape_keyindex_offset != -1) {
@ -432,8 +495,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
BM_elem_flag_enable(e, BM_ELEM_SMOOTH); BM_elem_flag_enable(e, BM_ELEM_SMOOTH);
} }
/* Copy Custom Data */ mesh_attributes_copy_to_bmesh_block(bm->edata, edge_info, i, e->head);
CustomData_to_bmesh_block(&mesh_edata, &bm->edata, i, &e->head.data, true);
} }
if (is_new) { if (is_new) {
bm->elem_index_dirty &= ~BM_EDGE; /* Added in order, clear dirty flag. */ bm->elem_index_dirty &= ~BM_EDGE; /* Added in order, clear dirty flag. */
@ -491,12 +553,11 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
/* Don't use 'j' since we may have skipped some faces, hence some loops. */ /* Don't use 'j' since we may have skipped some faces, hence some loops. */
BM_elem_index_set(l_iter, totloops++); /* set_ok */ BM_elem_index_set(l_iter, totloops++); /* set_ok */
/* Save index of corresponding #MLoop. */ mesh_attributes_copy_to_bmesh_block(bm->ldata, loop_info, j, l_iter->head);
CustomData_to_bmesh_block(&mesh_ldata, &bm->ldata, j++, &l_iter->head.data, true); j++;
} while ((l_iter = l_iter->next) != l_first); } while ((l_iter = l_iter->next) != l_first);
/* Copy Custom Data */ mesh_attributes_copy_to_bmesh_block(bm->pdata, poly_info, i, f->head);
CustomData_to_bmesh_block(&mesh_pdata, &bm->pdata, i, &f->head.data, true);
if (params->calc_face_normal) { if (params->calc_face_normal) {
BM_face_normal_update(f); BM_face_normal_update(f);
@ -998,6 +1059,66 @@ static void convert_bmesh_selection_flags_to_mesh_attributes(BMesh &bm,
} }
} }
struct BMeshToMeshLayerInfo {
eCustomDataType type;
/** The layer's position in the BMesh element's data block. */
int bmesh_offset;
/** The mesh's #CustomDataLayer::data. When null, the BMesh block is set to its default value. */
void *mesh_data;
/** The size of every custom data element. */
size_t elem_size;
};
/**
* Calculate the necessary information to copy every data layer from the BMesh to the Mesh.
*/
static Vector<BMeshToMeshLayerInfo> bm_to_mesh_copy_info_calc(const CustomData &bm_data,
CustomData &mesh_data)
{
Vector<BMeshToMeshLayerInfo> infos;
std::array<int, CD_NUMTYPES> per_type_index;
per_type_index.fill(0);
for (const int i : IndexRange(mesh_data.totlayer)) {
CustomDataLayer &mesh_layer = mesh_data.layers[i];
const eCustomDataType type = eCustomDataType(mesh_layer.type);
const int bm_layer_index =
mesh_layer.name[0] == '\0' ?
CustomData_get_layer_index_n(&bm_data, type, per_type_index[type]) :
CustomData_get_named_layer_index(&bm_data, type, mesh_layer.name);
/* Skip layers that don't exist in `bm_data` or are explicitly set to not be
* copied. The layers are either set separately or shouldn't exist on the mesh. */
if (bm_layer_index == -1) {
continue;
}
const CustomDataLayer &bm_layer = bm_data.layers[bm_layer_index];
if (bm_layer.flag & CD_FLAG_NOCOPY) {
continue;
}
BMeshToMeshLayerInfo info{};
info.type = type;
info.bmesh_offset = bm_layer.offset;
info.mesh_data = mesh_layer.data;
info.elem_size = CustomData_get_elem_size(&mesh_layer);
infos.append(info);
per_type_index[type]++;
}
return infos;
}
static void bmesh_block_copy_to_mesh_attributes(const Span<BMeshToMeshLayerInfo> copy_info,
const int mesh_index,
const void *block)
{
for (const BMeshToMeshLayerInfo &info : copy_info) {
CustomData_data_copy_value(info.type,
POINTER_OFFSET(block, info.bmesh_offset),
POINTER_OFFSET(info.mesh_data, info.elem_size * mesh_index));
}
}
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params) void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
{ {
using namespace blender; using namespace blender;
@ -1110,6 +1231,11 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
CustomData_copy(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly); CustomData_copy(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly);
} }
const Vector<BMeshToMeshLayerInfo> vert_info = bm_to_mesh_copy_info_calc(bm->vdata, me->vdata);
const Vector<BMeshToMeshLayerInfo> edge_info = bm_to_mesh_copy_info_calc(bm->edata, me->edata);
const Vector<BMeshToMeshLayerInfo> poly_info = bm_to_mesh_copy_info_calc(bm->pdata, me->pdata);
const Vector<BMeshToMeshLayerInfo> loop_info = bm_to_mesh_copy_info_calc(bm->ldata, me->ldata);
/* Clear the CD_FLAG_NOCOPY flags for the layers they were temporarily set on */ /* Clear the CD_FLAG_NOCOPY flags for the layers they were temporarily set on */
for (const int i : ldata_layers_marked_nocopy) { for (const int i : ldata_layers_marked_nocopy) {
bm->ldata.layers[i].flag &= ~CD_FLAG_NOCOPY; bm->ldata.layers[i].flag &= ~CD_FLAG_NOCOPY;
@ -1147,8 +1273,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BM_elem_index_set(v, i); /* set_inline */ BM_elem_index_set(v, i); /* set_inline */
/* Copy over custom-data. */ bmesh_block_copy_to_mesh_attributes(vert_info, i, v->head.data);
CustomData_from_bmesh_block(&bm->vdata, &me->vdata, v->head.data, i);
i++; i++;
@ -1174,8 +1299,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BM_elem_index_set(e, i); /* set_inline */ BM_elem_index_set(e, i); /* set_inline */
/* Copy over custom-data. */ bmesh_block_copy_to_mesh_attributes(edge_info, i, e->head.data);
CustomData_from_bmesh_block(&bm->edata, &me->edata, e->head.data, i);
i++; i++;
BM_CHECK_ELEMENT(e); BM_CHECK_ELEMENT(e);
@ -1204,8 +1328,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
mloop[j].e = BM_elem_index_get(l_iter->e); mloop[j].e = BM_elem_index_get(l_iter->e);
mloop[j].v = BM_elem_index_get(l_iter->v); mloop[j].v = BM_elem_index_get(l_iter->v);
/* Copy over custom-data. */ bmesh_block_copy_to_mesh_attributes(loop_info, j, l_iter->head.data);
CustomData_from_bmesh_block(&bm->ldata, &me->ldata, l_iter->head.data, j);
j++; j++;
BM_CHECK_ELEMENT(l_iter); BM_CHECK_ELEMENT(l_iter);
@ -1217,8 +1340,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
me->act_face = i; me->act_face = i;
} }
/* Copy over custom-data. */ bmesh_block_copy_to_mesh_attributes(poly_info, i, f->head.data);
CustomData_from_bmesh_block(&bm->pdata, &me->pdata, f->head.data, i);
i++; i++;
BM_CHECK_ELEMENT(f); BM_CHECK_ELEMENT(f);
@ -1427,12 +1549,13 @@ static void bm_to_mesh_verts(const BMesh &bm,
MutableSpan<bool> select_vert, MutableSpan<bool> select_vert,
MutableSpan<bool> hide_vert) MutableSpan<bool> hide_vert)
{ {
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.vdata, mesh.vdata);
MutableSpan<float3> dst_vert_positions = mesh.vert_positions_for_write(); MutableSpan<float3> dst_vert_positions = mesh.vert_positions_for_write();
threading::parallel_for(dst_vert_positions.index_range(), 1024, [&](const IndexRange range) { threading::parallel_for(dst_vert_positions.index_range(), 1024, [&](const IndexRange range) {
for (const int vert_i : range) { for (const int vert_i : range) {
const BMVert &src_vert = *bm_verts[vert_i]; const BMVert &src_vert = *bm_verts[vert_i];
copy_v3_v3(dst_vert_positions[vert_i], src_vert.co); copy_v3_v3(dst_vert_positions[vert_i], src_vert.co);
CustomData_from_bmesh_block(&bm.vdata, &mesh.vdata, src_vert.head.data, vert_i); bmesh_block_copy_to_mesh_attributes(info, vert_i, src_vert.head.data);
} }
if (!select_vert.is_empty()) { if (!select_vert.is_empty()) {
for (const int vert_i : range) { for (const int vert_i : range) {
@ -1454,6 +1577,7 @@ static void bm_to_mesh_edges(const BMesh &bm,
MutableSpan<bool> hide_edge, MutableSpan<bool> hide_edge,
MutableSpan<bool> sharp_edge) MutableSpan<bool> sharp_edge)
{ {
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.edata, mesh.edata);
MutableSpan<MEdge> dst_edges = mesh.edges_for_write(); MutableSpan<MEdge> dst_edges = mesh.edges_for_write();
threading::parallel_for(dst_edges.index_range(), 512, [&](const IndexRange range) { threading::parallel_for(dst_edges.index_range(), 512, [&](const IndexRange range) {
for (const int edge_i : range) { for (const int edge_i : range) {
@ -1462,7 +1586,7 @@ static void bm_to_mesh_edges(const BMesh &bm,
dst_edge.v1 = BM_elem_index_get(src_edge.v1); dst_edge.v1 = BM_elem_index_get(src_edge.v1);
dst_edge.v2 = BM_elem_index_get(src_edge.v2); dst_edge.v2 = BM_elem_index_get(src_edge.v2);
dst_edge.flag = bm_edge_flag_to_mflag(&src_edge); dst_edge.flag = bm_edge_flag_to_mflag(&src_edge);
CustomData_from_bmesh_block(&bm.edata, &mesh.edata, src_edge.head.data, edge_i); bmesh_block_copy_to_mesh_attributes(info, edge_i, src_edge.head.data);
} }
if (!select_edge.is_empty()) { if (!select_edge.is_empty()) {
for (const int edge_i : range) { for (const int edge_i : range) {
@ -1489,6 +1613,7 @@ static void bm_to_mesh_faces(const BMesh &bm,
MutableSpan<bool> hide_poly, MutableSpan<bool> hide_poly,
MutableSpan<int> material_indices) MutableSpan<int> material_indices)
{ {
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.pdata, mesh.pdata);
MutableSpan<MPoly> dst_polys = mesh.polys_for_write(); MutableSpan<MPoly> dst_polys = mesh.polys_for_write();
threading::parallel_for(dst_polys.index_range(), 1024, [&](const IndexRange range) { threading::parallel_for(dst_polys.index_range(), 1024, [&](const IndexRange range) {
for (const int face_i : range) { for (const int face_i : range) {
@ -1497,7 +1622,7 @@ static void bm_to_mesh_faces(const BMesh &bm,
dst_poly.totloop = src_face.len; dst_poly.totloop = src_face.len;
dst_poly.loopstart = BM_elem_index_get(BM_FACE_FIRST_LOOP(&src_face)); dst_poly.loopstart = BM_elem_index_get(BM_FACE_FIRST_LOOP(&src_face));
dst_poly.flag = bm_face_flag_to_mflag(&src_face); dst_poly.flag = bm_face_flag_to_mflag(&src_face);
CustomData_from_bmesh_block(&bm.pdata, &mesh.pdata, src_face.head.data, face_i); bmesh_block_copy_to_mesh_attributes(info, face_i, src_face.head.data);
} }
if (!select_poly.is_empty()) { if (!select_poly.is_empty()) {
for (const int face_i : range) { for (const int face_i : range) {
@ -1519,6 +1644,7 @@ static void bm_to_mesh_faces(const BMesh &bm,
static void bm_to_mesh_loops(const BMesh &bm, const Span<const BMLoop *> bm_loops, Mesh &mesh) static void bm_to_mesh_loops(const BMesh &bm, const Span<const BMLoop *> bm_loops, Mesh &mesh)
{ {
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.ldata, mesh.ldata);
MutableSpan<MLoop> dst_loops = mesh.loops_for_write(); MutableSpan<MLoop> dst_loops = mesh.loops_for_write();
threading::parallel_for(dst_loops.index_range(), 1024, [&](const IndexRange range) { threading::parallel_for(dst_loops.index_range(), 1024, [&](const IndexRange range) {
for (const int loop_i : range) { for (const int loop_i : range) {
@ -1526,7 +1652,7 @@ static void bm_to_mesh_loops(const BMesh &bm, const Span<const BMLoop *> bm_loop
MLoop &dst_loop = dst_loops[loop_i]; MLoop &dst_loop = dst_loops[loop_i];
dst_loop.v = BM_elem_index_get(src_loop.v); dst_loop.v = BM_elem_index_get(src_loop.v);
dst_loop.e = BM_elem_index_get(src_loop.e); dst_loop.e = BM_elem_index_get(src_loop.e);
CustomData_from_bmesh_block(&bm.ldata, &mesh.ldata, src_loop.head.data, loop_i); bmesh_block_copy_to_mesh_attributes(info, loop_i, src_loop.head.data);
} }
}); });
} }