Mesh: Move edge UV seams to a generic attribute #104728

Merged
Hans Goudey merged 11 commits from HooglyBoogly/blender:refactor-mesh-uv-seam-generic into main 2023-03-01 14:13:15 +01:00
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;
}