Mesh: Move edge UV seams to a generic attribute

As part of #95966, move the `ME_SEAM` flag on mesh edges
to a generic boolean attribute, called `.uv_seam`. This is the
last bit of extra information stored in mesh edges. After this
is committed we can switch to a different type for them and
have a 1/3 improvement in memory consumption.

It is also now possible to see that a mesh has no UV seams in
constant time, and like other similar refactors, interacting with
only the UV seams can be done with less memory.

The attribute name starts with a `.` to signify that the attribute,
like face sets, isn't meant to be used in arbitrary procedural
situations (with geometry nodes for example). That gives us more
freedom to change things in the future.

Pull Request #104728
This commit is contained in:
Hans Goudey 2023-03-01 14:13:05 +01:00 committed by Hans Goudey
parent 66c9c19466
commit cccf91ff83
24 changed files with 212 additions and 156 deletions

View File

@ -99,6 +99,9 @@ void BKE_mesh_legacy_attribute_strings_to_flags(struct Mesh *mesh);
void BKE_mesh_legacy_sharp_edges_to_flags(struct Mesh *mesh);
void BKE_mesh_legacy_sharp_edges_from_flags(struct Mesh *mesh);
void BKE_mesh_legacy_uv_seam_to_flags(struct Mesh *mesh);
void BKE_mesh_legacy_uv_seam_from_flags(struct Mesh *mesh);
struct MVert *BKE_mesh_legacy_convert_positions_to_verts(
Mesh *mesh,
blender::ResourceScope &temp_arrays_for_convert,

View File

@ -260,6 +260,7 @@ typedef bool (*MeshRemapIslandsCalc)(const float (*vert_positions)[3],
int totvert,
const struct MEdge *edges,
int totedge,
const bool *uv_seams,
const struct MPoly *polys,
int totpoly,
const struct MLoop *loops,
@ -277,6 +278,7 @@ bool BKE_mesh_calc_islands_loop_poly_edgeseam(const float (*vert_positions)[3],
int totvert,
const struct MEdge *edges,
int totedge,
const bool *uv_seams,
const struct MPoly *polys,
int totpoly,
const struct MLoop *loops,
@ -300,6 +302,7 @@ bool BKE_mesh_calc_islands_loop_poly_uvmap(float (*vert_positions)[3],
int totvert,
struct MEdge *edges,
int totedge,
const bool *uv_seams,
struct MPoly *polys,
int totpoly,
struct MLoop *loops,

View File

@ -95,7 +95,6 @@ typedef struct CCGDerivedMesh {
struct CCGFace *face;
} * faceMap;
short *edgeFlags;
struct DMFlagMat *faceFlags;
int *reverseFaceMap;

View File

@ -1005,26 +1005,21 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map,
return true;
}
if (r_map && cddata_type == CD_FAKE_SEAM) {
const size_t elem_size = sizeof(*((MEdge *)nullptr));
const size_t data_size = sizeof(((MEdge *)nullptr)->flag);
const size_t data_offset = offsetof(MEdge, flag);
const uint64_t data_flag = ME_SEAM;
data_transfer_layersmapping_add_item(r_map,
cddata_type,
mix_mode,
mix_factor,
mix_weights,
BKE_mesh_edges(me_src),
BKE_mesh_edges_for_write(me_dst),
me_src->totedge,
me_dst->totedge,
elem_size,
data_size,
data_offset,
data_flag,
nullptr,
interp_data);
if (!CustomData_get_layer_named(&me_dst->edata, CD_PROP_BOOL, ".uv_seam")) {
CustomData_add_layer_named(
&me_dst->edata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, me_dst->totedge, ".uv_seam");
}
data_transfer_layersmapping_add_item_cd(
r_map,
CD_PROP_BOOL,
mix_mode,
mix_factor,
mix_weights,
CustomData_get_layer_named(&me_src->edata, CD_PROP_BOOL, ".uv_seam"),
CustomData_get_layer_named_for_write(
&me_dst->edata, CD_PROP_BOOL, ".uv_seam", me_dst->totedge),
interp,
interp_data);
return true;
}
if (r_map && cddata_type == CD_FAKE_SHARP) {

View File

@ -2496,6 +2496,7 @@ static void gpencil_generate_edgeloops(Object *ob,
const bool use_seams,
const bool use_vgroups)
{
using namespace blender;
Mesh *me = (Mesh *)ob->data;
if (me->totedge == 0) {
return;
@ -2504,6 +2505,9 @@ static void gpencil_generate_edgeloops(Object *ob,
const Span<MEdge> edges = me->edges();
const Span<MDeformVert> dverts = me->deform_verts();
const float(*vert_normals)[3] = BKE_mesh_vert_normals_ensure(me);
const bke::AttributeAccessor attributes = me->attributes();
const VArray<bool> uv_seams = attributes.lookup_or_default<bool>(
".uv_seam", ATTR_DOMAIN_EDGE, false);
/* Arrays for all edge vertices (forward and backward) that form a edge loop.
* This is reused for each edge-loop to create gpencil stroke. */
@ -2529,7 +2533,7 @@ static void gpencil_generate_edgeloops(Object *ob,
sub_v3_v3v3(gped->vec, vert_positions[ed->v1], vert_positions[ed->v2]);
/* If use seams, mark as done if not a seam. */
if ((use_seams) && ((ed->flag & ME_SEAM) == 0)) {
if ((use_seams) && !uv_seams[i]) {
gped->flag = 1;
}
}

View File

@ -272,6 +272,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
BKE_mesh_legacy_bevel_weight_from_layers(mesh);
BKE_mesh_legacy_edge_crease_from_layers(mesh);
BKE_mesh_legacy_sharp_edges_to_flags(mesh);
BKE_mesh_legacy_uv_seam_to_flags(mesh);
BKE_mesh_legacy_attribute_strings_to_flags(mesh);
mesh->active_color_attribute = nullptr;
mesh->default_color_attribute = nullptr;

View File

@ -104,9 +104,9 @@ class MeshesToIMeshInfo {
void input_mvert_for_orig_index(int orig_index,
const Mesh **r_orig_mesh,
int *r_index_in_orig_mesh) const;
const MEdge *input_medge_for_orig_index(int orig_index,
const Mesh **r_orig_mesh,
int *r_index_in_orig_mesh) const;
void input_medge_for_orig_index(int orig_index,
const Mesh **r_orig_mesh,
int *r_index_in_orig_mesh) const;
};
/* Given an index `imesh_v` in the `IMesh`, return the index of the
@ -199,24 +199,21 @@ void MeshesToIMeshInfo::input_mvert_for_orig_index(int orig_index,
}
/* Similarly for edges. */
const MEdge *MeshesToIMeshInfo::input_medge_for_orig_index(int orig_index,
const Mesh **r_orig_mesh,
int *r_index_in_orig_mesh) const
void MeshesToIMeshInfo::input_medge_for_orig_index(int orig_index,
const Mesh **r_orig_mesh,
int *r_index_in_orig_mesh) const
{
int orig_mesh_index = input_mesh_for_imesh_edge(orig_index);
BLI_assert(0 <= orig_mesh_index && orig_mesh_index < meshes.size());
const Mesh *me = meshes[orig_mesh_index];
const Span<MEdge> edges = me->edges();
int index_in_mesh = orig_index - mesh_edge_offset[orig_mesh_index];
BLI_assert(0 <= index_in_mesh && index_in_mesh < me->totedge);
const MEdge *medge = &edges[index_in_mesh];
if (r_orig_mesh) {
*r_orig_mesh = me;
}
if (r_index_in_orig_mesh) {
*r_index_in_orig_mesh = index_in_mesh;
}
return medge;
}
/**
@ -434,13 +431,10 @@ static void copy_poly_attributes(Mesh *dest_mesh,
/* Similar to copy_vert_attributes but for edge attributes. */
static void copy_edge_attributes(Mesh *dest_mesh,
MEdge *medge,
const MEdge *orig_medge,
const Mesh *orig_me,
int medge_index,
int index_in_orig_me)
{
medge->flag = orig_medge->flag;
CustomData *target_cd = &dest_mesh->edata;
const CustomData *source_cd = &orig_me->edata;
for (int source_layer_i = 0; source_layer_i < source_cd->totlayer; ++source_layer_i) {
@ -777,7 +771,6 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
/* Now that the MEdges are populated, we can copy over the required attributes and custom layers.
*/
MutableSpan<MEdge> edges = result->edges_for_write();
for (int fi : im->face_index_range()) {
const Face *f = im->face(fi);
const MPoly *mp = &dst_polys[fi];
@ -785,11 +778,9 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
if (f->edge_orig[j] != NO_INDEX) {
const Mesh *orig_me;
int index_in_orig_me;
const MEdge *orig_medge = mim.input_medge_for_orig_index(
f->edge_orig[j], &orig_me, &index_in_orig_me);
mim.input_medge_for_orig_index(f->edge_orig[j], &orig_me, &index_in_orig_me);
int e_index = dst_loops[mp->loopstart + j].e;
MEdge *medge = &edges[e_index];
copy_edge_attributes(result, medge, orig_medge, orig_me, e_index, index_in_orig_me);
copy_edge_attributes(result, orig_me, e_index, index_in_orig_me);
}
}
}

View File

@ -120,8 +120,6 @@ static void make_edges_mdata_extend(Mesh &mesh)
BLI_edgehashIterator_step(ehi), ++medge, e_index++) {
BLI_edgehashIterator_getKey(ehi, &medge->v1, &medge->v2);
BLI_edgehashIterator_setValue(ehi, POINTER_FROM_UINT(e_index));
medge->flag = 0;
}
BLI_edgehashIterator_free(ehi);

View File

@ -476,7 +476,7 @@ static void convert_mfaces_to_mpolys(ID *id,
/* unrelated but avoid having the FGON flag enabled,
* so we can reuse it later for something else */
me->flag &= ~ME_FGON;
me->flag_legacy &= ~ME_FGON;
}
polyindex = (int *)CustomData_get_layer(fdata, CD_ORIGINDEX);
@ -1379,13 +1379,13 @@ void BKE_mesh_legacy_sharp_edges_to_flags(Mesh *mesh)
CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_edge"))) {
threading::parallel_for(edges.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
SET_FLAG_FROM_TEST(edges[i].flag, sharp_edges[i], ME_SHARP);
SET_FLAG_FROM_TEST(edges[i].flag_legacy, sharp_edges[i], ME_SHARP);
}
});
}
else {
for (const int i : edges.index_range()) {
edges[i].flag &= ~ME_SHARP;
edges[i].flag_legacy &= ~ME_SHARP;
}
}
}
@ -1399,13 +1399,14 @@ void BKE_mesh_legacy_sharp_edges_from_flags(Mesh *mesh)
if (attributes.contains("sharp_edge")) {
return;
}
if (std::any_of(
edges.begin(), edges.end(), [](const MEdge &edge) { return edge.flag & ME_SHARP; })) {
if (std::any_of(edges.begin(), edges.end(), [](const MEdge &edge) {
return edge.flag_legacy & ME_SHARP;
})) {
SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_only_span<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE);
threading::parallel_for(edges.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
sharp_edges.span[i] = edges[i].flag & ME_SHARP;
sharp_edges.span[i] = edges[i].flag_legacy & ME_SHARP;
}
});
sharp_edges.finish();
@ -1414,6 +1415,54 @@ void BKE_mesh_legacy_sharp_edges_from_flags(Mesh *mesh)
/** \} */
/* -------------------------------------------------------------------- */
/** \name UV Seam Conversion
* \{ */
void BKE_mesh_legacy_uv_seam_to_flags(Mesh *mesh)
{
using namespace blender;
MutableSpan<MEdge> edges = mesh->edges_for_write();
if (const bool *uv_seams = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, ".uv_seam"))) {
threading::parallel_for(edges.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
SET_FLAG_FROM_TEST(edges[i].flag_legacy, uv_seams[i], ME_SEAM);
}
});
}
else {
for (const int i : edges.index_range()) {
edges[i].flag_legacy &= ~ME_SEAM;
}
}
}
void BKE_mesh_legacy_uv_seam_from_flags(Mesh *mesh)
{
using namespace blender;
using namespace blender::bke;
const Span<MEdge> edges = mesh->edges();
MutableAttributeAccessor attributes = mesh->attributes_for_write();
if (attributes.contains(".uv_seam")) {
return;
}
if (std::any_of(edges.begin(), edges.end(), [](const MEdge &edge) {
return edge.flag_legacy & ME_SEAM;
})) {
SpanAttributeWriter<bool> uv_seams = attributes.lookup_or_add_for_write_only_span<bool>(
".uv_seam", ATTR_DOMAIN_EDGE);
threading::parallel_for(edges.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
uv_seams.span[i] = edges[i].flag_legacy & ME_SEAM;
}
});
uv_seams.finish();
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Hide Attribute and Legacy Flag Conversion
* \{ */
@ -1438,7 +1487,7 @@ void BKE_mesh_legacy_convert_hide_layers_to_flags(Mesh *mesh)
".hide_edge", ATTR_DOMAIN_EDGE, false);
threading::parallel_for(edges.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
SET_FLAG_FROM_TEST(edges[i].flag, hide_edge[i], ME_HIDE);
SET_FLAG_FROM_TEST(edges[i].flag_legacy, hide_edge[i], ME_HIDE);
}
});
@ -1476,13 +1525,14 @@ void BKE_mesh_legacy_convert_flags_to_hide_layers(Mesh *mesh)
}
const Span<MEdge> edges = mesh->edges();
if (std::any_of(
edges.begin(), edges.end(), [](const MEdge &edge) { return edge.flag & ME_HIDE; })) {
if (std::any_of(edges.begin(), edges.end(), [](const MEdge &edge) {
return edge.flag_legacy & ME_HIDE;
})) {
SpanAttributeWriter<bool> hide_edge = attributes.lookup_or_add_for_write_only_span<bool>(
".hide_edge", ATTR_DOMAIN_EDGE);
threading::parallel_for(edges.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
hide_edge.span[i] = edges[i].flag & ME_HIDE;
hide_edge.span[i] = edges[i].flag_legacy & ME_HIDE;
}
});
hide_edge.finish();
@ -1755,7 +1805,7 @@ void BKE_mesh_legacy_convert_selection_layers_to_flags(Mesh *mesh)
".select_edge", ATTR_DOMAIN_EDGE, false);
threading::parallel_for(edges.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
SET_FLAG_FROM_TEST(edges[i].flag, select_edge[i], SELECT);
SET_FLAG_FROM_TEST(edges[i].flag_legacy, select_edge[i], SELECT);
}
});
@ -1794,13 +1844,14 @@ void BKE_mesh_legacy_convert_flags_to_selection_layers(Mesh *mesh)
}
const Span<MEdge> edges = mesh->edges();
if (std::any_of(
edges.begin(), edges.end(), [](const MEdge &edge) { return edge.flag & SELECT; })) {
if (std::any_of(edges.begin(), edges.end(), [](const MEdge &edge) {
return edge.flag_legacy & SELECT;
})) {
SpanAttributeWriter<bool> select_edge = attributes.lookup_or_add_for_write_only_span<bool>(
".select_edge", ATTR_DOMAIN_EDGE);
threading::parallel_for(edges.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
select_edge.span[i] = edges[i].flag & SELECT;
select_edge.span[i] = edges[i].flag_legacy & SELECT;
}
});
select_edge.finish();
@ -1836,12 +1887,12 @@ void BKE_mesh_legacy_convert_loose_edges_to_flag(Mesh *mesh)
threading::parallel_for(edges.index_range(), 4096, [&](const IndexRange range) {
if (loose_edges.count == 0) {
for (const int64_t i : range) {
edges[i].flag &= ~ME_LOOSEEDGE;
edges[i].flag_legacy &= ~ME_LOOSEEDGE;
}
}
else {
for (const int64_t i : range) {
SET_FLAG_FROM_TEST(edges[i].flag, loose_edges.is_loose_bits[i], ME_LOOSEEDGE);
SET_FLAG_FROM_TEST(edges[i].flag_legacy, loose_edges.is_loose_bits[i], ME_LOOSEEDGE);
}
}
});

