Mesh: Move edge crease out of MEdge

This is very similar to D14077. There are two differences though.
First is that vertex creases are already stored in a separate layer,
and second is that we can now completely remove use of `Mesh.cd_flag`,
since that information is now inherent to whether the layers exist.

There are two functional differences here:
 * Operators are used to add and remove layers instead of a property.
 * The "crease" attribute can be created and removed by geometry nodes.

The second change should make various geometry nodes slightly faster,
since the "crease" attribute was always processed before. Creases are
now interpolated generically in the CustomData API too, which should
help maintain the values across edits better.

Meshes get an `edge_creases` RNA property like the existing vertex
property, to provide more efficient access to the data in Cycles.

One test failure is expected, where different rounding between float
the old char storage means that 5 additional points are scattered in
a geometry nodes test.

Differential Revision: https://developer.blender.org/D15927
This commit is contained in:
Hans Goudey 2022-09-23 09:02:05 -05:00
parent b197cd5821
commit a8a454287a
Notes: blender-bot 2023-07-05 22:54:18 +02:00
Referenced by commit 1bacd09abb, Fix: Mishandled creases in Cycles adaptive subdivision
Referenced by commit ed28ba4e99, Fix T101393: Vertex Crease operator does not create vertex crease layer
Referenced by commit fa1c214c5b, Fix crash in Solidify modifier with Inner Crease
Referenced by issue #102772, Regression: creases lost with two subsurf modifier
Referenced by issue #101401, Setting edge crease via PyAPI doesn't work
Referenced by issue #101393, Regression: Vertex Crease operator does not create vertex crease layer
Referenced by issue #101373, Regression with Crease Attribute
Referenced by issue #101340, Regression: Crease values are lost after some modifiers
Referenced by issue #95966, Struct of Arrays Refactor for Mesh Edges
Referenced by issue blender/blender-addons#102420, Regression: FBX Import error: AttributeError: 'Mesh' object has no attribute 'use_customdata_edge_crease'
Referenced by issue #105912, Regression: edge crease lost after a texture paint stroke (modifiers present)
Referenced by issue #109691, Regression: Edge Crease behaves differently between Complex and Simple Solidify
Referenced by commit c65fa57b0b, Fix #109691: Edge crease not handled in complex solidify
50 changed files with 461 additions and 294 deletions

View File

