forked from blender/blender
main sync #3
@ -85,6 +85,7 @@
|
||||
#include "BLI_span.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_task.hh"
|
||||
#include "BLI_timeit.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
@ -949,23 +950,6 @@ static void bm_to_mesh_shape(BMesh *bm,
|
||||
|
||||
/** \} */
|
||||
|
||||
template<typename T, typename GetFn>
|
||||
static void write_fn_to_attribute(blender::bke::MutableAttributeAccessor attributes,
|
||||
const StringRef attribute_name,
|
||||
const eAttrDomain domain,
|
||||
const GetFn &get_fn)
|
||||
{
|
||||
using namespace blender;
|
||||
bke::SpanAttributeWriter<T> attribute = attributes.lookup_or_add_for_write_only_span<T>(
|
||||
attribute_name, domain);
|
||||
threading::parallel_for(attribute.span.index_range(), 4096, [&](IndexRange range) {
|
||||
for (const int i : range) {
|
||||
attribute.span[i] = get_fn(i);
|
||||
}
|
||||
});
|
||||
attribute.finish();
|
||||
}
|
||||
|
||||
static void assert_bmesh_has_no_mesh_only_attributes(const BMesh &bm)
|
||||
{
|
||||
(void)bm; /* Unused in the release builds. */
|
||||
@ -981,68 +965,70 @@ static void assert_bmesh_has_no_mesh_only_attributes(const BMesh &bm)
|
||||
BLI_assert(CustomData_get_layer_named(&bm.pdata, CD_PROP_BOOL, ".select_poly") == nullptr);
|
||||
}
|
||||
|
||||
static void convert_bmesh_hide_flags_to_mesh_attributes(BMesh &bm,
|
||||
const bool need_hide_vert,
|
||||
const bool need_hide_edge,
|
||||
const bool need_hide_poly,
|
||||
Mesh &mesh)
|
||||
static void bmesh_to_mesh_calc_object_remap(Main &bmain,
|
||||
Mesh &me,
|
||||
BMesh &bm,
|
||||
const int old_totvert)
|
||||
{
|
||||
using namespace blender;
|
||||
/* The "hide" attributes are stored as flags on #BMesh. */
|
||||
assert_bmesh_has_no_mesh_only_attributes(bm);
|
||||
BMVert **vertMap = nullptr;
|
||||
BMVert *eve;
|
||||
|
||||
if (!(need_hide_vert || need_hide_edge || need_hide_poly)) {
|
||||
return;
|
||||
LISTBASE_FOREACH (Object *, ob, &bmain.objects) {
|
||||
if ((ob->parent) && (ob->parent->data == &me) && ELEM(ob->partype, PARVERT1, PARVERT3)) {
|
||||
|
||||
if (vertMap == nullptr) {
|
||||
vertMap = bm_to_mesh_vertex_map(&bm, old_totvert);
|
||||
}
|
||||
|
||||
bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
|
||||
BM_mesh_elem_table_ensure(&bm, BM_VERT | BM_EDGE | BM_FACE);
|
||||
if (ob->par1 < old_totvert) {
|
||||
eve = vertMap[ob->par1];
|
||||
if (eve) {
|
||||
ob->par1 = BM_elem_index_get(eve);
|
||||
}
|
||||
}
|
||||
if (ob->par2 < old_totvert) {
|
||||
eve = vertMap[ob->par2];
|
||||
if (eve) {
|
||||
ob->par2 = BM_elem_index_get(eve);
|
||||
}
|
||||
}
|
||||
if (ob->par3 < old_totvert) {
|
||||
eve = vertMap[ob->par3];
|
||||
if (eve) {
|
||||
ob->par3 = BM_elem_index_get(eve);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ob->data == &me) {
|
||||
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
|
||||
if (md->type == eModifierType_Hook) {
|
||||
HookModifierData *hmd = (HookModifierData *)md;
|
||||
|
||||
if (need_hide_vert) {
|
||||
write_fn_to_attribute<bool>(attributes, ".hide_vert", ATTR_DOMAIN_POINT, [&](const int i) {
|
||||
return BM_elem_flag_test(BM_vert_at_index(&bm, i), BM_ELEM_HIDDEN);
|
||||
});
|
||||
if (vertMap == nullptr) {
|
||||
vertMap = bm_to_mesh_vertex_map(&bm, old_totvert);
|
||||
}
|
||||
if (need_hide_edge) {
|
||||
write_fn_to_attribute<bool>(attributes, ".hide_edge", ATTR_DOMAIN_EDGE, [&](const int i) {
|
||||
return BM_elem_flag_test(BM_edge_at_index(&bm, i), BM_ELEM_HIDDEN);
|
||||
});
|
||||
int i, j;
|
||||
for (i = j = 0; i < hmd->indexar_num; i++) {
|
||||
if (hmd->indexar[i] < old_totvert) {
|
||||
eve = vertMap[hmd->indexar[i]];
|
||||
|
||||
if (eve) {
|
||||
hmd->indexar[j++] = BM_elem_index_get(eve);
|
||||
}
|
||||
if (need_hide_poly) {
|
||||
write_fn_to_attribute<bool>(attributes, ".hide_poly", ATTR_DOMAIN_FACE, [&](const int i) {
|
||||
return BM_elem_flag_test(BM_face_at_index(&bm, i), BM_ELEM_HIDDEN);
|
||||
});
|
||||
}
|
||||
else {
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
static void convert_bmesh_selection_flags_to_mesh_attributes(BMesh &bm,
|
||||
const bool need_select_vert,
|
||||
const bool need_select_edge,
|
||||
const bool need_select_poly,
|
||||
Mesh &mesh)
|
||||
{
|
||||
using namespace blender;
|
||||
if (!(need_select_vert || need_select_edge || need_select_poly)) {
|
||||
return;
|
||||
hmd->indexar_num = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
|
||||
BM_mesh_elem_table_ensure(&bm, BM_VERT | BM_EDGE | BM_FACE);
|
||||
|
||||
if (need_select_vert) {
|
||||
write_fn_to_attribute<bool>(attributes, ".select_vert", ATTR_DOMAIN_POINT, [&](const int i) {
|
||||
return BM_elem_flag_test(BM_vert_at_index(&bm, i), BM_ELEM_SELECT);
|
||||
});
|
||||
}
|
||||
if (need_select_edge) {
|
||||
write_fn_to_attribute<bool>(attributes, ".select_edge", ATTR_DOMAIN_EDGE, [&](const int i) {
|
||||
return BM_elem_flag_test(BM_edge_at_index(&bm, i), BM_ELEM_SELECT);
|
||||
});
|
||||
}
|
||||
if (need_select_poly) {
|
||||
write_fn_to_attribute<bool>(attributes, ".select_poly", ATTR_DOMAIN_FACE, [&](const int i) {
|
||||
return BM_elem_flag_test(BM_face_at_index(&bm, i), BM_ELEM_SELECT);
|
||||
});
|
||||
if (vertMap) {
|
||||
MEM_freeN(vertMap);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1110,6 +1096,7 @@ static void bm_vert_table_build(BMesh &bm,
|
||||
BM_elem_index_set(vert, i); /* set_inline */
|
||||
table[i] = vert;
|
||||
hflag |= vert->head.hflag;
|
||||
BM_CHECK_ELEMENT(vert);
|
||||
}
|
||||
need_select_vert = (hflag & BM_ELEM_SELECT) != 0;
|
||||
need_hide_vert = (hflag & BM_ELEM_HIDDEN) != 0;
|
||||
@ -1130,6 +1117,7 @@ static void bm_edge_table_build(BMesh &bm,
|
||||
BM_elem_index_set(edge, i); /* set_inline */
|
||||
table[i] = edge;
|
||||
hflag |= edge->head.hflag;
|
||||
BM_CHECK_ELEMENT(edge);
|
||||
}
|
||||
need_select_edge = (hflag & BM_ELEM_SELECT) != 0;
|
||||
need_hide_edge = (hflag & BM_ELEM_HIDDEN) != 0;
|
||||
@ -1156,11 +1144,13 @@ static void bm_face_loop_table_build(BMesh &bm,
|
||||
hflag |= face->head.hflag;
|
||||
need_sharp_face |= (face->head.hflag & BM_ELEM_SMOOTH) == 0;
|
||||
need_material_index |= face->mat_nr != 0;
|
||||
BM_CHECK_ELEMENT(face);
|
||||
|
||||
BMLoop *loop = BM_FACE_FIRST_LOOP(face);
|
||||
for ([[maybe_unused]] const int i : IndexRange(face->len)) {
|
||||
BM_elem_index_set(loop, loop_i); /* set_inline */
|
||||
loop_table[loop_i] = loop;
|
||||
BM_CHECK_ELEMENT(loop);
|
||||
loop = loop->next;
|
||||
loop_i++;
|
||||
}
|
||||
@ -1186,6 +1176,8 @@ static void bm_to_mesh_verts(const BMesh &bm,
|
||||
MutableSpan<bool> select_vert,
|
||||
MutableSpan<bool> hide_vert)
|
||||
{
|
||||
CustomData_add_layer_named(
|
||||
&mesh.vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, mesh.totvert, "position");
|
||||
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.vdata, mesh.vdata);
|
||||
MutableSpan<float3> dst_vert_positions = mesh.vert_positions_for_write();
|
||||
threading::parallel_for(dst_vert_positions.index_range(), 1024, [&](const IndexRange range) {
|
||||
@ -1215,6 +1207,7 @@ static void bm_to_mesh_edges(const BMesh &bm,
|
||||
MutableSpan<bool> sharp_edge,
|
||||
MutableSpan<bool> uv_seams)
|
||||
{
|
||||
CustomData_add_layer(&mesh.edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, mesh.totedge);
|
||||
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.edata, mesh.edata);
|
||||
MutableSpan<MEdge> dst_edges = mesh.edges_for_write();
|
||||
threading::parallel_for(dst_edges.index_range(), 512, [&](const IndexRange range) {
|
||||
@ -1256,6 +1249,7 @@ static void bm_to_mesh_faces(const BMesh &bm,
|
||||
MutableSpan<bool> sharp_faces,
|
||||
MutableSpan<int> material_indices)
|
||||
{
|
||||
CustomData_add_layer(&mesh.pdata, CD_MPOLY, CD_CONSTRUCT, nullptr, mesh.totpoly);
|
||||
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.pdata, mesh.pdata);
|
||||
MutableSpan<MPoly> dst_polys = mesh.polys_for_write();
|
||||
threading::parallel_for(dst_polys.index_range(), 1024, [&](const IndexRange range) {
|
||||
@ -1291,6 +1285,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)
|
||||
{
|
||||
CustomData_add_layer(&mesh.ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, mesh.totloop);
|
||||
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.ldata, mesh.ldata);
|
||||
MutableSpan<MLoop> dst_loops = mesh.loops_for_write();
|
||||
threading::parallel_for(dst_loops.index_range(), 1024, [&](const IndexRange range) {
|
||||
@ -1309,13 +1304,8 @@ static void bm_to_mesh_loops(const BMesh &bm, const Span<const BMLoop *> bm_loop
|
||||
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
|
||||
{
|
||||
using namespace blender;
|
||||
BMVert *v, *eve;
|
||||
BMEdge *e;
|
||||
BMFace *f;
|
||||
BMIter iter;
|
||||
int i, j;
|
||||
|
||||
const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
|
||||
|
||||
const int ototvert = me->totvert;
|
||||
|
||||
@ -1333,11 +1323,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
||||
/* Add new custom data. */
|
||||
me->totvert = bm->totvert;
|
||||
me->totedge = bm->totedge;
|
||||
me->totface = 0;
|
||||
me->totloop = bm->totloop;
|
||||
me->totpoly = bm->totface;
|
||||
/* Will be overwritten with a valid value if 'dotess' is set, otherwise we
|
||||
* end up with 'me->totface' and `me->mface == nullptr` which can crash #28625. */
|
||||
me->totface = 0;
|
||||
me->act_face = -1;
|
||||
|
||||
/* Mark UV selection layers which are all false as 'nocopy'. */
|
||||
@ -1418,26 +1406,6 @@ 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);
|
||||
}
|
||||
|
||||
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 */
|
||||
for (const int i : ldata_layers_marked_nocopy) {
|
||||
bm->ldata.layers[i].flag &= ~CD_FLAG_NOCOPY;
|
||||
}
|
||||
|
||||
CustomData_add_layer_named(
|
||||
&me->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, me->totvert, "position");
|
||||
CustomData_add_layer(&me->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, me->totedge);
|
||||
CustomData_add_layer(&me->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, me->totloop);
|
||||
CustomData_add_layer(&me->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, me->totpoly);
|
||||
MutableSpan<float3> positions = me->vert_positions_for_write();
|
||||
MutableSpan<MEdge> edges = me->edges_for_write();
|
||||
MutableSpan<MPoly> polys = me->polys_for_write();
|
||||
MutableSpan<MLoop> mloop = me->loops_for_write();
|
||||
|
||||
bool need_select_vert = false;
|
||||
bool need_select_edge = false;
|
||||
bool need_select_poly = false;
|
||||
@ -1445,199 +1413,129 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
||||
bool need_hide_edge = false;
|
||||
bool need_hide_poly = false;
|
||||
bool need_material_index = false;
|
||||
bool need_sharp_face = false;
|
||||
bool need_sharp_edge = false;
|
||||
bool need_uv_seam = false;
|
||||
bool need_sharp_face = false;
|
||||
bool need_uv_seams = false;
|
||||
Array<const BMVert *> vert_table;
|
||||
Array<const BMEdge *> edge_table;
|
||||
Array<const BMFace *> face_table;
|
||||
Array<const BMLoop *> loop_table;
|
||||
threading::parallel_invoke(
|
||||
me->totface > 1024,
|
||||
[&]() {
|
||||
vert_table.reinitialize(bm->totvert);
|
||||
bm_vert_table_build(*bm, vert_table, need_select_vert, need_hide_vert);
|
||||
},
|
||||
[&]() {
|
||||
edge_table.reinitialize(bm->totedge);
|
||||
bm_edge_table_build(
|
||||
*bm, edge_table, need_select_edge, need_hide_edge, need_sharp_edge, need_uv_seams);
|
||||
},
|
||||
[&]() {
|
||||
face_table.reinitialize(bm->totface);
|
||||
loop_table.reinitialize(bm->totloop);
|
||||
bm_face_loop_table_build(*bm,
|
||||
face_table,
|
||||
loop_table,
|
||||
need_select_poly,
|
||||
need_hide_poly,
|
||||
need_sharp_face,
|
||||
need_material_index);
|
||||
});
|
||||
bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE | BM_LOOP);
|
||||
|
||||
i = 0;
|
||||
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
copy_v3_v3(positions[i], v->co);
|
||||
|
||||
if (BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
|
||||
need_hide_vert = true;
|
||||
/* Add optional mesh attributes before parallel iteration. */
|
||||
assert_bmesh_has_no_mesh_only_attributes(*bm);
|
||||
bke::MutableAttributeAccessor attrs = me->attributes_for_write();
|
||||
bke::SpanAttributeWriter<bool> select_vert;
|
||||
bke::SpanAttributeWriter<bool> hide_vert;
|
||||
bke::SpanAttributeWriter<bool> select_edge;
|
||||
bke::SpanAttributeWriter<bool> hide_edge;
|
||||
bke::SpanAttributeWriter<bool> sharp_edge;
|
||||
bke::SpanAttributeWriter<bool> uv_seams;
|
||||
bke::SpanAttributeWriter<bool> select_poly;
|
||||
bke::SpanAttributeWriter<bool> hide_poly;
|
||||
bke::SpanAttributeWriter<bool> sharp_face;
|
||||
bke::SpanAttributeWriter<int> material_index;
|
||||
if (need_select_vert) {
|
||||
select_vert = attrs.lookup_or_add_for_write_only_span<bool>(".select_vert", ATTR_DOMAIN_POINT);
|
||||
}
|
||||
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
|
||||
need_select_vert = true;
|
||||
if (need_hide_vert) {
|
||||
hide_vert = attrs.lookup_or_add_for_write_only_span<bool>(".hide_vert", ATTR_DOMAIN_POINT);
|
||||
}
|
||||
|
||||
BM_elem_index_set(v, i); /* set_inline */
|
||||
|
||||
bmesh_block_copy_to_mesh_attributes(vert_info, i, v->head.data);
|
||||
|
||||
i++;
|
||||
|
||||
BM_CHECK_ELEMENT(v);
|
||||
}
|
||||
bm->elem_index_dirty &= ~BM_VERT;
|
||||
|
||||
i = 0;
|
||||
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
|
||||
edges[i].v1 = BM_elem_index_get(e->v1);
|
||||
edges[i].v2 = BM_elem_index_get(e->v2);
|
||||
|
||||
if (BM_elem_flag_test(e, BM_ELEM_SEAM)) {
|
||||
need_uv_seam = true;
|
||||
}
|
||||
if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
|
||||
need_hide_edge = true;
|
||||
}
|
||||
if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
|
||||
need_select_edge = true;
|
||||
}
|
||||
if (!BM_elem_flag_test(e, BM_ELEM_SMOOTH)) {
|
||||
need_sharp_edge = true;
|
||||
}
|
||||
|
||||
BM_elem_index_set(e, i); /* set_inline */
|
||||
|
||||
bmesh_block_copy_to_mesh_attributes(edge_info, i, e->head.data);
|
||||
|
||||
i++;
|
||||
BM_CHECK_ELEMENT(e);
|
||||
}
|
||||
bm->elem_index_dirty &= ~BM_EDGE;
|
||||
|
||||
i = 0;
|
||||
j = 0;
|
||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||
BMLoop *l_iter, *l_first;
|
||||
polys[i].loopstart = j;
|
||||
polys[i].totloop = f->len;
|
||||
if (f->mat_nr != 0) {
|
||||
need_material_index = true;
|
||||
}
|
||||
if (!BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
|
||||
need_sharp_face = true;
|
||||
}
|
||||
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
|
||||
need_hide_poly = true;
|
||||
}
|
||||
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
|
||||
need_select_poly = true;
|
||||
}
|
||||
|
||||
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
||||
do {
|
||||
mloop[j].e = BM_elem_index_get(l_iter->e);
|
||||
mloop[j].v = BM_elem_index_get(l_iter->v);
|
||||
|
||||
bmesh_block_copy_to_mesh_attributes(loop_info, j, l_iter->head.data);
|
||||
|
||||
j++;
|
||||
BM_CHECK_ELEMENT(l_iter);
|
||||
BM_CHECK_ELEMENT(l_iter->e);
|
||||
BM_CHECK_ELEMENT(l_iter->v);
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
|
||||
if (f == bm->act_face) {
|
||||
me->act_face = i;
|
||||
}
|
||||
|
||||
bmesh_block_copy_to_mesh_attributes(poly_info, i, f->head.data);
|
||||
|
||||
i++;
|
||||
BM_CHECK_ELEMENT(f);
|
||||
}
|
||||
|
||||
if (need_material_index) {
|
||||
BM_mesh_elem_table_ensure(bm, BM_FACE);
|
||||
write_fn_to_attribute<int>(me->attributes_for_write(),
|
||||
"material_index",
|
||||
ATTR_DOMAIN_FACE,
|
||||
[&](const int i) { return int(BM_face_at_index(bm, i)->mat_nr); });
|
||||
if (need_select_edge) {
|
||||
select_edge = attrs.lookup_or_add_for_write_only_span<bool>(".select_edge", ATTR_DOMAIN_EDGE);
|
||||
}
|
||||
if (need_sharp_edge) {
|
||||
BM_mesh_elem_table_ensure(bm, BM_EDGE);
|
||||
write_fn_to_attribute<bool>(
|
||||
me->attributes_for_write(), "sharp_edge", ATTR_DOMAIN_EDGE, [&](const int i) {
|
||||
return !BM_elem_flag_test(BM_edge_at_index(bm, i), BM_ELEM_SMOOTH);
|
||||
});
|
||||
sharp_edge = attrs.lookup_or_add_for_write_only_span<bool>("sharp_edge", ATTR_DOMAIN_EDGE);
|
||||
}
|
||||
if (need_uv_seams) {
|
||||
uv_seams = attrs.lookup_or_add_for_write_only_span<bool>(".uv_seam", ATTR_DOMAIN_EDGE);
|
||||
}
|
||||
if (need_hide_edge) {
|
||||
hide_edge = attrs.lookup_or_add_for_write_only_span<bool>(".hide_edge", ATTR_DOMAIN_EDGE);
|
||||
}
|
||||
if (need_select_poly) {
|
||||
select_poly = attrs.lookup_or_add_for_write_only_span<bool>(".select_poly", ATTR_DOMAIN_FACE);
|
||||
}
|
||||
if (need_hide_poly) {
|
||||
hide_poly = attrs.lookup_or_add_for_write_only_span<bool>(".hide_poly", ATTR_DOMAIN_FACE);
|
||||
}
|
||||
if (need_sharp_face) {
|
||||
BM_mesh_elem_table_ensure(bm, BM_FACE);
|
||||
write_fn_to_attribute<bool>(
|
||||
me->attributes_for_write(), "sharp_face", ATTR_DOMAIN_FACE, [&](const int i) {
|
||||
return !BM_elem_flag_test(BM_face_at_index(bm, i), BM_ELEM_SMOOTH);
|
||||
});
|
||||
sharp_face = attrs.lookup_or_add_for_write_only_span<bool>("sharp_face", ATTR_DOMAIN_FACE);
|
||||
}
|
||||
if (need_uv_seam) {
|
||||
BM_mesh_elem_table_ensure(bm, BM_EDGE);
|
||||
write_fn_to_attribute<bool>(
|
||||
me->attributes_for_write(), ".uv_seam", ATTR_DOMAIN_EDGE, [&](const int i) {
|
||||
return BM_elem_flag_test(BM_edge_at_index(bm, i), BM_ELEM_SEAM);
|
||||
});
|
||||
if (need_material_index) {
|
||||
material_index = attrs.lookup_or_add_for_write_only_span<int>("material_index",
|
||||
ATTR_DOMAIN_FACE);
|
||||
}
|
||||
|
||||
/* Loop over all elements in parallel, copying attributes and building the Mesh topology. */
|
||||
threading::parallel_invoke(
|
||||
me->totvert > 1024,
|
||||
[&]() {
|
||||
bm_to_mesh_verts(*bm, vert_table, *me, select_vert.span, hide_vert.span);
|
||||
if (me->key) {
|
||||
bm_to_mesh_shape(
|
||||
bm, me->key, me->vert_positions_for_write(), params->active_shapekey_to_mvert);
|
||||
}
|
||||
},
|
||||
[&]() {
|
||||
bm_to_mesh_edges(*bm,
|
||||
edge_table,
|
||||
*me,
|
||||
select_edge.span,
|
||||
hide_edge.span,
|
||||
sharp_edge.span,
|
||||
uv_seams.span);
|
||||
},
|
||||
[&]() {
|
||||
bm_to_mesh_faces(*bm,
|
||||
face_table,
|
||||
*me,
|
||||
select_poly.span,
|
||||
hide_poly.span,
|
||||
sharp_face.span,
|
||||
material_index.span);
|
||||
if (bm->act_face) {
|
||||
me->act_face = BM_elem_index_get(bm->act_face);
|
||||
}
|
||||
},
|
||||
[&]() {
|
||||
bm_to_mesh_loops(*bm, loop_table, *me);
|
||||
/* Topology could be changed, ensure #CD_MDISPS are ok. */
|
||||
multires_topology_changed(me);
|
||||
/* Clear the CD_FLAG_NOCOPY flags for the layers they were temporarily set on */
|
||||
for (const int i : ldata_layers_marked_nocopy) {
|
||||
bm->ldata.layers[i].flag &= ~CD_FLAG_NOCOPY;
|
||||
}
|
||||
},
|
||||
[&]() {
|
||||
/* Patch hook indices and vertex parents. */
|
||||
if (params->calc_object_remap && (ototvert > 0)) {
|
||||
BLI_assert(bmain != nullptr);
|
||||
BMVert **vertMap = nullptr;
|
||||
|
||||
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
|
||||
if ((ob->parent) && (ob->parent->data == me) && ELEM(ob->partype, PARVERT1, PARVERT3)) {
|
||||
|
||||
if (vertMap == nullptr) {
|
||||
vertMap = bm_to_mesh_vertex_map(bm, ototvert);
|
||||
bmesh_to_mesh_calc_object_remap(*bmain, *me, *bm, ototvert);
|
||||
}
|
||||
|
||||
if (ob->par1 < ototvert) {
|
||||
eve = vertMap[ob->par1];
|
||||
if (eve) {
|
||||
ob->par1 = BM_elem_index_get(eve);
|
||||
}
|
||||
}
|
||||
if (ob->par2 < ototvert) {
|
||||
eve = vertMap[ob->par2];
|
||||
if (eve) {
|
||||
ob->par2 = BM_elem_index_get(eve);
|
||||
}
|
||||
}
|
||||
if (ob->par3 < ototvert) {
|
||||
eve = vertMap[ob->par3];
|
||||
if (eve) {
|
||||
ob->par3 = BM_elem_index_get(eve);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ob->data == me) {
|
||||
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
|
||||
if (md->type == eModifierType_Hook) {
|
||||
HookModifierData *hmd = (HookModifierData *)md;
|
||||
|
||||
if (vertMap == nullptr) {
|
||||
vertMap = bm_to_mesh_vertex_map(bm, ototvert);
|
||||
}
|
||||
|
||||
for (i = j = 0; i < hmd->indexar_num; i++) {
|
||||
if (hmd->indexar[i] < ototvert) {
|
||||
eve = vertMap[hmd->indexar[i]];
|
||||
|
||||
if (eve) {
|
||||
hmd->indexar[j++] = BM_elem_index_get(eve);
|
||||
}
|
||||
}
|
||||
else {
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
hmd->indexar_num = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vertMap) {
|
||||
MEM_freeN(vertMap);
|
||||
}
|
||||
}
|
||||
|
||||
convert_bmesh_hide_flags_to_mesh_attributes(
|
||||
*bm, need_hide_vert, need_hide_edge, need_hide_poly, *me);
|
||||
convert_bmesh_selection_flags_to_mesh_attributes(
|
||||
*bm, need_select_vert, need_select_edge, need_select_poly, *me);
|
||||
|
||||
{
|
||||
},
|
||||
[&]() {
|
||||
me->totselect = BLI_listbase_count(&(bm->selected));
|
||||
|
||||
MEM_SAFE_FREE(me->mselect);
|
||||
@ -1645,7 +1543,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
||||
me->mselect = static_cast<MSelect *>(
|
||||
MEM_mallocN(sizeof(MSelect) * me->totselect, "Mesh selection history"));
|
||||
}
|
||||
|
||||
int i;
|
||||
LISTBASE_FOREACH_INDEX (BMEditSelection *, selected, &bm->selected, i) {
|
||||
if (selected->htype == BM_VERT) {
|
||||
me->mselect[i].type = ME_VSEL;
|
||||
@ -1659,25 +1557,36 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
||||
|
||||
me->mselect[i].index = BM_elem_index_get(selected->ele);
|
||||
}
|
||||
}
|
||||
|
||||
if (me->key) {
|
||||
bm_to_mesh_shape(bm, me->key, positions, params->active_shapekey_to_mvert);
|
||||
}
|
||||
|
||||
/* Run this even when shape keys aren't used since it may be used for hooks or vertex parents. */
|
||||
},
|
||||
[&]() {
|
||||
/* Run this even when shape keys aren't used since it may be used for hooks or vertex
|
||||
* parents. */
|
||||
if (params->update_shapekey_indices) {
|
||||
/* We have written a new shape key, if this mesh is _not_ going to be freed,
|
||||
* update the shape key indices to match the newly updated. */
|
||||
const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata,
|
||||
CD_SHAPE_KEYINDEX);
|
||||
if (cd_shape_keyindex_offset != -1) {
|
||||
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
|
||||
BM_ELEM_CD_SET_INT(eve, cd_shape_keyindex_offset, i);
|
||||
BMIter iter;
|
||||
BMVert *vert;
|
||||
int i;
|
||||
BM_ITER_MESH_INDEX (vert, &iter, bm, BM_VERTS_OF_MESH, i) {
|
||||
BM_ELEM_CD_SET_INT(vert, cd_shape_keyindex_offset, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/* Topology could be changed, ensure #CD_MDISPS are ok. */
|
||||
multires_topology_changed(me);
|
||||
select_vert.finish();
|
||||
hide_vert.finish();
|
||||
select_edge.finish();
|
||||
hide_edge.finish();
|
||||
sharp_edge.finish();
|
||||
uv_seams.finish();
|
||||
select_poly.finish();
|
||||
hide_poly.finish();
|
||||
sharp_face.finish();
|
||||
material_index.finish();
|
||||
}
|
||||
|
||||
/* NOTE: The function is called from multiple threads with the same input BMesh and different
|
||||
@ -1698,14 +1607,6 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
|
||||
me->totloop = bm->totloop;
|
||||
me->totpoly = bm->totface;
|
||||
|
||||
if (!CustomData_get_layer_named(&me->vdata, CD_PROP_FLOAT3, "position")) {
|
||||
CustomData_add_layer_named(
|
||||
&me->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, bm->totvert, "position");
|
||||
}
|
||||
CustomData_add_layer(&me->edata, CD_MEDGE, CD_CONSTRUCT, nullptr, bm->totedge);
|
||||
CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CONSTRUCT, nullptr, bm->totloop);
|
||||
CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CONSTRUCT, nullptr, bm->totface);
|
||||
|
||||
/* Don't process shape-keys, we only feed them through the modifier stack as needed,
|
||||
* e.g. for applying modifiers or the like. */
|
||||
CustomData_MeshMasks mask = CD_MASK_DERIVEDMESH;
|
||||
|
Loading…
Reference in New Issue
Block a user