diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index b71a705eecb..0e7e81a2383 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -2289,26 +2289,12 @@ bool CustomData_merge(const CustomData *source, return changed; } -static bool attribute_stored_in_bmesh_flag(const StringRef name) -{ - return ELEM(name, - "position", - ".hide_vert", - ".hide_edge", - ".hide_poly", - ".select_vert", - ".select_edge", - ".select_poly", - "material_index", - "sharp_edge"); -} - CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData *src, const eCustomDataMask mask) { Vector dst_layers; for (const CustomDataLayer &layer : Span{src->layers, src->totlayer}) { - if (attribute_stored_in_bmesh_flag(layer.name)) { + if (BM_attribute_stored_in_bmesh_builtin(layer.name)) { continue; } if (!(mask & CD_TYPE_AS_MASK(layer.type))) { diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc index d58337400a2..0980f8d1918 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc @@ -133,6 +133,20 @@ static char bm_face_flag_to_mflag(const BMFace *f) return ((hflag & BM_ELEM_SMOOTH) ? ME_SMOOTH : 0); } +bool BM_attribute_stored_in_bmesh_builtin(const StringRef name) +{ + return ELEM(name, + "position", + ".hide_vert", + ".hide_edge", + ".hide_poly", + ".select_vert", + ".select_edge", + ".select_poly", + "material_index", + "sharp_edge"); +} + /* Static function for alloc (duplicate in modifiers_bmesh.c) */ static BMFace *bm_face_create_from_mpoly(BMesh &bm, Span loops, diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.h b/source/blender/bmesh/intern/bmesh_mesh_convert.h index 82b6d41b19b..bd6492d6ec6 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.h +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.h @@ -9,6 +9,16 @@ #include "bmesh.h" +#ifdef __cplusplus +# include "BLI_string_ref.hh" + +/** + * \return Whether attributes with the given name are stored in special flags or fields in BMesh + * rather than in the regular custom data blocks. + */ +bool BM_attribute_stored_in_bmesh_builtin(const blender::StringRef name); +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc b/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc index a77b73ebaae..232839c6863 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc @@ -274,15 +274,14 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator * /*op*/) return OPERATOR_FINISHED; } - static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoWarnFlag flag) { uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Warning!"), ICON_ERROR); uiLayout *layout = UI_popup_menu_layout(pup); if (flag & (DYNTOPO_WARN_VDATA | DYNTOPO_WARN_EDATA | DYNTOPO_WARN_LDATA)) { - const char *msg_error = TIP_("Vertex Data Detected!"); - const char *msg = TIP_("Dyntopo will not preserve vertex colors, UVs, or other customdata"); + const char *msg_error = TIP_("Attribute Data Detected"); + const char *msg = TIP_("Dyntopo will not preserve colors, UVs, or other attributes"); uiItemL(layout, msg_error, ICON_INFO); uiItemL(layout, msg, ICON_NONE); uiItemS(layout); @@ -305,6 +304,24 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoW return OPERATOR_INTERFACE; } +static bool dyntopo_supports_customdata_type(const CustomDataLayer &layer) +{ + if (CD_TYPE_AS_MASK(layer.type) & CD_MASK_PROP_ALL) { + if (layer.name[0] == '\0') { + return false; + } + /* Some data is stored as generic attributes on #Mesh but in flags or field on #BMesh. */ + return BM_attribute_stored_in_bmesh_builtin(layer.name); + } + /* Some layers just encode #Mesh topology or are handled as special cases for dyntopo. */ + return ELEM(layer.type, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX); +} + +static bool dyntopo_supports_customdata_layers(const blender::Span layers) +{ + return std::all_of(layers.begin(), layers.end(), dyntopo_supports_customdata_type); +} + enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob) { Mesh *me = static_cast(ob->data); @@ -315,18 +332,17 @@ enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob) BLI_assert(ss->bm == nullptr); UNUSED_VARS_NDEBUG(ss); - for (int i = 0; i < CD_NUMTYPES; i++) { - if (!ELEM(i, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX)) { - if (CustomData_has_layer(&me->vdata, i)) { - flag |= DYNTOPO_WARN_VDATA; - } - if (CustomData_has_layer(&me->edata, i)) { - flag |= DYNTOPO_WARN_EDATA; - } - if (CustomData_has_layer(&me->ldata, i)) { - flag |= DYNTOPO_WARN_LDATA; - } - } + if (!dyntopo_supports_customdata_layers({me->vdata.layers, me->vdata.totlayer})) { + flag |= DYNTOPO_WARN_VDATA; + } + if (!dyntopo_supports_customdata_layers({me->edata.layers, me->edata.totlayer})) { + flag |= DYNTOPO_WARN_EDATA; + } + if (!dyntopo_supports_customdata_layers({me->pdata.layers, me->pdata.totlayer})) { + flag |= DYNTOPO_WARN_LDATA; + } + if (!dyntopo_supports_customdata_layers({me->ldata.layers, me->ldata.totlayer})) { + flag |= DYNTOPO_WARN_LDATA; } {