diff options
-rw-r--r-- | release/scripts/startup/bl_ui/properties_data_mesh.py | 13 | ||||
-rw-r--r-- | source/blender/editors/geometry/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/editors/geometry/geometry_attributes.cc | 205 | ||||
-rw-r--r-- | source/blender/editors/geometry/geometry_intern.hh | 5 | ||||
-rw-r--r-- | source/blender/editors/geometry/geometry_ops.cc | 3 | ||||
-rw-r--r-- | source/blender/makesrna/RNA_enum_types.h | 4 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_attribute.c | 9 |
7 files changed, 237 insertions, 4 deletions
diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index 49f196640d8..11e2cd84903 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -82,6 +82,14 @@ class MESH_MT_shape_key_context_menu(Menu): layout.operator("object.shape_key_move", icon='TRIA_UP_BAR', text="Move to Top").type = 'TOP' layout.operator("object.shape_key_move", icon='TRIA_DOWN_BAR', text="Move to Bottom").type = 'BOTTOM' +class MESH_MT_attribute_context_menu(Menu): + bl_label = "Attribute Specials" + + def draw(self, context): + layout = self.layout + + layout.operator("geometry.attribute_convert") + class MESH_UL_vgroups(UIList): def draw_item(self, _context, layout, _data, item, icon, _active_data_, _active_propname, _index): @@ -615,6 +623,10 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel): col.operator("geometry.attribute_add", icon='ADD', text="") col.operator("geometry.attribute_remove", icon='REMOVE', text="") + col.separator() + + col.menu("MESH_MT_attribute_context_menu", icon='DOWNARROW_HLT', text="") + self.draw_attribute_warnings(context, layout) def draw_attribute_warnings(self, context, layout): @@ -652,6 +664,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel): classes = ( MESH_MT_vertex_group_context_menu, MESH_MT_shape_key_context_menu, + MESH_MT_attribute_context_menu, MESH_UL_vgroups, MESH_UL_fmaps, MESH_UL_shape_keys, diff --git a/source/blender/editors/geometry/CMakeLists.txt b/source/blender/editors/geometry/CMakeLists.txt index 65b9633da98..8c920915937 100644 --- a/source/blender/editors/geometry/CMakeLists.txt +++ b/source/blender/editors/geometry/CMakeLists.txt @@ -20,9 +20,11 @@ set(INC ../../blenkernel ../../blenlib ../../depsgraph + ../../functions ../../makesdna ../../makesrna ../../windowmanager + ../../../../intern/guardedalloc ) set(INC_SYS diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc index 9c0f6728701..56ecd108bba 100644 --- a/source/blender/editors/geometry/geometry_attributes.cc +++ b/source/blender/editors/geometry/geometry_attributes.cc @@ -21,8 +21,18 @@ * \ingroup edgeometry */ +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" + #include "BKE_attribute.h" #include "BKE_context.h" +#include "BKE_deform.h" +#include "BKE_geometry_set.hh" +#include "BKE_object_deform.h" +#include "BKE_report.h" #include "RNA_access.h" #include "RNA_define.h" @@ -33,10 +43,19 @@ #include "WM_api.h" #include "WM_types.h" +#include "UI_interface.h" +#include "UI_resources.h" + #include "ED_object.h" #include "geometry_intern.hh" +namespace blender::ed::geometry { + +using fn::CPPType; +using fn::GArray; +using fn::GVArray; + /*********************** Attribute Operators ************************/ static bool geometry_attributes_poll(bContext *C) @@ -76,7 +95,7 @@ static const EnumPropertyItem *geometry_attribute_domain_itemf(bContext *C, return DummyRNA_NULL_items; } - return rna_enum_attribute_domain_itemf(static_cast<ID *>(ob->data), r_free); + return rna_enum_attribute_domain_itemf(static_cast<ID *>(ob->data), false, r_free); } static int geometry_attribute_add_exec(bContext *C, wmOperator *op) @@ -180,3 +199,187 @@ void GEOMETRY_OT_attribute_remove(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +enum class ConvertAttributeMode { + Generic, + UVMap, + VertexGroup, + VertexColor, +}; + +static bool geometry_attribute_convert_poll(bContext *C) +{ + if (!geometry_attributes_poll(C)) { + return false; + } + + Object *ob = ED_object_context(C); + ID *data = static_cast<ID *>(ob->data); + if (GS(data->name) != ID_ME) { + return false; + } + CustomDataLayer *layer = BKE_id_attributes_active_get(data); + if (layer == nullptr) { + return false; + } + return true; +} + +static int geometry_attribute_convert_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_context(C); + ID *ob_data = static_cast<ID *>(ob->data); + CustomDataLayer *layer = BKE_id_attributes_active_get(ob_data); + const std::string name = layer->name; + + const ConvertAttributeMode mode = static_cast<ConvertAttributeMode>( + RNA_enum_get(op->ptr, "mode")); + + Mesh *mesh = reinterpret_cast<Mesh *>(ob_data); + MeshComponent mesh_component; + mesh_component.replace(mesh, GeometryOwnershipType::Editable); + + /* General conversion steps are always the same: + * 1. Convert old data to right domain and data type. + * 2. Copy the data into a new array so that it does not depend on the old attribute anymore. + * 3. Delete the old attribute. + * 4. Create a new attribute based on the previously copied data. */ + switch (mode) { + case ConvertAttributeMode::Generic: { + const AttributeDomain dst_domain = static_cast<AttributeDomain>( + RNA_enum_get(op->ptr, "domain")); + const CustomDataType dst_type = static_cast<CustomDataType>( + RNA_enum_get(op->ptr, "data_type")); + + if (ELEM(dst_type, CD_PROP_STRING, CD_MLOOPCOL)) { + BKE_report(op->reports, RPT_ERROR, "Cannot convert to the selected type"); + return OPERATOR_CANCELLED; + } + + GVArray src_varray = mesh_component.attribute_get_for_read(name, dst_domain, dst_type); + const CPPType &cpp_type = src_varray.type(); + void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__); + src_varray.materialize_to_uninitialized(new_data); + mesh_component.attribute_try_delete(name); + mesh_component.attribute_try_create(name, dst_domain, dst_type, AttributeInitMove(new_data)); + break; + } + case ConvertAttributeMode::UVMap: { + MLoopUV *dst_uvs = static_cast<MLoopUV *>( + MEM_calloc_arrayN(mesh->totloop, sizeof(MLoopUV), __func__)); + VArray<float2> src_varray = mesh_component.attribute_get_for_read<float2>( + name, ATTR_DOMAIN_CORNER, {0.0f, 0.0f}); + for (const int i : IndexRange(mesh->totloop)) { + copy_v2_v2(dst_uvs[i].uv, src_varray[i]); + } + mesh_component.attribute_try_delete(name); + CustomData_add_layer_named( + &mesh->ldata, CD_MLOOPUV, CD_ASSIGN, dst_uvs, mesh->totloop, name.c_str()); + break; + } + case ConvertAttributeMode::VertexColor: { + MLoopCol *dst_colors = static_cast<MLoopCol *>( + MEM_calloc_arrayN(mesh->totloop, sizeof(MLoopCol), __func__)); + VArray<ColorGeometry4f> src_varray = mesh_component.attribute_get_for_read<ColorGeometry4f>( + name, ATTR_DOMAIN_CORNER, ColorGeometry4f{0.0f, 0.0f, 0.0f, 1.0f}); + for (const int i : IndexRange(mesh->totloop)) { + ColorGeometry4b encoded_color = src_varray[i].encode(); + copy_v4_v4_uchar(&dst_colors[i].r, &encoded_color.r); + } + mesh_component.attribute_try_delete(name); + CustomData_add_layer_named( + &mesh->ldata, CD_MLOOPCOL, CD_ASSIGN, dst_colors, mesh->totloop, name.c_str()); + break; + } + case ConvertAttributeMode::VertexGroup: { + Array<float> src_weights(mesh->totvert); + VArray<float> src_varray = mesh_component.attribute_get_for_read<float>( + name, ATTR_DOMAIN_POINT, 0.0f); + src_varray.materialize(src_weights); + mesh_component.attribute_try_delete(name); + + bDeformGroup *defgroup = BKE_object_defgroup_new(ob, name.c_str()); + const int defgroup_index = BLI_findindex(BKE_id_defgroup_list_get(&mesh->id), defgroup); + MDeformVert *dverts = BKE_object_defgroup_data_create(&mesh->id); + for (const int i : IndexRange(mesh->totvert)) { + const float weight = src_weights[i]; + if (weight > 0.0f) { + BKE_defvert_add_index_notest(dverts + i, defgroup_index, weight); + } + } + break; + } + } + + int *active_index = BKE_id_attributes_active_index_p(&mesh->id); + if (*active_index > 0) { + *active_index -= 1; + } + + DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_GEOM | ND_DATA, &mesh->id); + + return OPERATOR_FINISHED; +} + +static void geometry_attribute_convert_ui(bContext *UNUSED(C), wmOperator *op) +{ + uiLayout *layout = op->layout; + + uiItemR(layout, op->ptr, "mode", 0, nullptr, ICON_NONE); + + const ConvertAttributeMode mode = static_cast<ConvertAttributeMode>( + RNA_enum_get(op->ptr, "mode")); + + if (mode == ConvertAttributeMode::Generic) { + uiItemR(layout, op->ptr, "domain", 0, nullptr, ICON_NONE); + uiItemR(layout, op->ptr, "data_type", 0, nullptr, ICON_NONE); + } +} + +static int geometry_attribute_convert_invoke(bContext *C, + wmOperator *op, + const wmEvent *UNUSED(event)) +{ + return WM_operator_props_dialog_popup(C, op, 300); +} + +void GEOMETRY_OT_attribute_convert(wmOperatorType *ot) +{ + ot->name = "Convert Attribute"; + ot->description = "Change how the attribute is stored"; + ot->idname = "GEOMETRY_OT_attribute_convert"; + + ot->invoke = geometry_attribute_convert_invoke; + ot->exec = geometry_attribute_convert_exec; + ot->poll = geometry_attribute_convert_poll; + ot->ui = geometry_attribute_convert_ui; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + static EnumPropertyItem mode_items[] = { + {int(ConvertAttributeMode::Generic), "GENERIC", 0, "Generic", ""}, + {int(ConvertAttributeMode::UVMap), "UV_MAP", 0, "UV Map", ""}, + {int(ConvertAttributeMode::VertexGroup), "VERTEX_GROUP", 0, "Vertex Group", ""}, + {int(ConvertAttributeMode::VertexColor), "VERTEX_COLOR", 0, "Vertex Color", ""}, + {0, nullptr, 0, nullptr, nullptr}, + }; + + PropertyRNA *prop; + + RNA_def_enum( + ot->srna, "mode", mode_items, static_cast<int>(ConvertAttributeMode::Generic), "Mode", ""); + + prop = RNA_def_enum(ot->srna, + "domain", + rna_enum_attribute_domain_items, + ATTR_DOMAIN_POINT, + "Domain", + "Which geometry element to move the attribute to"); + RNA_def_enum_funcs(prop, geometry_attribute_domain_itemf); + + RNA_def_enum( + ot->srna, "data_type", rna_enum_attribute_type_items, CD_PROP_FLOAT, "Data Type", ""); +} + +} // namespace blender::ed::geometry diff --git a/source/blender/editors/geometry/geometry_intern.hh b/source/blender/editors/geometry/geometry_intern.hh index 14992476edd..30a2a1d6eb1 100644 --- a/source/blender/editors/geometry/geometry_intern.hh +++ b/source/blender/editors/geometry/geometry_intern.hh @@ -25,6 +25,11 @@ struct wmOperatorType; +namespace blender::ed::geometry { + /* *** geometry_attributes.cc *** */ void GEOMETRY_OT_attribute_add(struct wmOperatorType *ot); void GEOMETRY_OT_attribute_remove(struct wmOperatorType *ot); +void GEOMETRY_OT_attribute_convert(struct wmOperatorType *ot); + +} // namespace blender::ed::geometry diff --git a/source/blender/editors/geometry/geometry_ops.cc b/source/blender/editors/geometry/geometry_ops.cc index ba8afe0e62f..8933b2a7f00 100644 --- a/source/blender/editors/geometry/geometry_ops.cc +++ b/source/blender/editors/geometry/geometry_ops.cc @@ -31,6 +31,9 @@ void ED_operatortypes_geometry(void) { + using namespace blender::ed::geometry; + WM_operatortype_append(GEOMETRY_OT_attribute_add); WM_operatortype_append(GEOMETRY_OT_attribute_remove); + WM_operatortype_append(GEOMETRY_OT_attribute_convert); } diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index da07f1043a7..fcae1009c8b 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -35,7 +35,9 @@ struct bNodeType; #define DEF_ENUM(id) extern const EnumPropertyItem id[]; #include "RNA_enum_items.h" -extern const EnumPropertyItem *rna_enum_attribute_domain_itemf(struct ID *id, bool *r_free); +extern const EnumPropertyItem *rna_enum_attribute_domain_itemf(struct ID *id, + bool include_instances, + bool *r_free); /** * For ID filters (#FILTER_ID_AC, #FILTER_ID_AR, ...) an int isn't enough. This version allows 64 diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c index 78c15444308..35da353a043 100644 --- a/source/blender/makesrna/intern/rna_attribute.c +++ b/source/blender/makesrna/intern/rna_attribute.c @@ -166,7 +166,9 @@ static int rna_Attribute_type_get(PointerRNA *ptr) return layer->type; } -const EnumPropertyItem *rna_enum_attribute_domain_itemf(ID *id, bool *r_free) +const EnumPropertyItem *rna_enum_attribute_domain_itemf(ID *id, + bool include_instances, + bool *r_free) { EnumPropertyItem *item = NULL; const EnumPropertyItem *domain_item = NULL; @@ -188,6 +190,9 @@ const EnumPropertyItem *rna_enum_attribute_domain_itemf(ID *id, bool *r_free) if (id_type == ID_ME && ELEM(domain_item->value, ATTR_DOMAIN_CURVE)) { continue; } + if (!include_instances && domain_item->value == ATTR_DOMAIN_INSTANCE) { + continue; + } if (domain_item->value == ATTR_DOMAIN_POINT && id_type == ID_ME) { RNA_enum_item_add(&item, &totitem, &mesh_vertex_domain_item); @@ -207,7 +212,7 @@ static const EnumPropertyItem *rna_Attribute_domain_itemf(bContext *UNUSED(C), PropertyRNA *UNUSED(prop), bool *r_free) { - return rna_enum_attribute_domain_itemf(ptr->owner_id, r_free); + return rna_enum_attribute_domain_itemf(ptr->owner_id, true, r_free); } static int rna_Attribute_domain_get(PointerRNA *ptr) |