View File

@ -999,8 +999,8 @@ void BKE_mesh_loop_islands_add(MeshIslandStore *island_store,
sizeof(*innrcut->indices) * size_t(num_innercut_items));
}
static bool mesh_calc_islands_loop_poly_uv(const MEdge *edges,
const int totedge,
static bool mesh_calc_islands_loop_poly_uv(const int totedge,
const bool *uv_seams,
const MPoly *polys,
const int totpoly,
const MLoop *loops,
@ -1085,7 +1085,7 @@ static bool mesh_calc_islands_loop_poly_uv(const MEdge *edges,
}
/* Edge is UV boundary if tagged as seam. */
return (edges[edge_index].flag & ME_SEAM) != 0;
return uv_seams && uv_seams[edge_index];
};
poly_edge_loop_islands_calc(totedge,
@ -1185,21 +1185,23 @@ bool BKE_mesh_calc_islands_loop_poly_edgeseam(const float (*vert_positions)[3],
const int totvert,
const MEdge *edges,
const int totedge,
const bool *uv_seams,
const MPoly *polys,
const int totpoly,
const MLoop *loops,
const int totloop,
MeshIslandStore *r_island_store)
{
UNUSED_VARS(vert_positions, totvert);
UNUSED_VARS(vert_positions, totvert, edges);
return mesh_calc_islands_loop_poly_uv(
edges, totedge, polys, totpoly, loops, totloop, nullptr, r_island_store);
totedge, uv_seams, polys, totpoly, loops, totloop, nullptr, r_island_store);
}
bool BKE_mesh_calc_islands_loop_poly_uvmap(float (*vert_positions)[3],
const int totvert,
MEdge *edges,
const int totedge,
const bool *uv_seams,
MPoly *polys,
const int totpoly,
MLoop *loops,
@ -1207,10 +1209,10 @@ bool BKE_mesh_calc_islands_loop_poly_uvmap(float (*vert_positions)[3],
const float (*luvs)[2],
MeshIslandStore *r_island_store)
{
UNUSED_VARS(vert_positions, totvert);
UNUSED_VARS(vert_positions, totvert, edges);
BLI_assert(luvs != nullptr);
return mesh_calc_islands_loop_poly_uv(
edges, totedge, polys, totpoly, loops, totloop, luvs, r_island_store);
totedge, uv_seams, polys, totpoly, loops, totloop, luvs, r_island_store);
}
/** \} */

View File

@ -1444,10 +1444,13 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
/* First, generate the islands, if possible. */
if (gen_islands_src) {
const bool *uv_seams = static_cast<const bool *>(
CustomData_get_layer_named(&me_src->edata, CD_PROP_BOOL, ".uv_seam"));
use_islands = gen_islands_src(positions_src,
num_verts_src,
edges_src.data(),
int(edges_src.size()),
uv_seams,
polys_src.data(),
int(polys_src.size()),
loops_src.data(),

View File

@ -911,11 +911,10 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, float (*r_positions)[3])
}
/* utility function */
BLI_INLINE void ccgDM_to_MEdge(MEdge *med, const int v1, const int v2, const short flag)
BLI_INLINE void ccgDM_to_MEdge(MEdge *med, const int v1, const int v2)
{
med->v1 = v1;
med->v2 = v2;
med->flag = flag;
}
static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
@ -927,7 +926,6 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
int gridSize = ccgSubSurf_getGridSize(ss);
int edgeSize = ccgSubSurf_getEdgeSize(ss);
uint i = 0;
short *edgeFlags = ccgdm->edgeFlags;
totface = ccgSubSurf_getNumFaces(ss);
for (index = 0; index < totface; index++) {
@ -938,20 +936,17 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
for (x = 0; x < gridSize - 1; x++) {
ccgDM_to_MEdge(&medge[i++],
getFaceIndex(ss, f, S, x, 0, edgeSize, gridSize),
getFaceIndex(ss, f, S, x + 1, 0, edgeSize, gridSize),
0);
getFaceIndex(ss, f, S, x + 1, 0, edgeSize, gridSize));
}
for (x = 1; x < gridSize - 1; x++) {
for (y = 0; y < gridSize - 1; y++) {
ccgDM_to_MEdge(&medge[i++],
getFaceIndex(ss, f, S, x, y, edgeSize, gridSize),
getFaceIndex(ss, f, S, x, y + 1, edgeSize, gridSize),
0);
getFaceIndex(ss, f, S, x, y + 1, edgeSize, gridSize));
ccgDM_to_MEdge(&medge[i++],
getFaceIndex(ss, f, S, y, x, edgeSize, gridSize),
getFaceIndex(ss, f, S, y + 1, x, edgeSize, gridSize),
0);
getFaceIndex(ss, f, S, y + 1, x, edgeSize, gridSize));
}
}
}
@ -960,21 +955,9 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
totedge = ccgSubSurf_getNumEdges(ss);
for (index = 0; index < totedge; index++) {
CCGEdge *e = ccgdm->edgeMap[index].edge;
short ed_flag = 0;
int x;
int edgeIdx = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(e));
if (edgeFlags) {
if (edgeIdx != -1) {
ed_flag |= (edgeFlags[index] & ME_SEAM);
}
}
for (x = 0; x < edgeSize - 1; x++) {
ccgDM_to_MEdge(&medge[i++],
getEdgeIndex(ss, e, x, edgeSize),
getEdgeIndex(ss, e, x + 1, edgeSize),
ed_flag);
for (int x = 0; x < edgeSize - 1; x++) {
ccgDM_to_MEdge(
&medge[i++], getEdgeIndex(ss, e, x, edgeSize), getEdgeIndex(ss, e, x + 1, edgeSize));
}
}
}
@ -1170,7 +1153,6 @@ static void ccgDM_release(DerivedMesh *dm)
if (ccgdm->pmap_mem) {
MEM_freeN(ccgdm->pmap_mem);
}
MEM_freeN(ccgdm->edgeFlags);
MEM_freeN(ccgdm->faceFlags);
MEM_freeN(ccgdm->vertMap);
MEM_freeN(ccgdm->edgeMap);
@ -1539,7 +1521,6 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
int index;
int i;
int vertNum = 0, edgeNum = 0, faceNum = 0;
short *edgeFlags = ccgdm->edgeFlags;
DMFlagMat *faceFlags = ccgdm->faceFlags;
int *polyidx = nullptr;
blender::Vector<int, 16> loopidx;
@ -1551,7 +1532,6 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
int gridSideEdges;
int gridInternalEdges;
WeightTable wtable = {nullptr};
MEdge *medge = nullptr;
bool has_edge_cd;
edgeSize = ccgSubSurf_getEdgeSize(ss);
@ -1562,8 +1542,6 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
gridSideEdges = gridSize - 1;
gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2;
medge = dm->getEdgeArray(dm);
const MPoly *mpoly = static_cast<const MPoly *>(CustomData_get_layer(&dm->polyData, CD_MPOLY));
const int *material_indices = static_cast<const int *>(
CustomData_get_layer_named(&dm->polyData, CD_MPOLY, "material_index"));
@ -1742,10 +1720,6 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
ccgdm->edgeMap[index].startVert = vertNum;
ccgdm->edgeMap[index].startEdge = edgeNum;
if (edgeIdx >= 0 && edgeFlags) {
edgeFlags[edgeIdx] = medge[edgeIdx].flag;
}
/* set the edge base vert */
*((int *)ccgSubSurf_getEdgeUserData(ss, e)) = vertNum;
@ -1827,6 +1801,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
CCGDerivedMesh *ccgdm = MEM_cnew<CCGDerivedMesh>(__func__);
BLI_assert(totedge == ccgSubSurf_getNumEdges(ss));
UNUSED_VARS_NDEBUG(totedge);
BLI_assert(totface == ccgSubSurf_getNumFaces(ss));
DM_from_template(&ccgdm->dm,
dm,
@ -1849,7 +1824,6 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccgdm->useSubsurfUv = useSubsurfUv;
/* CDDM hack. */
ccgdm->edgeFlags = static_cast<short *>(MEM_callocN(sizeof(short) * totedge, "edgeFlags"));
ccgdm->faceFlags = static_cast<DMFlagMat *>(
MEM_callocN(sizeof(DMFlagMat) * totface, "faceFlags"));

View File

@ -35,6 +35,7 @@ static void version_mesh_legacy_to_struct_of_array_format(Mesh &mesh)
BKE_mesh_legacy_sharp_edges_from_flags(&mesh);
BKE_mesh_legacy_face_set_to_generic(&mesh);
BKE_mesh_legacy_edge_crease_to_layers(&mesh);
BKE_mesh_legacy_uv_seam_from_flags(&mesh);
BKE_mesh_legacy_convert_verts_to_positions(&mesh);
BKE_mesh_legacy_attribute_flags_to_strings(&mesh);
}