@ -1084,23 +1084,23 @@ static void create_subd_mesh(Scene *scene,
const int edges_num = b_mesh.edges.length();
if (edges_num != 0) {
if (edges_num != 0 && b_mesh.edge_creases.length() > 0) {
size_t num_creases = 0;
const MEdge *edges = static_cast<MEdge *>(b_mesh.edges[0].ptr.data);
const float *creases = static_cast<float *>(b_mesh.edge_creases[0].ptr.data);
for (int i = 0; i < edges_num; i++) {
const MEdge &b_edge = edges[i];
if (b_edge.crease != 0) {
if (creases[i] != 0.0f) {
num_creases++;
}
}
mesh->reserve_subd_creases(num_creases);
const MEdge *edges = static_cast<MEdge *>(b_mesh.edges[0].ptr.data);
for (int i = 0; i < edges_num; i++) {
const MEdge &b_edge = edges[i];
if (b_edge.crease != 0) {
mesh->add_edge_crease(b_edge.v1, b_edge.v2, float(b_edge.crease) / 255.0f);
if (creases[i] != 0.0f) {
const MEdge &b_edge = edges[i];
mesh->add_edge_crease(b_edge.v1, b_edge.v2, creases[i]);
}
}

View File

@ -503,11 +503,15 @@ class DATA_PT_customdata(MeshButtonsPanel, Panel):
else:
col.operator("mesh.customdata_bevel_weight_vertex_add", icon='ADD')
col = layout.column(heading="Store")
if me.has_crease_edge:
col.operator("mesh.customdata_crease_edge_clear", icon='X')
else:
col.operator("mesh.customdata_crease_edge_add", icon='ADD')
col.enabled = obj is not None and obj.mode != 'EDIT'
col.prop(me, "use_customdata_vertex_crease", text="Vertex Crease")
col.prop(me, "use_customdata_edge_crease", text="Edge Crease")
if me.has_crease_vertex:
col.operator("mesh.customdata_crease_vertex_clear", icon='X')
else:
col.operator("mesh.customdata_crease_vertex_add", icon='ADD')
class DATA_PT_custom_props_mesh(MeshButtonsPanel, PropertyPanel, Panel):

View File

@ -104,9 +104,6 @@ struct DerivedMesh {
int num_alloc;
} looptris;
/* use for converting to BMesh which doesn't store bevel weight and edge crease by default */
char cd_flag;
short tangent_mask; /* which tangent layers are calculated */
/** Loop tessellation cache (WARNING! Only call inside threading-protected code!) */

View File

@ -634,8 +634,7 @@ enum {
CD_SHAPEKEY, /* Not available as real CD layer in non-bmesh context. */
/* Edges. */
CD_FAKE_SEAM = CD_FAKE | 100, /* UV seam flag for edges. */
CD_FAKE_CREASE = CD_FAKE | CD_CREASE, /* *sigh*. */
CD_FAKE_SEAM = CD_FAKE | 100, /* UV seam flag for edges. */
/* Multiple types of mesh elements... */
CD_FAKE_UV = CD_FAKE |

View File

@ -26,6 +26,15 @@ void BKE_mesh_legacy_face_set_from_generic(struct Mesh *mesh);
*/
void BKE_mesh_legacy_face_set_to_generic(struct Mesh *mesh);
/**
* Copy edge creases from a separate layer into edges.
*/
void BKE_mesh_legacy_edge_crease_from_layers(struct Mesh *mesh);
/**
* Copy edge creases from edges to a separate layer.
*/
void BKE_mesh_legacy_edge_crease_to_layers(struct Mesh *mesh);
/**
* Copy bevel weights from separate layers into vertices and edges.
*/

View File

@ -307,7 +307,6 @@ BLI_INLINE void BKE_subdiv_rotate_grid_to_quad(
/* Convert Blender edge crease value to OpenSubdiv sharpness. */
BLI_INLINE float BKE_subdiv_crease_to_sharpness_f(float edge_crease);
BLI_INLINE float BKE_subdiv_crease_to_sharpness_char(char edge_crease);
#ifdef __cplusplus
}

View File

@ -240,8 +240,6 @@ void DM_from_template(DerivedMesh *dm,
CustomData_copy(&source->loopData, &dm->loopData, mask->lmask, CD_SET_DEFAULT, numLoops);
CustomData_copy(&source->polyData, &dm->polyData, mask->pmask, CD_SET_DEFAULT, numPolys);
dm->cd_flag = source->cd_flag;
dm->type = type;
dm->numVertData = numVerts;
dm->numEdgeData = numEdges;

View File

@ -206,7 +206,6 @@ static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh,
* but only if the original mesh had its deformed_only flag correctly set
* (which isn't generally the case). */
dm->deformedOnly = 1;
dm->cd_flag = mesh->cd_flag;
CustomData_merge(&mesh->vdata, &dm->vertData, cddata_masks.vmask, alloctype, mesh->totvert);
CustomData_merge(&mesh->edata, &dm->edgeData, cddata_masks.emask, alloctype, mesh->totedge);

View File

@ -1869,9 +1869,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 29: CD_BWEIGHT */
{sizeof(MFloatProperty), "MFloatProperty", 1, nullptr, nullptr, nullptr, layerInterp_bweight},
/* 30: CD_CREASE */
/* NOTE: we do not interpolate crease data as it should be either inherited for subdivided
* edges, or for vertex creases, only present on the original vertex. */
{sizeof(float), "", 0, N_("SubSurfCrease"), nullptr, nullptr, nullptr},
{sizeof(float), "", 0, N_("SubSurfCrease"), nullptr, nullptr, layerInterp_propFloat},
/* 31: CD_ORIGSPACE_MLOOP */
{sizeof(OrigSpaceLoop),
"OrigSpaceLoop",
@ -2124,7 +2122,8 @@ const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX = {
const CustomData_MeshMasks CD_MASK_MESH = {
/* vmask */ (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK |
CD_MASK_PROP_ALL | CD_MASK_CREASE | CD_MASK_BWEIGHT),
/* emask */ (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL | CD_MASK_BWEIGHT),
/* emask */
(CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL | CD_MASK_BWEIGHT | CD_MASK_CREASE),
/* fmask */ 0,
/* pmask */
(CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL),
@ -2136,7 +2135,9 @@ const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
/* vmask */ (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN |
CD_MASK_PAINT_MASK | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL |
CD_MASK_CREASE | CD_MASK_BWEIGHT),
/* emask */ (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_BWEIGHT | CD_MASK_PROP_ALL),
/* emask */
(CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_BWEIGHT | CD_MASK_PROP_ALL |
CD_MASK_CREASE),
/* fmask */ (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT),
/* pmask */
(CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL),

View File

@ -199,7 +199,7 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type)
case DT_TYPE_SEAM:
return CD_FAKE_SEAM;
case DT_TYPE_CREASE:
return CD_FAKE_CREASE;
return CD_CREASE;
case DT_TYPE_BWEIGHT_EDGE:
return CD_BWEIGHT;
case DT_TYPE_FREESTYLE_EDGE:
@ -981,39 +981,6 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map,
}
return true;
}
if (cddata_type == CD_FAKE_CREASE) {
const size_t elem_size = sizeof(*((MEdge *)NULL));
const size_t data_size = sizeof(((MEdge *)NULL)->crease);
const size_t data_offset = offsetof(MEdge, crease);
const uint64_t data_flag = 0;
if (!(me_src->cd_flag & ME_CDFLAG_EDGE_CREASE)) {
if (use_delete) {
me_dst->cd_flag &= ~ME_CDFLAG_EDGE_CREASE;
}
return true;
}
me_dst->cd_flag |= ME_CDFLAG_EDGE_CREASE;
if (r_map) {
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,
data_transfer_interp_char,
interp_data);
}
return true;
}
if (r_map && ELEM(cddata_type, CD_FAKE_SHARP, CD_FAKE_SEAM)) {
const size_t elem_size = sizeof(*((MEdge *)NULL));
const size_t data_size = sizeof(((MEdge *)NULL)->flag);

View File

@ -904,14 +904,14 @@ static void set_loop_uv(MLoopUV &uv, float2 co)
copy_v2_v2(uv.uv, co);
}
static float get_crease(const MEdge &edge)
static float get_crease(const float &crease)
{
return edge.crease / 255.0f;
return crease;
}
static void set_crease(MEdge &edge, float value)
static void set_crease(float &crease, const float value)
{
edge.crease = round_fl_to_uchar_clamp(value * 255.0f);
crease = std::clamp(value, 0.0f, 1.0f);
}
class VArrayImpl_For_VertexWeights final : public VMutableArrayImpl<float> {
@ -1256,13 +1256,13 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
"crease",
ATTR_DOMAIN_EDGE,
CD_PROP_FLOAT,
CD_MEDGE,
BuiltinAttributeProvider::NonCreatable,
CD_CREASE,
BuiltinAttributeProvider::Creatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
BuiltinAttributeProvider::Deletable,
edge_access,
make_derived_read_attribute<MEdge, float, get_crease>,
make_derived_write_attribute<MEdge, float, get_crease, set_crease>,
make_array_read_attribute<float>,
make_derived_write_attribute<float, float, get_crease, set_crease>,
nullptr);
static NamedLegacyCustomDataProvider uvs(

View File

@ -148,8 +148,6 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
mesh_tessface_clear_intern(mesh_dst, false);
}
mesh_dst->cd_flag = mesh_src->cd_flag;
mesh_dst->edit_mesh = nullptr;
mesh_dst->mselect = (MSelect *)MEM_dupallocN(mesh_dst->mselect);
@ -253,6 +251,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
BKE_mesh_legacy_convert_material_indices_to_mpoly(mesh);
BKE_mesh_legacy_bevel_weight_from_layers(mesh);
BKE_mesh_legacy_face_set_from_generic(mesh);
BKE_mesh_legacy_edge_crease_from_layers(mesh);
/* When converting to the old mesh format, don't save redundant attributes. */
names_to_skip.add_multiple_new({".hide_vert", ".hide_edge", ".hide_poly", "material_index"});
@ -1018,7 +1017,6 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
me_dst->totloop = loops_len;
me_dst->totpoly = polys_len;
me_dst->cd_flag = me_src->cd_flag;
BKE_mesh_copy_parameters_for_eval(me_dst, me_src);
CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_SET_DEFAULT, verts_len);
@ -1620,7 +1618,7 @@ void BKE_mesh_do_versions_cd_flag_init(Mesh *mesh)
break;
}
}
if (edge.crease != 0) {
if (edge.crease_legacy != 0) {
mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
if (mesh->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) {
break;

View File

@ -449,7 +449,6 @@ static void copy_edge_attributes(Mesh *dest_mesh,
int medge_index,
int index_in_orig_me)
{
medge->crease = orig_medge->crease;
medge->flag = orig_medge->flag;
CustomData *target_cd = &dest_mesh->edata;
const CustomData *source_cd = &orig_me->edata;

View File

@ -119,7 +119,6 @@ static void make_edges_mdata_extend(Mesh &mesh)
BLI_edgehashIterator_getKey(ehi, &medge->v1, &medge->v2);
BLI_edgehashIterator_setValue(ehi, POINTER_FROM_UINT(e_index));
medge->crease = 0;
medge->flag = ME_EDGEDRAW | ME_EDGERENDER;
}
BLI_edgehashIterator_free(ehi);
@ -1328,7 +1327,6 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob)
BLI_listbase_clear(&mesh_src->vertex_group_names);
BKE_mesh_copy_parameters(mesh_dst, mesh_src);
mesh_dst->cd_flag = mesh_src->cd_flag;
/* For original meshes, shape key data is stored in the #Key data-block, so it
* must be moved from the storage in #CustomData layers used for evaluation. */

View File

@ -27,21 +27,11 @@
# include "BLI_dynstr.h"
static void mesh_debug_info_from_cd_flag(const Mesh *me, DynStr *dynstr)
{
BLI_dynstr_append(dynstr, "'cd_flag': {");
if (me->cd_flag & ME_CDFLAG_EDGE_CREASE) {
BLI_dynstr_append(dynstr, "'EDGE_CREASE', ");
}
BLI_dynstr_append(dynstr, "},\n");
}
char *BKE_mesh_debug_info(const Mesh *me)
{
DynStr *dynstr = BLI_dynstr_new();
char *ret;
const char *indent4 = " ";
const char *indent8 = " ";
BLI_dynstr_append(dynstr, "{\n");
@ -75,9 +65,6 @@ char *BKE_mesh_debug_info(const Mesh *me)
CustomData_debug_info_from_layers(&me->fdata, indent8, dynstr);
BLI_dynstr_append(dynstr, " ),\n");
BLI_dynstr_append(dynstr, indent4);
mesh_debug_info_from_cd_flag(me, dynstr);
BLI_dynstr_append(dynstr, "}\n");
ret = BLI_dynstr_get_cstring(dynstr);

View File

@ -1005,6 +1005,44 @@ void BKE_mesh_legacy_bevel_weight_to_layers(Mesh *mesh)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Edge Crease Conversion
* \{ */
void BKE_mesh_legacy_edge_crease_from_layers(Mesh *mesh)
{
using namespace blender;
MutableSpan<MEdge> edges = mesh->edges_for_write();
if (const float *creases = static_cast<const float *>(
CustomData_get_layer(&mesh->edata, CD_CREASE))) {
mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
for (const int i : edges.index_range()) {
edges[i].crease_legacy = std::clamp(creases[i], 0.0f, 1.0f) * 255.0f;
}
}
else {
mesh->cd_flag &= ~ME_CDFLAG_EDGE_CREASE;
for (const int i : edges.index_range()) {
edges[i].crease_legacy = 0;
}
}
}
void BKE_mesh_legacy_edge_crease_to_layers(Mesh *mesh)
{
using namespace blender;
const Span<MEdge> edges = mesh->edges();
if (mesh->cd_flag & ME_CDFLAG_EDGE_CREASE) {
float *creases = static_cast<float *>(
CustomData_add_layer(&mesh->edata, CD_CREASE, CD_CONSTRUCT, nullptr, edges.size()));
for (const int i : edges.index_range()) {
creases[i] = edges[i].crease_legacy / 255.0f;
}
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Hide Attribute and Legacy Flag Conversion
* \{ */

View File

@ -101,6 +101,8 @@ typedef struct MultiresReshapeContext {
/* Vertex crease custom data layer, null if none is present. */
const float *cd_vertex_crease;
/* Edge crease custom data layer, null if none is present. */
const float *cd_edge_crease;
} MultiresReshapeContext;
/**

View File

@ -482,13 +482,14 @@ static bool is_crease_supported(const MultiresReshapeSmoothContext *reshape_smoo
/* Get crease which will be used for communication to OpenSubdiv topology.
* Note that simple subdivision treats all base edges as infinitely sharp. */
static char get_effective_crease_char(const MultiresReshapeSmoothContext *reshape_smooth_context,
const MEdge *base_edge)
static float get_effective_crease(const MultiresReshapeSmoothContext *reshape_smooth_context,
const int base_edge_index)
{
if (!is_crease_supported(reshape_smooth_context)) {
return 255;
}
return base_edge->crease;
const float *creases = reshape_smooth_context->reshape_context->cd_vertex_crease;
return creases ? creases[base_edge_index] : 0.0f;
}
static float get_effective_crease_float(const MultiresReshapeSmoothContext *reshape_smooth_context,
@ -812,7 +813,6 @@ static void foreach_edge(const struct SubdivForeachContext *foreach_context,
const int subdiv_v2)
{
MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
if (reshape_smooth_context->smoothing_type == MULTIRES_SUBDIVIDE_LINEAR) {
if (!is_loose) {
@ -832,8 +832,7 @@ static void foreach_edge(const struct SubdivForeachContext *foreach_context,
return;
}
/* Edges without crease are to be ignored as well. */
const MEdge *base_edge = &reshape_context->base_edges[coarse_edge_index];
const char crease = get_effective_crease_char(reshape_smooth_context, base_edge);
const char crease = get_effective_crease(reshape_smooth_context, coarse_edge_index);
if (crease == 0) {
return;
}
@ -846,7 +845,6 @@ static void geometry_init_loose_information(MultiresReshapeSmoothContext *reshap
const Mesh *base_mesh = reshape_context->base_mesh;
const MPoly *base_mpoly = reshape_context->base_polys;
const MLoop *base_mloop = reshape_context->base_loops;
const MEdge *base_edge = reshape_context->base_edges;
reshape_smooth_context->non_loose_base_edge_map = BLI_BITMAP_NEW(base_mesh->totedge,
"non_loose_base_edge_map");
@ -859,8 +857,8 @@ static void geometry_init_loose_information(MultiresReshapeSmoothContext *reshap
if (!BLI_BITMAP_TEST_BOOL(reshape_smooth_context->non_loose_base_edge_map, loop->e)) {
BLI_BITMAP_ENABLE(reshape_smooth_context->non_loose_base_edge_map, loop->e);
const char crease = get_effective_crease_char(reshape_smooth_context, &base_edge[loop->e]);
if (crease != 0) {
const float crease = get_effective_crease(reshape_smooth_context, loop->e);
if (crease > 0.0f) {
++num_used_edges;
}
}

View File

@ -206,6 +206,7 @@ bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape
reshape_context->top.grid_size = BKE_subdiv_grid_size_from_level(reshape_context->top.level);
reshape_context->cd_vertex_crease = CustomData_get_layer(&base_mesh->vdata, CD_CREASE);
reshape_context->cd_edge_crease = CustomData_get_layer(&base_mesh->edata, CD_CREASE);
context_init_commoon(reshape_context);
@ -271,6 +272,8 @@ bool multires_reshape_context_create_from_subdiv(MultiresReshapeContext *reshape
reshape_context->base_edges = BKE_mesh_edges(base_mesh);
reshape_context->base_polys = BKE_mesh_polys(base_mesh);
reshape_context->base_loops = BKE_mesh_loops(base_mesh);
reshape_context->cd_vertex_crease = (const float *)CustomData_get_layer(&base_mesh->edata,
CD_CREASE);
reshape_context->subdiv = subdiv;
reshape_context->need_free_subdiv = false;

View File

@ -41,6 +41,8 @@ typedef struct ConverterStorage {
/* CustomData layer for vertex sharpnesses. */
const float *cd_vertex_crease;
/* CustomData layer for edge sharpness. */
const float *cd_edge_crease;
/* Indexed by loop index, value denotes index of face-varying vertex
* which corresponds to the UV coordinate.
*/
@ -157,12 +159,11 @@ static float get_edge_sharpness(const OpenSubdiv_Converter *converter, int manif
return 10.0f;
}
#endif
if (!storage->settings.use_creases) {
if (!storage->settings.use_creases || storage->cd_edge_crease == NULL) {
return 0.0f;
}
const int edge_index = storage->manifold_edge_index_reverse[manifold_edge_index];
const MEdge *medge = storage->edges;
return BKE_subdiv_crease_to_sharpness_char(medge[edge_index].crease);
return BKE_subdiv_crease_to_sharpness_f(storage->cd_edge_crease[edge_index]);
}
static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter,
@ -398,6 +399,7 @@ static void init_user_data(OpenSubdiv_Converter *converter,
user_data->polys = BKE_mesh_polys(mesh);
user_data->loops = BKE_mesh_loops(mesh);
user_data->cd_vertex_crease = CustomData_get_layer(&mesh->vdata, CD_CREASE);
user_data->cd_edge_crease = CustomData_get_layer(&mesh->edata, CD_CREASE);
user_data->loop_uv_indices = NULL;
initialize_manifold_indices(user_data);
converter->user_data = user_data;

View File

@ -518,9 +518,11 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex
const int *UNUSED(subdiv_polygon_offset))
{
/* Multi-resolution grid data will be applied or become invalid after subdivision,
* so don't try to preserve it and use memory. */
* so don't try to preserve it and use memory. Crease values should also not be interpolated. */
CustomData_MeshMasks mask = CD_MASK_EVERYTHING;
mask.lmask &= ~CD_MASK_MULTIRES_GRIDS;
mask.vmask &= ~CD_MASK_CREASE;
mask.emask &= ~CD_MASK_CREASE;
SubdivMeshContext *subdiv_context = static_cast<SubdivMeshContext *>(foreach_context->user_data);
subdiv_context->subdiv_mesh = BKE_mesh_new_nomain_from_template_ex(
@ -790,7 +792,7 @@ static void subdiv_copy_edge_data(SubdivMeshContext *ctx,
{
const int subdiv_edge_index = subdiv_edge - ctx->subdiv_edges;
if (coarse_edge == nullptr) {
subdiv_edge->crease = 0;
/* TODO: Ensure crease layer isn't copied to result. */
subdiv_edge->flag = 0;
if (!ctx->settings->use_optimal_display) {
subdiv_edge->flag |= ME_EDGERENDER;

View File

@ -592,11 +592,12 @@ static void ss_sync_ccg_from_derivedmesh(CCGSubSurf *ss,
me = medge;
index = (int *)dm->getEdgeDataArray(dm, CD_ORIGINDEX);
const float *creases = (const float *)dm->getEdgeDataArray(dm, CD_CREASE);
for (i = 0; i < totedge; i++, me++) {
CCGEdge *e;
float crease;
crease = useFlatSubdiv ? creaseFactor : me->crease * creaseFactor / 255.0f;
crease = useFlatSubdiv ? creaseFactor : (creases ? creases[i] * creaseFactor : 0.0f);
ccgSubSurf_syncEdge(
ss, POINTER_FROM_INT(i), POINTER_FROM_UINT(me->v1), POINTER_FROM_UINT(me->v2), crease, &e);
@ -949,7 +950,6 @@ BLI_INLINE void ccgDM_to_MEdge(MEdge *med, const int v1, const int v2, const sho
{
med->v1 = v1;
med->v2 = v2;
med->crease = 0;
med->flag = flag;
}

View File

@ -25,6 +25,7 @@ static void version_mesh_legacy_to_struct_of_array_format(Mesh &mesh)
BKE_mesh_legacy_convert_mpoly_to_material_indices(&mesh);
BKE_mesh_legacy_bevel_weight_to_layers(&mesh);
BKE_mesh_legacy_face_set_to_generic(&mesh);
BKE_mesh_legacy_edge_crease_to_layers(&mesh);
}
void blo_do_versions_400(FileData * /*fd*/, Library * /*lib*/, Main *bmain)

View File

@ -507,8 +507,6 @@ void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst,
allocsize = &bm_mesh_allocsize_default;
}
char cd_flag = 0;
for (int i = 0; i < me_src_array_len; i++) {
const Mesh *me_src = me_src_array[i];
if (i == 0) {
@ -531,18 +529,12 @@ void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst,
CustomData_merge_mesh_to_bmesh(
&me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0);
}
cd_flag |= me_src->cd_flag;
}
cd_flag |= BM_mesh_cd_flag_from_bmesh(bm_dst);
CustomData_bmesh_init_pool(&bm_dst->vdata, allocsize->totvert, BM_VERT);
CustomData_bmesh_init_pool(&bm_dst->edata, allocsize->totedge, BM_EDGE);
CustomData_bmesh_init_pool(&bm_dst->ldata, allocsize->totloop, BM_LOOP);
CustomData_bmesh_init_pool(&bm_dst->pdata, allocsize->totface, BM_FACE);
BM_mesh_cd_flag_apply(bm_dst, cd_flag);
}
void BM_mesh_copy_init_customdata_from_mesh(BMesh *bm_dst,

View File

@ -110,57 +110,6 @@ using blender::MutableSpan;
using blender::Span;
using blender::StringRef;
void BM_mesh_cd_flag_ensure(BMesh *bm, Mesh *mesh, const char cd_flag)
{
const char cd_flag_all = BM_mesh_cd_flag_from_bmesh(bm) | cd_flag;
BM_mesh_cd_flag_apply(bm, cd_flag_all);
if (mesh) {
mesh->cd_flag = cd_flag_all;
}
}
void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag)
{
/* CustomData_bmesh_init_pool() must run first */
BLI_assert(bm->vdata.totlayer == 0 || bm->vdata.pool != nullptr);
BLI_assert(bm->edata.totlayer == 0 || bm->edata.pool != nullptr);
BLI_assert(bm->pdata.totlayer == 0 || bm->pdata.pool != nullptr);
if (cd_flag & ME_CDFLAG_VERT_CREASE) {
if (!CustomData_has_layer(&bm->vdata, CD_CREASE)) {
BM_data_layer_add(bm, &bm->vdata, CD_CREASE);
}
}
else {
if (CustomData_has_layer(&bm->vdata, CD_CREASE)) {
BM_data_layer_free(bm, &bm->vdata, CD_CREASE);
}
}
if (cd_flag & ME_CDFLAG_EDGE_CREASE) {
if (!CustomData_has_layer(&bm->edata, CD_CREASE)) {
BM_data_layer_add(bm, &bm->edata, CD_CREASE);
}
}
else {
if (CustomData_has_layer(&bm->edata, CD_CREASE)) {
BM_data_layer_free(bm, &bm->edata, CD_CREASE);
}
}
}
char BM_mesh_cd_flag_from_bmesh(BMesh *bm)
{
char cd_flag = 0;
if (CustomData_has_layer(&bm->vdata, CD_CREASE)) {
cd_flag |= ME_CDFLAG_VERT_CREASE;
}
if (CustomData_has_layer(&bm->edata, CD_CREASE)) {
cd_flag |= ME_CDFLAG_EDGE_CREASE;
}
return cd_flag;
}
/* Static function for alloc (duplicate in modifiers_bmesh.c) */
static BMFace *bm_face_create_from_mpoly(BMesh &bm,
Span<MLoop> loops,
@ -310,13 +259,9 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP);
CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE);
}
BM_mesh_cd_flag_apply(bm, me->cd_flag | (is_new ? 0 : BM_mesh_cd_flag_from_bmesh(bm)));
/* Only copy these values over if the source mesh is flagged to be using them.
* Even if `bm` has these layers, they may have been added from another mesh, when `!is_new`. */
const int cd_edge_crease_offset = (me->cd_flag & ME_CDFLAG_EDGE_CREASE) ?
CustomData_get_offset(&bm->edata, CD_CREASE) :
-1;
const int cd_shape_key_offset = tot_shape_keys ? CustomData_get_offset(&bm->vdata, CD_SHAPEKEY) :
-1;
const int cd_shape_keyindex_offset = is_new && (tot_shape_keys || params->add_key_index) ?
@ -394,10 +339,6 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
/* Copy Custom Data */
CustomData_to_bmesh_block(&me->edata, &bm->edata, i, &e->head.data, true);
if (cd_edge_crease_offset != -1) {
BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset, (float)medge[i].crease / 255.0f);
}
}
if (is_new) {
bm->elem_index_dirty &= ~BM_EDGE; /* Added in order, clear dirty flag. */
@ -957,7 +898,6 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BMIter iter;
int i, j;
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
const int ototvert = me->totvert;
@ -1006,8 +946,6 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
* different than the BMesh's. */
BKE_mesh_clear_derived_normals(me);
me->cd_flag = BM_mesh_cd_flag_from_bmesh(bm);
i = 0;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
copy_v3_v3(mvert[i].co, v->co);
@ -1045,10 +983,6 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
bmesh_quick_edgedraw_flag(&medge[i], e);
if (cd_edge_crease_offset != -1) {
medge[i].crease = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(e, cd_edge_crease_offset);
}
i++;
BM_CHECK_ELEMENT(e);
}
@ -1258,8 +1192,6 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
MLoop *mloop = loops.data();
unsigned int i, j;
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
/* Clear normals on the mesh completely, since the original vertex and polygon count might be
* different than the BMesh's. */
BKE_mesh_clear_derived_normals(me);
@ -1315,10 +1247,6 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
}
}
if (cd_edge_crease_offset != -1) {
med->crease = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_crease_offset);
}
CustomData_from_bmesh_block(&bm->edata, &me->edata, eed->head.data, i);
}
bm->elem_index_dirty &= ~BM_EDGE;
@ -1374,6 +1302,4 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
hide_vert_attribute.finish();
hide_edge_attribute.finish();
hide_poly_attribute.finish();
me->cd_flag = BM_mesh_cd_flag_from_bmesh(bm);
}

View File

@ -13,10 +13,6 @@ struct CustomData_MeshMasks;
struct Main;
struct Mesh;
void BM_mesh_cd_flag_ensure(BMesh *bm, struct Mesh *mesh, char cd_flag);
void BM_mesh_cd_flag_apply(BMesh *bm, char cd_flag);
char BM_mesh_cd_flag_from_bmesh(BMesh *bm);
struct BMeshFromMeshParams {
bool calc_face_normal;
bool calc_vert_normal;

View File

@ -346,7 +346,9 @@ static void edgetag_ensure_cd_flag(Mesh *me, const char edge_mode)
switch (edge_mode) {
case EDGE_MODE_TAG_CREASE:
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE);
if (!CustomData_has_layer(&bm->edata, CD_CREASE)) {
BM_data_layer_add(bm, &bm->edata, CD_CREASE);
}
break;
case EDGE_MODE_TAG_BEVEL:
if (!CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {

View File

@ -990,6 +990,126 @@ void MESH_OT_customdata_bevel_weight_edge_clear(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* Edge crease. */
static int mesh_customdata_crease_edge_state(bContext *C)
{
const Object *ob = ED_object_context(C);
if (ob && ob->type == OB_MESH) {
const Mesh *mesh = static_cast<Mesh *>(ob->data);
if (!ID_IS_LINKED(mesh)) {
const CustomData *data = GET_CD_DATA(mesh, edata);
return CustomData_has_layer(data, CD_CREASE);
}
}
return -1;
}
static bool mesh_customdata_crease_edge_add_poll(bContext *C)
{
return mesh_customdata_crease_edge_state(C) == 0;
}
static int mesh_customdata_crease_edge_add_exec(bContext *C, wmOperator *UNUSED(op))
{
return mesh_customdata_add_exec__internal(C, BM_EDGE, CD_CREASE);
}
void MESH_OT_customdata_crease_edge_add(wmOperatorType *ot)
{
ot->name = "Add Edge Crease";
ot->idname = "MESH_OT_customdata_crease_edge_add";
ot->description = "Add an edge crease layer";
ot->exec = mesh_customdata_crease_edge_add_exec;
ot->poll = mesh_customdata_crease_edge_add_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static bool mesh_customdata_crease_edge_clear_poll(bContext *C)
{
return mesh_customdata_crease_edge_state(C) == 1;
}
static int mesh_customdata_crease_edge_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
return mesh_customdata_clear_exec__internal(C, BM_EDGE, CD_CREASE);
}
void MESH_OT_customdata_crease_edge_clear(wmOperatorType *ot)
{
ot->name = "Clear Edge Crease";
ot->idname = "MESH_OT_customdata_crease_edge_clear";
ot->description = "Clear the edge crease layer";
ot->exec = mesh_customdata_crease_edge_clear_exec;
ot->poll = mesh_customdata_crease_edge_clear_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* Vertex crease. */
static int mesh_customdata_crease_vertex_state(bContext *C)
{
const Object *object = ED_object_context(C);
if (object && object->type == OB_MESH) {
const Mesh *mesh = static_cast<Mesh *>(object->data);
if (!ID_IS_LINKED(mesh)) {
const CustomData *data = GET_CD_DATA(mesh, vdata);
return CustomData_has_layer(data, CD_CREASE);
}
}
return -1;
}
static bool mesh_customdata_crease_vertex_add_poll(bContext *C)
{
return mesh_customdata_crease_vertex_state(C) == 0;
}
static int mesh_customdata_crease_vertex_add_exec(bContext *C, wmOperator *UNUSED(op))
{
return mesh_customdata_add_exec__internal(C, BM_VERT, CD_CREASE);
}
void MESH_OT_customdata_crease_vertex_add(wmOperatorType *ot)
{
ot->name = "Add Vertex Crease";
ot->idname = "MESH_OT_customdata_crease_vertex_add";
ot->description = "Add a vertex crease layer";
ot->exec = mesh_customdata_crease_vertex_add_exec;
ot->poll = mesh_customdata_crease_vertex_add_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static bool mesh_customdata_crease_vertex_clear_poll(bContext *C)
{
return (mesh_customdata_crease_vertex_state(C) == 1);
}
static int mesh_customdata_crease_vertex_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
return mesh_customdata_clear_exec__internal(C, BM_VERT, CD_CREASE);
}
void MESH_OT_customdata_crease_vertex_clear(wmOperatorType *ot)
{
ot->name = "Clear Vertex Crease";
ot->idname = "MESH_OT_customdata_crease_vertex_clear";
ot->description = "Clear the vertex crease layer";
ot->exec = mesh_customdata_crease_vertex_clear_exec;
ot->poll = mesh_customdata_crease_vertex_clear_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/************************** Add Geometry Layers *************************/
void ED_mesh_update(Mesh *mesh, bContext *C, bool calc_edges, bool calc_edges_loose)

View File

@ -319,6 +319,10 @@ void MESH_OT_customdata_bevel_weight_vertex_add(struct wmOperatorType *ot);
void MESH_OT_customdata_bevel_weight_vertex_clear(struct wmOperatorType *ot);
void MESH_OT_customdata_bevel_weight_edge_add(struct wmOperatorType *ot);
void MESH_OT_customdata_bevel_weight_edge_clear(struct wmOperatorType *ot);
void MESH_OT_customdata_crease_vertex_add(struct wmOperatorType *ot);
void MESH_OT_customdata_crease_vertex_clear(struct wmOperatorType *ot);
void MESH_OT_customdata_crease_edge_add(struct wmOperatorType *ot);
void MESH_OT_customdata_crease_edge_clear(struct wmOperatorType *ot);
#ifdef __cplusplus
}

View File

@ -143,6 +143,10 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_customdata_bevel_weight_vertex_clear);
WM_operatortype_append(MESH_OT_customdata_bevel_weight_edge_add);
WM_operatortype_append(MESH_OT_customdata_bevel_weight_edge_clear);
WM_operatortype_append(MESH_OT_customdata_crease_vertex_add);
WM_operatortype_append(MESH_OT_customdata_crease_vertex_clear);
WM_operatortype_append(MESH_OT_customdata_crease_edge_add);
WM_operatortype_append(MESH_OT_customdata_crease_edge_clear);
WM_operatortype_append(MESH_OT_edgering_select);
WM_operatortype_append(MESH_OT_loopcut);

View File

@ -102,9 +102,6 @@ static void join_mesh_single(Depsgraph *depsgraph,
MPoly *mpoly = *mpoly_pp;
if (me->totvert) {
/* merge customdata flag */
((Mesh *)ob_dst->data)->cd_flag |= me->cd_flag;
/* standard data */
CustomData_merge(&me->vdata, vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert);
CustomData_copy_data_named(&me->vdata, vdata, 0, *vertofs, me->totvert);

View File

@ -673,10 +673,11 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
break;
}
case SCULPT_FACE_SETS_FROM_CREASES: {
const Span<MEdge> edges = mesh->edges();
const float *creases = static_cast<const float *>(
CustomData_get_layer(&mesh->edata, CD_CREASE));
sculpt_face_sets_init_flood_fill(
ob, [&](const int /*from_face*/, const int edge, const int /*to_face*/) -> bool {
return edges[edge].crease / 255.0f < threshold;
return creases[edge] < threshold;
});
break;
}

View File

@ -1005,7 +1005,9 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
}
if (median->v_crease) {
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_CREASE);
if (!CustomData_has_layer(&bm->vdata, CD_CREASE)) {
BM_data_layer_add(bm, &bm->vdata, CD_CREASE);
}
cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
BLI_assert(cd_vert_crease_offset != -1);
@ -1073,7 +1075,9 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
}
if (median->e_crease) {
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE);
if (!CustomData_has_layer(&bm->edata, CD_CREASE)) {
BM_data_layer_add(bm, &bm->edata, CD_CREASE);
}
cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
BLI_assert(cd_edge_crease_offset != -1);

View File

@ -74,7 +74,9 @@ static void createTransEdge(bContext *UNUSED(C), TransInfo *t)
}
else { /* if (t->mode == TFM_EDGE_CREASE) { */
BLI_assert(t->mode == TFM_EDGE_CREASE);
BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_CREASE);
if (!CustomData_has_layer(&em->bm->edata, CD_CREASE)) {
BM_data_layer_add(em->bm, &em->bm->edata, CD_CREASE);
}
cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
}

View File

@ -90,7 +90,9 @@ static void createTransMeshVertCData(bContext *UNUSED(C), TransInfo *t)
cd_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
}
else {
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_CREASE);
if (!CustomData_has_layer(&bm->edata, CD_CREASE)) {
BM_data_layer_add(bm, &bm->edata, CD_CREASE);
}
cd_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
}

View File

@ -1232,7 +1232,6 @@ static void customdata_weld(
#ifdef USE_WELD_NORMALS
float no[3] = {0.0f, 0.0f, 0.0f};
#endif
int crease = 0;
short flag = 0;
/* interpolates a layer at a time */
@ -1272,7 +1271,6 @@ static void customdata_weld(
else if (type == CD_MEDGE) {
for (j = 0; j < count; j++) {
MEdge *me_src = &((MEdge *)src_data)[src_indices[j]];
crease += me_src->crease;
flag |= me_src->flag;
}
}
@ -1323,10 +1321,6 @@ static void customdata_weld(
}
else if (type == CD_MEDGE) {
MEdge *me = &((MEdge *)layer_dst->data)[dest_index];
crease *= fac;
CLAMP_MAX(crease, 255);
me->crease = (char)crease;
me->flag = flag;
}
else if (CustomData_layer_has_interp(dest, dest_i)) {

View File

@ -809,7 +809,6 @@ static OrderedAttributes gather_generic_mesh_attributes_to_propagate(
attributes_to_propagate.remove("position");
attributes_to_propagate.remove("normal");
attributes_to_propagate.remove("shade_smooth");
attributes_to_propagate.remove("crease");
r_create_id = attributes_to_propagate.pop_try("id").has_value();
r_create_material_index = attributes_to_propagate.pop_try("material_index").has_value();
OrderedAttributes ordered_attributes;

View File

@ -476,16 +476,17 @@ static void get_edge_creases(struct Mesh *mesh,
std::vector<int32_t> &lengths,
std::vector<float> &sharpnesses)
{
const float factor = 1.0f / 255.0f;
indices.clear();
lengths.clear();
sharpnesses.clear();
const float *creases = static_cast<const float *>(CustomData_get_layer(&mesh->edata, CD_CREASE));
if (!creases) {
return;
}
const Span<MEdge> edges = mesh->edges();
for (const int i : edges.index_range()) {
const float sharpness = static_cast<float>(edges[i].crease) * factor;
const float sharpness = creases[i];
if (sharpness != 0.0f) {
indices.push_back(edges[i].v1);

View File

@ -903,8 +903,6 @@ static void read_vertex_creases(Mesh *mesh,
vertex_crease_data[idx] = (*sharpnesses)[i];
}
mesh->cd_flag |= ME_CDFLAG_VERT_CREASE;
}
static void read_edge_creases(Mesh *mesh,
@ -918,6 +916,9 @@ static void read_edge_creases(Mesh *mesh,
MutableSpan<MEdge> edges = mesh->edges_for_write();
EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, edges.size());
float *creases = static_cast<float *>(
CustomData_add_layer(&mesh->edata, CD_CREASE, CD_SET_DEFAULT, nullptr, edges.size()));
for (const int i : edges.index_range()) {
MEdge *edge = &edges[i];
BLI_edgehash_insert(edge_hash, edge->v1, edge->v2, edge);
@ -939,13 +940,11 @@ static void read_edge_creases(Mesh *mesh,
}
if (edge) {
edge->crease = unit_float_to_uchar_clamp((*sharpnesses)[s]);
creases[edge - edges.data()] = unit_float_to_uchar_clamp((*sharpnesses)[s]);
}
}
BLI_edgehash_free(edge_hash, nullptr);
mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
}
/* ************************************************************************** */

View File

@ -592,7 +592,6 @@ void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
unsigned int *indices = mp->getPositionIndices().getData();
for (int j = 0; j < edge_count; j++, med++) {
med->crease = 0;
med->flag |= ME_LOOSEEDGE;
med->v1 = indices[2 * j];
med->v2 = indices[2 * j + 1];

View File

@ -283,25 +283,22 @@ static void get_loops_polys(const Mesh *mesh, USDMeshData &usd_mesh_data)
static void get_edge_creases(const Mesh *mesh, USDMeshData &usd_mesh_data)
{
const float factor = 1.0f / 255.0f;
const float *creases = static_cast<const float *>(CustomData_get_layer(&mesh->edata, CD_CREASE));
if (!creases) {
return;
}
const Span<MEdge> edges = mesh->edges();
float sharpness;
for (const int i : edges.index_range()) {
const MEdge &edge = edges[i];
if (edge.crease == 0) {
const float crease = creases[i];
if (crease == 0.0f) {
continue;
}
if (edge.crease == 255) {
sharpness = pxr::UsdGeomMesh::SHARPNESS_INFINITE;
}
else {
sharpness = static_cast<float>(edge.crease) * factor;
}
const float sharpness = crease >= 1.0f ? pxr::UsdGeomMesh::SHARPNESS_INFINITE : crease;
usd_mesh_data.crease_vertex_indices.push_back(edge.v1);
usd_mesh_data.crease_vertex_indices.push_back(edge.v2);
usd_mesh_data.crease_vertex_indices.push_back(edges[i].v1);
usd_mesh_data.crease_vertex_indices.push_back(edges[i].v2);
usd_mesh_data.crease_lengths.push_back(2);
usd_mesh_data.crease_sharpnesses.push_back(sharpness);
}

View File

@ -127,12 +127,7 @@ typedef enum eCustomDataType {
CD_SHAPE_KEYINDEX = 27,
CD_SHAPEKEY = 28,
CD_BWEIGHT = 29,
/**
* Usage of #CD_CREASE depends on where on the Mesh the layer is added:
* - For vertex creasing, this is persistent data across all modes and is stored in the file.
* - For edge creasing, it is runtime data which is only used in edit-mode before being copied
* to #MEdge when exiting edit-mode.
*/
/** Subdivision sharpness data per edge or per vertex. */
CD_CREASE = 30,
CD_ORIGSPACE_MLOOP = 31,
CD_PREVIEW_MLOOPCOL = 32,

View File

@ -253,25 +253,24 @@ typedef struct Mesh {
*/
float smoothresh;
/**
* Flag for choosing whether or not so store bevel weight and crease as custom data layers in the
* edit mesh (they are always stored in #MVert and #MEdge currently). In the future, this data
* may be stored as generic named attributes (see T89054 and T93602).
*/
char cd_flag;
/**
* User-defined symmetry flag (#eMeshSymmetryType) that causes editing operations to maintain
* symmetrical geometry. Supported by operations such as transform and weight-painting.
*/
char symmetry;
/** The length of the #mat array. */
short totcol;
/** Choice between different remesh methods in the UI. */
char remesh_mode;
/** The length of the #mat array. */
short totcol;
/**
* Deprecated flag for choosing whether to store specific custom data that was built into #Mesh
* structs in edit mode. Replaced by separating that data to separate layers. Kept for forward
* and backwards compatibility.
*/
char cd_flag DNA_DEPRECATED;
char subdiv DNA_DEPRECATED;
char subdivr DNA_DEPRECATED;
char subsurftype DNA_DEPRECATED;
@ -438,15 +437,15 @@ enum {
ME_REMESH_REPROJECT_SCULPT_FACE_SETS = 1 << 15,
};
#ifdef DNA_DEPRECATED_ALLOW
/** #Mesh.cd_flag */
enum {
#ifdef DNA_DEPRECATED_ALLOW
ME_CDFLAG_VERT_BWEIGHT = 1 << 0,
ME_CDFLAG_EDGE_BWEIGHT = 1 << 1,
#endif
ME_CDFLAG_EDGE_CREASE = 1 << 2,
ME_CDFLAG_VERT_CREASE = 1 << 3,
};
#endif
/** #Mesh.remesh_mode */
enum {

View File

@ -51,7 +51,8 @@ enum {
typedef struct MEdge {
/** Un-ordered vertex indices (cannot match). */
unsigned int v1, v2;
char crease;
/** Deprecated edge crease, now located in #CD_CREASE, except for file read and write. */
char crease_legacy;
/**
* Deprecated bevel weight storage, now located in #CD_BWEIGHT, except for file read and write.
*/

View File

@ -98,6 +98,7 @@ DNA_STRUCT_RENAME_ELEM(Object, restrictflag, visibility_flag)
DNA_STRUCT_RENAME_ELEM(Object, size, scale)
DNA_STRUCT_RENAME_ELEM(Object_Runtime, crazyspace_num_verts, crazyspace_verts_num)
DNA_STRUCT_RENAME_ELEM(MEdge, bweight, bweight_legacy)
DNA_STRUCT_RENAME_ELEM(MEdge, crease, crease_legacy)
DNA_STRUCT_RENAME_ELEM(MPoly, mat_nr, mat_nr_legacy)
DNA_STRUCT_RENAME_ELEM(MVert, bweight, bweight_legacy)
DNA_STRUCT_RENAME_ELEM(ParticleSettings, child_nbr, child_percent)

View File

@ -108,7 +108,7 @@ static CustomData *rna_mesh_vdata(const PointerRNA *ptr)
Mesh *me = rna_mesh(ptr);
return rna_mesh_vdata_helper(me);
}
static CustomData *rna_mesh_edata(PointerRNA *ptr)
static CustomData *rna_mesh_edata(const PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
return rna_mesh_edata_helper(me);
@ -239,6 +239,16 @@ static bool rna_Mesh_has_vertex_bevel_weight_get(PointerRNA *ptr)
return CustomData_has_layer(rna_mesh_vdata(ptr), CD_BWEIGHT);
}
static bool rna_Mesh_has_edge_crease_get(PointerRNA *ptr)
{
return CustomData_has_layer(rna_mesh_edata(ptr), CD_CREASE);
}
static bool rna_Mesh_has_vertex_crease_get(PointerRNA *ptr)
{
return CustomData_has_layer(rna_mesh_vdata(ptr), CD_CREASE);
}
/** \} */
/* -------------------------------------------------------------------- */
@ -472,14 +482,19 @@ static void rna_MEdge_bevel_weight_set(PointerRNA *ptr, float value)
static float rna_MEdge_crease_get(PointerRNA *ptr)
{
MEdge *medge = (MEdge *)ptr->data;
return medge->crease / 255.0f;
const Mesh *mesh = rna_mesh(ptr);
const int index = rna_MeshEdge_index_get(ptr);
const float *values = (const float *)CustomData_get_layer(&mesh->edata, CD_CREASE);
return values == NULL ? 0.0f : values[index];
}
static void rna_MEdge_crease_set(PointerRNA *ptr, float value)
{
MEdge *medge = (MEdge *)ptr->data;
medge->crease = round_fl_to_uchar_clamp(value * 255.0f);
Mesh *mesh = rna_mesh(ptr);
const int index = rna_MeshEdge_index_get(ptr);
float *values = (float *)CustomData_add_layer(
&mesh->edata, CD_CREASE, CD_SET_DEFAULT, NULL, mesh->totedge);
values[index] = clamp_f(value, 0.0f, 1.0f);
}
static void rna_MeshLoop_normal_get(PointerRNA *ptr, float *values)
@ -1165,6 +1180,31 @@ static int rna_MeshVertexCreaseLayer_data_length(PointerRNA *ptr)
/* End vertex creases */
/* Edge creases */
DEFINE_CUSTOMDATA_LAYER_COLLECTION(edge_crease, edata, CD_CREASE)
static char *rna_EdgeCustomData_data_path(const PointerRNA *ptr, const char *collection, int type);
static char *rna_MeshEdgeCreaseLayer_path(const PointerRNA *ptr)
{
return rna_EdgeCustomData_data_path(ptr, "edge_creases", CD_CREASE);
}
static void rna_MeshEdgeCreaseLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
rna_iterator_array_begin(iter, layer->data, sizeof(float), me->totedge, 0, NULL);
}
static int rna_MeshEdgeCreaseLayer_data_length(PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
return me->totedge;
}
/* End edge creases */
/* Paint mask */
DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_paint_mask, vdata, CD_PAINT_MASK)
@ -1424,6 +1464,27 @@ static char *rna_VertCustomData_data_path(const PointerRNA *ptr, const char *col
return NULL;
}
static char *rna_EdgeCustomData_data_path(const PointerRNA *ptr, const char *collection, int type)
{
const CustomDataLayer *cdl;
const Mesh *me = rna_mesh(ptr);
const CustomData *edata = rna_mesh_edata(ptr);
int a, b, totedge = (me->edit_mesh) ? 0 : me->totedge;
for (cdl = edata->layers, a = 0; a < edata->totlayer; cdl++, a++) {
if (cdl->type == type) {
b = ((char *)ptr->data - ((char *)cdl->data)) / CustomData_sizeof(type);
if (b >= 0 && b < totedge) {
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("%s[\"%s\"].data[%d]", collection, name_esc, b);
}
}
}
return NULL;
}
static char *rna_PolyCustomData_data_path(const PointerRNA *ptr, const char *collection, int type)
{
const CustomDataLayer *cdl;
@ -1969,6 +2030,7 @@ static void UNUSED_FUNCTION(rna_mesh_unused)(void)
(void)rna_Mesh_face_map_active_index_get;
(void)rna_Mesh_face_map_active_set;
(void)rna_Mesh_vertex_crease_index_range;
(void)rna_Mesh_edge_crease_index_range;
/* end unused function block */
}
@ -3291,6 +3353,40 @@ static void rna_def_vertex_creases(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
}
static void rna_def_edge_creases(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "MeshEdgeCreaseLayer", NULL);
RNA_def_struct_ui_text(srna, "Mesh Edge Crease Layer", "Per-edge crease");
RNA_def_struct_sdna(srna, "CustomDataLayer");
RNA_def_struct_path_func(srna, "rna_MeshEdgeCreaseLayer_path");
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshEdgeCrease");
RNA_def_property_ui_text(prop, "Data", "");
RNA_def_property_collection_funcs(prop,
"rna_MeshEdgeCreaseLayer_data_begin",
"rna_iterator_array_next",
"rna_iterator_array_end",
"rna_iterator_array_get",
"rna_MeshEdgeCreaseLayer_data_length",
NULL,
NULL,
NULL);
/* EdgeCrease struct */
srna = RNA_def_struct(brna, "MeshEdgeCrease", NULL);
RNA_def_struct_sdna(srna, "MFloatProperty");
RNA_def_struct_ui_text(srna, "Float Property", "");
prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f");
RNA_def_property_ui_text(prop, "Value", "");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
}
static void rna_def_paint_mask(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
{
StructRNA *srna;
@ -3765,6 +3861,24 @@ static void rna_def_mesh(BlenderRNA *brna)
rna_def_vertex_creases(brna);
/* End vertex crease */
/* Vertex Crease */
prop = RNA_def_property(srna, "edge_creases", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshEdgeCreaseLayer");
RNA_def_property_collection_sdna(prop, NULL, "edata.layers", "edata.totlayer");
RNA_def_property_collection_funcs(prop,
"rna_Mesh_edge_creases_begin",
NULL,
NULL,
NULL,
"rna_Mesh_edge_creases_length",
NULL,
NULL,
NULL);
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_ui_text(prop, "Edge Creases", "Sharpness of the edges for subdivision");
rna_def_edge_creases(brna);
/* End edge crease */
/* Paint mask */
prop = RNA_def_property(srna, "vertex_paint_masks", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "vdata.layers", "vdata.totlayer");
@ -3910,6 +4024,17 @@ static void rna_def_mesh(BlenderRNA *brna)
prop, "Has Vertex Bevel Weight", "True if the mesh has an vertex bevel weight layer");
RNA_def_property_boolean_funcs(prop, "rna_Mesh_has_vertex_bevel_weight_get", NULL);
prop = RNA_def_property(srna, "has_crease_edge", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Has Edge Crease", "True if the mesh has an edge crease layer");
RNA_def_property_boolean_funcs(prop, "rna_Mesh_has_edge_crease_get", NULL);
prop = RNA_def_property(srna, "has_crease_vertex", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Has Vertex Crease", "True if the mesh has an vertex crease layer");
RNA_def_property_boolean_funcs(prop, "rna_Mesh_has_vertex_crease_get", NULL);
prop = RNA_def_property(srna, "texco_mesh", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "texcomesh");
RNA_def_property_flag(prop, PROP_EDITABLE);
@ -3962,16 +4087,6 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_VERTEXSEL, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_Mesh_update_vertmask");
/* customdata flags */
prop = RNA_def_property(srna, "use_customdata_vertex_crease", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "cd_flag", ME_CDFLAG_VERT_CREASE);
RNA_def_property_ui_text(prop, "Store Vertex Crease", "");
prop = RNA_def_property(srna, "use_customdata_edge_crease", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "cd_flag", ME_CDFLAG_EDGE_CREASE);
RNA_def_property_ui_text(prop, "Store Edge Crease", "");
/* readonly editmesh info - use for extrude menu */
prop = RNA_def_property(srna, "total_vert_sel", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop, "rna_Mesh_tot_vert_get", NULL, NULL);

View File

@ -444,7 +444,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
for (i = 0; i < totedge; i++, med_orig++, med_new++) {
med_new->v1 = med_orig->v1;
med_new->v2 = med_orig->v2;
med_new->crease = med_orig->crease;
med_new->flag = med_orig->flag & ~ME_LOOSEEDGE;
/* Tag #MVert as not loose. */
@ -1064,7 +1063,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
med_new->v1 = i1;
med_new->v2 = i2;
med_new->flag = med_new_firstloop->flag;
med_new->crease = med_new_firstloop->crease;
med_new++;
}
i1 += totvert;
@ -1092,7 +1090,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
med_new->v1 = i1;
med_new->v2 = i2;
med_new->flag = med_new_firstloop->flag & ~ME_LOOSEEDGE;
med_new->crease = med_new_firstloop->crease;
med_new++;
}

View File

@ -1024,16 +1024,17 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
NULL;
float nor[3];
#endif
const uchar crease_rim = smd->crease_rim * 255.0f;
const uchar crease_outer = smd->crease_outer * 255.0f;
const uchar crease_inner = smd->crease_inner * 255.0f;
const float crease_rim = smd->crease_rim;
const float crease_outer = smd->crease_outer;
const float crease_inner = smd->crease_inner;
int *origindex_edge;
int *orig_ed;
uint j;
float *result_edge_crease = NULL;
if (crease_rim || crease_outer || crease_inner) {
result->cd_flag |= ME_CDFLAG_EDGE_CREASE;
result_edge_crease = (float *)CustomData_get_layer(&result->edata, CD_CREASE);
}
/* add faces & edges */
@ -1051,7 +1052,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
}
if (crease_rim) {
ed->crease = crease_rim;
result_edge_crease[ed - medge] = crease_rim;
}
}
@ -1140,16 +1141,16 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
}
if (crease_outer) {
/* crease += crease_outer; without wrapping */
char *cr = &(ed->crease);
int tcr = *cr + crease_outer;
*cr = tcr > 255 ? 255 : tcr;
float *cr = &(result_edge_crease[ed - medge]);
float tcr = *cr + crease_outer;
*cr = tcr > 1.0f ? 1.0f : tcr;
}
if (crease_inner) {
/* crease += crease_inner; without wrapping */
char *cr = &(medge[edges_num + (do_shell ? eidx : i)].crease);
int tcr = *cr + crease_inner;
*cr = tcr > 255 ? 255 : tcr;
float *cr = &(result_edge_crease[edges_num + (do_shell ? eidx : i)]);
float tcr = *cr + crease_inner;
*cr = tcr > 1.0f ? 1.0f : tcr;
}
#ifdef SOLIDIFY_SIDE_NORMALS

View File

@ -192,6 +192,7 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
/* These might be null. */
const float *orig_vert_bweight = CustomData_get_layer(&mesh->vdata, CD_BWEIGHT);
const float *orig_edge_bweight = CustomData_get_layer(&mesh->edata, CD_BWEIGHT);
const float *orig_edge_crease = CustomData_get_layer(&mesh->edata, CD_CREASE);
uint new_verts_num = 0;
uint new_edges_num = 0;
@ -1984,12 +1985,13 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
/* Get vertex crease layer and ensure edge creases are active if vertex creases are found, since
* they will introduce edge creases in the used custom interpolation method. */
const float *vertex_crease = CustomData_get_layer(&mesh->vdata, CD_CREASE);
float *result_edge_crease = NULL;
if (vertex_crease) {
result->cd_flag |= ME_CDFLAG_EDGE_CREASE;
result_edge_crease = (float *)CustomData_add_layer(
&result->edata, CD_CREASE, CD_SET_DEFAULT, NULL, result->totedge);
/* delete all vertex creases in the result if a rim is used. */
if (do_rim) {
CustomData_free_layers(&result->vdata, CD_CREASE, result->totvert);
result->cd_flag &= (char)(~ME_CDFLAG_VERT_CREASE);
}
}
@ -2042,7 +2044,10 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
medge[insert].v1 = v1;
medge[insert].v2 = v2;
medge[insert].flag = orig_medge[(*l)->old_edge].flag | ME_EDGEDRAW | ME_EDGERENDER;
medge[insert].crease = orig_medge[(*l)->old_edge].crease;
if (result_edge_crease) {
result_edge_crease[insert] = orig_edge_crease ? orig_edge_crease[(*l)->old_edge] :
0.0f;
}
if (result_edge_bweight) {
result_edge_bweight[insert] = orig_edge_bweight[(*l)->old_edge];
}
@ -2118,12 +2123,12 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
EdgeGroup *g2 = gs;
EdgeGroup *last_g = NULL;
EdgeGroup *first_g = NULL;
char mv_crease = vertex_crease ? (char)(vertex_crease[i] * 255.0f) : 0;
float mv_crease = vertex_crease ? vertex_crease[i] : 0.0f;
float mv_bweight = orig_vert_bweight ? orig_vert_bweight[i] : 0.0f;
/* Data calculation cache. */
char max_crease;
char last_max_crease = 0;
char first_max_crease = 0;
float max_crease;
float last_max_crease = 0.0f;
float first_max_crease = 0.0f;
float max_bweight;
float last_max_bweight = 0.0f;
float first_max_bweight = 0.0f;
@ -2139,14 +2144,24 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
BLI_assert(g->edges_len >= 2);
if (g->edges_len == 2) {
max_crease = min_cc(orig_medge[g->edges[0]->old_edge].crease,
orig_medge[g->edges[1]->old_edge].crease);
if (result_edge_crease) {
if (orig_edge_crease) {
max_crease = min_ff(orig_edge_crease[g->edges[0]->old_edge],
orig_edge_crease[g->edges[1]->old_edge]);
}
else {
max_crease = 0.0f;
}
}
}
else {
for (uint k = 1; k < g->edges_len - 1; k++) {
const MEdge *ed = orig_medge + g->edges[k]->old_edge;
if (ed->crease > max_crease) {
max_crease = ed->crease;
const uint orig_edge_index = g->edges[k]->old_edge;
const MEdge *ed = &orig_medge[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];
}
}
if (g->edges[k]->new_edge != MOD_SOLIDIFY_EMPTY_TAG) {
if (result_edge_bweight) {
@ -2193,7 +2208,10 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
medge[edge_index].v2 = g->new_vert;
medge[edge_index].flag = ME_EDGEDRAW | ME_EDGERENDER |
((last_flag | flag) & (ME_SEAM | ME_SHARP));
medge[edge_index].crease = max_cc(mv_crease, min_cc(last_max_crease, max_crease));
if (result_edge_crease) {
result_edge_crease[edge_index] = max_ff(mv_crease,
min_ff(last_max_crease, max_crease));
}
if (result_edge_bweight) {
result_edge_bweight[edge_index] = max_ff(mv_bweight,
min_ff(last_max_bweight, max_bweight));
@ -2224,8 +2242,10 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
medge[edge_index].v2 = first_g->new_vert;
medge[edge_index].flag = ME_EDGEDRAW | ME_EDGERENDER |
((last_flag | first_flag) & (ME_SEAM | ME_SHARP));
medge[edge_index].crease = max_cc(mv_crease,
min_cc(last_max_crease, first_max_crease));
if (result_edge_crease) {
result_edge_crease[edge_index] = max_ff(mv_crease,
min_ff(last_max_crease, first_max_crease));
}
if (result_edge_bweight) {
result_edge_bweight[edge_index] = max_ff(
mv_bweight, min_ff(last_max_bweight, first_max_bweight));

View File

@ -150,7 +150,6 @@ static MEdge new_edge(const int v1, const int v2)
MEdge edge;
edge.v1 = v1;
edge.v2 = v2;
edge.crease = 0;
edge.flag = (ME_EDGEDRAW | ME_EDGERENDER);
return edge;
}
@ -160,7 +159,6 @@ static MEdge new_loose_edge(const int v1, const int v2)
MEdge edge;
edge.v1 = v1;
edge.v2 = v2;
edge.crease = 0;
edge.flag = ME_LOOSEEDGE;
return edge;
}