Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2022-01-21 14:47:35 +0300
committerJacques Lucke <jacques@blender.org>2022-01-21 14:47:35 +0300
commitf6888b530ac81abbe61755971449ad6b42b93c82 (patch)
treed5234ec992f73046f031e71d62cc47efe5cbcc64 /source
parent36c40760a5a38db733e20c948b2170ab78bb2607 (diff)
Attributes: add operator to convert generic attributes to other types
Editing of generic attributes on the original objects in edit modes is still very limited. However, when applying a geometry nodes modifier that generates new attributes. These attributes will show up in the Attributes panel. Currently, our exporters are not capable of exporting generic attributes. Therefore, for the time being, a work around is to apply geometry nodes and then convert a generic attribute to a task specific attribute like a uv map, vertex group or vertex color layer. Once more parts of Blender support generic attributes, this will become less important. Currently, only meshes are supported by the operator. However, it would be relatively easy to extend it to other geometry types. Differential Revision: https://developer.blender.org/D13838
Diffstat (limited to 'source')
-rw-r--r--source/blender/editors/geometry/CMakeLists.txt2
-rw-r--r--source/blender/editors/geometry/geometry_attributes.cc205
-rw-r--r--source/blender/editors/geometry/geometry_intern.hh5
-rw-r--r--source/blender/editors/geometry/geometry_ops.cc3
-rw-r--r--source/blender/makesrna/RNA_enum_types.h4
-rw-r--r--source/blender/makesrna/intern/rna_attribute.c9
6 files changed, 224 insertions, 4 deletions
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)