View File

@ -113,21 +113,11 @@ using blender::Span;
using blender::StringRef;
using blender::Vector;
static char bm_edge_flag_from_mflag(const short mflag)
{
return ((mflag & ME_SEAM) ? BM_ELEM_SEAM : 0) | BM_ELEM_DRAW;
}
static char bm_face_flag_from_mflag(const char mflag)
{
return ((mflag & ME_SMOOTH) ? BM_ELEM_SMOOTH : 0);
}
static short bm_edge_flag_to_mflag(const BMEdge *e)
{
const char hflag = e->head.hflag;
return (hflag & BM_ELEM_SEAM) ? ME_SEAM : 0;
}
static char bm_face_flag_to_mflag(const BMFace *f)
{
const char hflag = f->head.hflag;
@ -142,6 +132,7 @@ bool BM_attribute_stored_in_bmesh_builtin(const StringRef name)
".hide_vert",
".hide_edge",
".hide_poly",
".uv_seam",
".select_vert",
".select_edge",
".select_poly",
@ -437,6 +428,8 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
&me->pdata, CD_PROP_INT32, "material_index");
const bool *sharp_edges = (const bool *)CustomData_get_layer_named(
&me->edata, CD_PROP_BOOL, "sharp_edge");
const bool *uv_seams = (const bool *)CustomData_get_layer_named(
&me->edata, CD_PROP_BOOL, ".uv_seam");
const Span<float3> positions = me->vert_positions();
Array<BMVert *> vtable(me->totvert);
@ -482,8 +475,10 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
bm, vtable[medge[i].v1], vtable[medge[i].v2], nullptr, BM_CREATE_SKIP_CD);
BM_elem_index_set(e, i); /* set_ok */
/* Transfer flags. */
e->head.hflag = bm_edge_flag_from_mflag(medge[i].flag);
e->head.hflag = 0;
if (uv_seams && uv_seams[i]) {
BM_elem_flag_enable(e, BM_ELEM_SEAM);
}
if (hide_edge && hide_edge[i]) {
BM_elem_flag_enable(e, BM_ELEM_HIDDEN);
}
@ -1258,6 +1253,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
bool need_hide_poly = false;
bool need_material_index = false;
bool need_sharp_edge = false;
bool need_uv_seam = false;
i = 0;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@ -1285,7 +1281,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
medge[i].v1 = BM_elem_index_get(e->v1);
medge[i].v2 = BM_elem_index_get(e->v2);
medge[i].flag = bm_edge_flag_to_mflag(e);
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;
}
@ -1359,6 +1357,13 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
return !BM_elem_flag_test(BM_edge_at_index(bm, i), BM_ELEM_SMOOTH);
});
}
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);
});
}
/* Patch hook indices and vertex parents. */
if (params->calc_object_remap && (ototvert > 0)) {
@ -1496,7 +1501,8 @@ static void bm_edge_table_build(BMesh &bm,
MutableSpan<const BMEdge *> table,
bool &need_select_edge,
bool &need_hide_edge,
bool &need_sharp_edge)
bool &need_sharp_edge,
bool &need_uv_seams)
{
char hflag = 0;
BMIter iter;
@ -1510,6 +1516,7 @@ static void bm_edge_table_build(BMesh &bm,
need_select_edge = (hflag & BM_ELEM_SELECT) != 0;
need_hide_edge = (hflag & BM_ELEM_HIDDEN) != 0;
need_sharp_edge = (hflag & BM_ELEM_SMOOTH) != 0;
need_uv_seams = (hflag & BM_ELEM_SEAM) != 0;
}
static void bm_face_loop_table_build(BMesh &bm,
@ -1574,7 +1581,8 @@ static void bm_to_mesh_edges(const BMesh &bm,
Mesh &mesh,
MutableSpan<bool> select_edge,
MutableSpan<bool> hide_edge,
MutableSpan<bool> sharp_edge)
MutableSpan<bool> sharp_edge,
MutableSpan<bool> uv_seams)
{
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.edata, mesh.edata);
MutableSpan<MEdge> dst_edges = mesh.edges_for_write();
@ -1584,7 +1592,6 @@ static void bm_to_mesh_edges(const BMesh &bm,
MEdge &dst_edge = dst_edges[edge_i];
dst_edge.v1 = BM_elem_index_get(src_edge.v1);
dst_edge.v2 = BM_elem_index_get(src_edge.v2);
dst_edge.flag = bm_edge_flag_to_mflag(&src_edge);
bmesh_block_copy_to_mesh_attributes(info, edge_i, src_edge.head.data);
}
if (!select_edge.is_empty()) {
@ -1602,6 +1609,11 @@ static void bm_to_mesh_edges(const BMesh &bm,
sharp_edge[edge_i] = !BM_elem_flag_test(bm_edges[edge_i], BM_ELEM_SMOOTH);
}
}
if (!uv_seams.is_empty()) {
for (const int edge_i : range) {
uv_seams[edge_i] = BM_elem_flag_test(bm_edges[edge_i], BM_ELEM_SEAM);
}
}
});
}
@ -1709,6 +1721,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
bool need_hide_poly = false;
bool need_material_index = false;
bool need_sharp_edge = false;
bool need_uv_seams = false;
Array<const BMVert *> vert_table;
Array<const BMEdge *> edge_table;
Array<const BMFace *> face_table;
@ -1721,7 +1734,8 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
},
[&]() {
edge_table.reinitialize(bm->totedge);
bm_edge_table_build(*bm, edge_table, need_select_edge, need_hide_edge, need_sharp_edge);
bm_edge_table_build(
*bm, edge_table, need_select_edge, need_hide_edge, need_sharp_edge, need_uv_seams);
},
[&]() {
face_table.reinitialize(bm->totface);
@ -1739,6 +1753,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
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<int> material_index;
@ -1754,6 +1769,9 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
if (need_sharp_edge) {
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);
}
@ -1773,7 +1791,13 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
me->totvert > 1024,
[&]() { bm_to_mesh_verts(*bm, vert_table, *me, select_vert.span, hide_vert.span); },
[&]() {
bm_to_mesh_edges(*bm, edge_table, *me, select_edge.span, hide_edge.span, sharp_edge.span);
bm_to_mesh_edges(*bm,
edge_table,
*me,
select_edge.span,
hide_edge.span,
sharp_edge.span,
uv_seams.span);
},
[&]() {
bm_to_mesh_faces(
@ -1786,6 +1810,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
select_edge.finish();
hide_edge.finish();
sharp_edge.finish();
uv_seams.finish();
select_poly.finish();
hide_poly.finish();
material_index.finish();

View File

@ -227,7 +227,9 @@ static void build_poly_connections(blender::AtomicDisjointSet &islands,
const Span<MEdge> edges = mesh.edges();
const Span<MLoop> loops = mesh.loops();
bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
const bke::AttributeAccessor attributes = mesh.attributes();
const VArray<bool> uv_seams = attributes.lookup_or_default<bool>(
".uv_seam", ATTR_DOMAIN_EDGE, false);
const VArray<bool> hide_poly = attributes.lookup_or_default<bool>(
".hide_poly", ATTR_DOMAIN_FACE, false);
@ -243,7 +245,7 @@ static void build_poly_connections(blender::AtomicDisjointSet &islands,
for (const int poly_loop_index : poly_loops.index_range()) {
const MLoop &outer_mloop = poly_loops[poly_loop_index];
if (skip_seams && (edges[outer_mloop.e].flag & ME_SEAM) != 0) {
if (skip_seams && uv_seams[outer_mloop.e]) {
continue;
}
@ -252,7 +254,7 @@ static void build_poly_connections(blender::AtomicDisjointSet &islands,
if (&outer_mloop == &inner_mloop) {
continue;
}
if (skip_seams && (edges[inner_mloop.e].flag & ME_SEAM) != 0) {
if (skip_seams && uv_seams[inner_mloop.e]) {
continue;
}
islands.join(inner_mloop.e, outer_mloop.e);
@ -277,6 +279,8 @@ static void paintface_select_linked_faces(Mesh &mesh,
const Span<MLoop> loops = mesh.loops();
bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
const VArray<bool> uv_seams = attributes.lookup_or_default<bool>(
".uv_seam", ATTR_DOMAIN_EDGE, false);
bke::SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_span<bool>(
".select_poly", ATTR_DOMAIN_FACE);
@ -284,7 +288,7 @@ static void paintface_select_linked_faces(Mesh &mesh,
for (const int i : face_indices) {
const MPoly &poly = polys[i];
for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
if ((edges[loop.e].flag & ME_SEAM) != 0) {
if (uv_seams[loop.e]) {
continue;
}
const int root = islands.find_root(loop.e);

View File

@ -680,10 +680,11 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
break;
}
case SCULPT_FACE_SETS_FROM_UV_SEAMS: {
const Span<MEdge> edges = mesh->edges();
const VArraySpan<bool> uv_seams = mesh->attributes().lookup_or_default<bool>(
".uv_seam", ATTR_DOMAIN_EDGE, false);
sculpt_face_sets_init_flood_fill(
ob, [&](const int /*from_face*/, const int edge, const int /*to_face*/) -> bool {
return (edges[edge].flag & ME_SEAM) == 0;
return !uv_seams[edge];
});
break;
}

View File

@ -1419,8 +1419,6 @@ static void customdata_weld(
int src_i, dest_i;
int j;
short flag = 0;
/* interpolates a layer at a time */
dest_i = 0;
for (src_i = 0; src_i < source->totlayer; src_i++) {
@ -1442,10 +1440,7 @@ static void customdata_weld(
if (dest->layers[dest_i].type == type) {
void *src_data = source->layers[src_i].data;
if (type == CD_MEDGE) {
for (j = 0; j < count; j++) {
MEdge *me_src = &((MEdge *)src_data)[src_indices[j]];
flag |= me_src->flag;
}
/* Pass. */
}
else if (CustomData_layer_has_interp(dest, dest_i)) {
/* Already calculated.
@ -1478,8 +1473,7 @@ static void customdata_weld(
CustomDataLayer *layer_dst = &dest->layers[dest_i];
const int type = layer_dst->type;
if (type == CD_MEDGE) {
MEdge *me = &((MEdge *)layer_dst->data)[dest_index];
me->flag = flag;
/* Pass. */
}
else if (CustomData_layer_has_interp(dest, dest_i)) {
/* Already calculated. */

View File

@ -32,23 +32,23 @@ typedef struct MEdge {
* Deprecated bevel weight storage, now located in #CD_BWEIGHT, except for file read and write.
*/
char bweight_legacy;
short flag;
short flag_legacy;
} MEdge;
#ifdef DNA_DEPRECATED_ALLOW
/** #MEdge.flag */
enum {
/** Deprecated selection status. Now stored in ".select_edge" attribute. */
/* SELECT = (1 << 0), */
ME_SEAM = (1 << 2),
/** Deprecated hide status. Now stored in ".hide_edge" attribute. */
/* ME_HIDE = (1 << 4), */
#ifdef DNA_DEPRECATED_ALLOW
/** Deprecated hide status. Now stored in ".hide_edge" attribute. */
/* ME_HIDE = (1 << 4), */
/** Deprecated loose edge status. Now stored in #Mesh::loose_edges() runtime cache. */
ME_LOOSEEDGE = (1 << 7),
/** Deprecated sharp edge status. Now stored in "sharp_edge" attribute. */
ME_SHARP = (1 << 9),
#endif
};
#endif
/**
* Mesh Faces.

View File

@ -89,6 +89,7 @@ DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_mask, material_m
DNA_STRUCT_RENAME_ELEM(MDefCell, totinfluence, influences_num)
DNA_STRUCT_RENAME_ELEM(MEdge, bweight, bweight_legacy)
DNA_STRUCT_RENAME_ELEM(MEdge, crease, crease_legacy)
DNA_STRUCT_RENAME_ELEM(MEdge, flag, flag_legacy)
DNA_STRUCT_RENAME_ELEM(MPoly, mat_nr, mat_nr_legacy)
DNA_STRUCT_RENAME_ELEM(MVert, bweight, bweight_legacy)
DNA_STRUCT_RENAME_ELEM(MVert, co, co_legacy)

View File

@ -1745,6 +1745,32 @@ static void rna_MeshEdge_use_edge_sharp_set(PointerRNA *ptr, bool value)
sharp_edge[index] = value;
}
static bool rna_MeshEdge_use_seam_get(PointerRNA *ptr)
{
const Mesh *mesh = rna_mesh(ptr);
const bool *seam_edge = (const bool *)CustomData_get_layer_named(
&mesh->edata, CD_PROP_BOOL, ".uv_seam");
const int index = rna_MeshEdge_index_get(ptr);
return seam_edge == NULL ? false : seam_edge[index];
}
static void rna_MeshEdge_use_seam_set(PointerRNA *ptr, bool value)
{
Mesh *mesh = rna_mesh(ptr);
bool *seam_edge = (bool *)CustomData_get_layer_named_for_write(
&mesh->edata, CD_PROP_BOOL, ".uv_seam", mesh->totedge);
if (!seam_edge) {
if (!value) {
/* Skip adding layer if it doesn't exist already anyway and we're not hiding an element. */
return;
}
seam_edge = (bool *)CustomData_add_layer_named(
&mesh->edata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totedge, ".uv_seam");
}
const int index = rna_MeshEdge_index_get(ptr);
seam_edge[index] = value;
}
static bool rna_MeshEdge_is_loose_get(PointerRNA *ptr)
{
const Mesh *mesh = rna_mesh(ptr);
@ -2718,7 +2744,7 @@ static void rna_def_medge(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Mesh_update_select");
prop = RNA_def_property(srna, "use_seam", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SEAM);
RNA_def_property_boolean_funcs(prop, "rna_MeshEdge_use_seam_get", "rna_MeshEdge_use_seam_set");
RNA_def_property_ui_text(prop, "Seam", "Seam edge for UV unwrapping");
RNA_def_property_update(prop, 0, "rna_Mesh_update_select");

View File

@ -588,7 +588,6 @@ static void add_interpolated_polys_to_new_mesh(const Mesh &src_mesh,
cut_edge.v1 = dst_loops[mp_dst.loopstart].v;
cut_edge.v2 = cut_dst_loop.v;
BLI_assert(cut_edge.v1 != cut_edge.v2);
cut_edge.flag = 0;
edge_index++;
/* Only handle one of the cuts per iteration. */

View File

@ -449,7 +449,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
for (uint i = 0; i < totedge; i++, med_orig++, med_new++) {
med_new->v1 = med_orig->v1;
med_new->v2 = med_orig->v2;
med_new->flag = med_orig->flag;
}
/* build polygon -> edge map */
@ -801,7 +800,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
/* add the new edge */
med_new->v1 = varray_stride + j;
med_new->v2 = med_new->v1 - totvert;
med_new->flag = 0;
med_new++;
}
}
@ -819,7 +817,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
for (uint i = 0; i < totvert; i++) {
med_new->v1 = i;
med_new->v2 = varray_stride + i;
med_new->flag = 0;
med_new++;
}
}
@ -948,7 +945,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
if (step) { /* The first set is already done */
med_new->v1 = i1;
med_new->v2 = i2;
med_new->flag = med_new_firstloop->flag;
med_new++;
}
i1 += totvert;
@ -975,7 +971,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
/* new vertical edge */
med_new->v1 = i1;
med_new->v2 = i2;
med_new->flag = med_new_firstloop->flag;
med_new++;
}

View File

@ -2073,7 +2073,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
BLI_assert(v2 != MOD_SOLIDIFY_EMPTY_TAG);
edges[insert].v1 = v1;
edges[insert].v2 = v2;
edges[insert].flag = orig_edges[(*l)->old_edge].flag;
if (result_edge_crease) {
result_edge_crease[insert] = orig_edge_crease ? orig_edge_crease[(*l)->old_edge] :
0.0f;
@ -2162,14 +2161,10 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
float max_bweight;
float last_max_bweight = 0.0f;
float first_max_bweight = 0.0f;
short flag;
short last_flag = 0;
short first_flag = 0;
for (uint j = 0; g->valid; g++) {
if ((do_rim && !g->is_orig_closed) || (do_shell && g->split)) {
max_crease = 0;
max_bweight = 0;
flag = 0;
BLI_assert(g->edges_len >= 2);
@ -2187,7 +2182,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
else {
for (uint k = 1; k < g->edges_len - 1; k++) {
const uint orig_edge_index = g->edges[k]->old_edge;
const MEdge *ed = &orig_edges[orig_edge_index];
if (result_edge_crease) {
if (orig_edge_crease && orig_edge_crease[orig_edge_index] > max_crease) {
max_crease = orig_edge_crease[orig_edge_index];
@ -2201,7 +2195,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
}
}
}
flag |= ed->flag;
}
}
@ -2222,7 +2215,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
first_g = g;
first_max_crease = max_crease;
first_max_bweight = max_bweight;
first_flag = flag;
}
else {
last_g->open_face_edge = edge_index;
@ -2236,7 +2228,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
}
edges[edge_index].v1 = last_g->new_vert;
edges[edge_index].v2 = g->new_vert;
edges[edge_index].flag = ((last_flag | flag) & ME_SEAM);
if (result_edge_crease) {
result_edge_crease[edge_index] = max_ff(mv_crease,
min_ff(last_max_crease, max_crease));
@ -2250,7 +2241,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
last_g = g;
last_max_crease = max_crease;
last_max_bweight = max_bweight;
last_flag = flag;
j++;
}
if (!(g + 1)->valid || g->topo_group != (g + 1)->topo_group) {
@ -2269,7 +2259,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
last_g->open_face_edge = edge_index;
edges[edge_index].v1 = last_g->new_vert;
edges[edge_index].v2 = first_g->new_vert;
edges[edge_index].flag = ((last_flag | first_flag) & ME_SEAM);
if (result_edge_crease) {
result_edge_crease[edge_index] = max_ff(mv_crease,
min_ff(last_max_crease, first_max_crease));
@ -2373,8 +2362,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
first_max_crease = 0;
last_max_bweight = 0;
first_max_bweight = 0;
last_flag = 0;
first_flag = 0;
}
}
}

View File

@ -152,7 +152,6 @@ static MEdge new_edge(const int v1, const int v2)
MEdge edge;
edge.v1 = v1;
edge.v2 = v2;
edge.flag = 0;
return edge;
}