[Bf-blender-cvs] [9c28f0eb37a] master: D14823: Adds operator to duplicate the active color attribute layer

Dennis Ranish noreply at git.blender.org
Wed Jun 8 21:12:10 CEST 2022


Commit: 9c28f0eb37aebd6e5eae0763b008ef02d5ce081b
Author: Dennis Ranish
Date:   Wed Jun 8 12:10:32 2022 -0700
Branches: master
https://developer.blender.org/rB9c28f0eb37aebd6e5eae0763b008ef02d5ce081b

D14823: Adds operator to duplicate the active color attribute layer

Fixes T97706

Adds operator to duplicate the active color attribute layer.
Adds `"Color Attribute Specials"` menu to color attribute ui to access the `"geometry.color_attribute_duplicate"` operator.
Internally adds a function that duplicates a referenced CustomDataLayer
- `BKE_id_attribute_duplicate` mostly copies the existing `BKE_id_attribute_new`
- but gets the type and domain from the referenced layer
- and copies the data from the old layer into the new layer

Reviewed By: Joseph Eagar & Hans Goudey & Julien Kaspar
Differential Revision: https://developer.blender.org/D14823
Ref D14823

===================================================================

M	release/scripts/startup/bl_ui/properties_data_mesh.py
M	source/blender/blenkernel/BKE_attribute.h
M	source/blender/blenkernel/intern/attribute.cc
M	source/blender/editors/geometry/geometry_attributes.cc
M	source/blender/editors/geometry/geometry_intern.hh
M	source/blender/editors/geometry/geometry_ops.cc

===================================================================

diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index 15d25f71419..764299e7ce3 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -64,6 +64,18 @@ class MESH_MT_shape_key_context_menu(Menu):
         layout.operator("object.shape_key_move", icon='TRIA_DOWN_BAR', text="Move to Bottom").type = 'BOTTOM'
 
 
+class MESH_MT_color_attribute_context_menu(Menu):
+    bl_label = "Color Attribute Specials"
+
+    def draw(self, _context):
+        layout = self.layout
+
+        props = layout.operator(
+            "geometry.color_attribute_duplicate",
+            icon='DUPLICATE',
+        )
+
+
 class MESH_MT_attribute_context_menu(Menu):
     bl_label = "Attribute Specials"
 
@@ -660,12 +672,16 @@ class DATA_PT_vertex_colors(DATA_PT_mesh_attributes, Panel):
         col.operator("geometry.color_attribute_add", icon='ADD', text="")
         col.operator("geometry.color_attribute_remove", icon='REMOVE', text="")
 
-        self.draw_attribute_warnings(context, layout)
+        col.separator()
 
+        col.menu("MESH_MT_color_attribute_context_menu", icon='DOWNARROW_HLT', text="")
+
+        self.draw_attribute_warnings(context, layout)
 
 classes = (
     MESH_MT_vertex_group_context_menu,
     MESH_MT_shape_key_context_menu,
+    MESH_MT_color_attribute_context_menu,
     MESH_MT_attribute_context_menu,
     MESH_UL_vgroups,
     MESH_UL_fmaps,
diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h
index 52a3e01026c..5755ddb3018 100644
--- a/source/blender/blenkernel/BKE_attribute.h
+++ b/source/blender/blenkernel/BKE_attribute.h
@@ -60,6 +60,13 @@ struct CustomDataLayer *BKE_id_attribute_new(
     struct ID *id, const char *name, int type, eAttrDomain domain, struct ReportList *reports);
 bool BKE_id_attribute_remove(struct ID *id, const char *name, struct ReportList *reports);
 
+/**
+ * Creates a duplicate attribute layer.
+ */
+struct CustomDataLayer *BKE_id_attribute_duplicate(struct ID *id,
+                                                   struct CustomDataLayer *layer,
+                                                   struct ReportList *reports);
+
 struct CustomDataLayer *BKE_id_attribute_find(const struct ID *id,
                                               const char *name,
                                               int type,
diff --git a/source/blender/blenkernel/intern/attribute.cc b/source/blender/blenkernel/intern/attribute.cc
index eac42d19b52..b2ea8b833b3 100644
--- a/source/blender/blenkernel/intern/attribute.cc
+++ b/source/blender/blenkernel/intern/attribute.cc
@@ -208,6 +208,55 @@ CustomDataLayer *BKE_id_attribute_new(
   return (index == -1) ? nullptr : &(customdata->layers[index]);
 }
 
+CustomDataLayer *BKE_id_attribute_duplicate(ID *id, CustomDataLayer *layer, ReportList *reports)
+{
+  DomainInfo info[ATTR_DOMAIN_NUM];
+  get_domains(id, info);
+
+  eCustomDataType type = (eCustomDataType)layer->type;
+  eAttrDomain domain = BKE_id_attribute_domain(id, layer);
+
+  CustomData *customdata = info[domain].customdata;
+  if (customdata == nullptr) {
+    BKE_report(reports, RPT_ERROR, "Attribute domain not supported by this geometry type");
+    return nullptr;
+  }
+
+  char name[MAX_CUSTOMDATA_LAYER_NAME];
+  char uniquename[MAX_CUSTOMDATA_LAYER_NAME];
+
+  /* Make a copy of name in case CustomData API reallocates the layers. */
+  BLI_strncpy(name, layer->name, MAX_CUSTOMDATA_LAYER_NAME);
+  BKE_id_attribute_calc_unique_name(id, layer->name, uniquename);
+
+  switch (GS(id->name)) {
+    case ID_ME: {
+      Mesh *me = (Mesh *)id;
+      BMEditMesh *em = me->edit_mesh;
+      if (em != nullptr) {
+        BM_data_layer_add_named(em->bm, customdata, type, uniquename);
+      }
+      else {
+        CustomData_add_layer_named(
+            customdata, type, CD_DEFAULT, nullptr, info[domain].length, uniquename);
+      }
+      break;
+    }
+    default: {
+      CustomData_add_layer_named(
+          customdata, type, CD_DEFAULT, nullptr, info[domain].length, uniquename);
+      break;
+    }
+  }
+
+  int from_index = CustomData_get_named_layer_index(customdata, type, name);
+  int to_index = CustomData_get_named_layer_index(customdata, type, uniquename);
+  CustomData_copy_data_layer(
+      customdata, customdata, from_index, to_index, 0, 0, info[domain].length);
+
+  return (to_index == -1) ? nullptr : &(customdata->layers[to_index]);
+}
+
 bool BKE_id_attribute_remove(ID *id, const char *name, ReportList *reports)
 {
   if (BKE_id_attribute_required(id, name)) {
@@ -283,7 +332,7 @@ CustomDataLayer *BKE_id_attribute_search(const ID *id,
     }
 
     CustomData *customdata = info[domain].customdata;
-    if (customdata == NULL) {
+    if (customdata == nullptr) {
       continue;
     }
 
@@ -295,7 +344,7 @@ CustomDataLayer *BKE_id_attribute_search(const ID *id,
     }
   }
 
-  return NULL;
+  return nullptr;
 }
 
 int BKE_id_attributes_length(const ID *id, eAttrDomainMask domain_mask, eCustomDataMask mask)
diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc
index 63059a49a9e..37ec7a61bcb 100644
--- a/source/blender/editors/geometry/geometry_attributes.cc
+++ b/source/blender/editors/geometry/geometry_attributes.cc
@@ -498,6 +498,7 @@ static bool geometry_color_attributes_remove_poll(bContext *C)
 
   return false;
 }
+
 void GEOMETRY_OT_color_attribute_remove(wmOperatorType *ot)
 {
   /* identifiers */
@@ -513,6 +514,57 @@ void GEOMETRY_OT_color_attribute_remove(wmOperatorType *ot)
   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
+static int geometry_color_attribute_duplicate_exec(bContext *C, wmOperator *op)
+{
+  Object *ob = ED_object_context(C);
+  ID *id = static_cast<ID *>(ob->data);
+  CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
+
+  if (layer == nullptr) {
+    return OPERATOR_CANCELLED;
+  }
+
+  CustomDataLayer *newLayer = BKE_id_attribute_duplicate(id, layer, op->reports);
+
+  BKE_id_attributes_active_color_set(id, newLayer);
+
+  DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
+  WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+
+  return OPERATOR_FINISHED;
+}
+
+static bool geometry_color_attributes_duplicate_poll(bContext *C)
+{
+  if (!geometry_attributes_poll(C)) {
+    return false;
+  }
+
+  Object *ob = ED_object_context(C);
+  ID *data = ob ? static_cast<ID *>(ob->data) : nullptr;
+
+  if (BKE_id_attributes_active_color_get(data) != nullptr) {
+    return true;
+  }
+
+  return false;
+}
+
+void GEOMETRY_OT_color_attribute_duplicate(wmOperatorType *ot)
+{
+  /* identifiers */
+  ot->name = "Duplicate Color Attribute";
+  ot->description = "Duplicate color attribute";
+  ot->idname = "GEOMETRY_OT_color_attribute_duplicate";
+
+  /* api callbacks */
+  ot->exec = geometry_color_attribute_duplicate_exec;
+  ot->poll = geometry_color_attributes_duplicate_poll;
+
+  /* flags */
+  ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
 static void geometry_attribute_convert_ui(bContext *UNUSED(C), wmOperator *op)
 {
   uiLayout *layout = op->layout;
diff --git a/source/blender/editors/geometry/geometry_intern.hh b/source/blender/editors/geometry/geometry_intern.hh
index bbcb682d6bf..a1000a5d01f 100644
--- a/source/blender/editors/geometry/geometry_intern.hh
+++ b/source/blender/editors/geometry/geometry_intern.hh
@@ -17,6 +17,7 @@ void GEOMETRY_OT_attribute_remove(struct wmOperatorType *ot);
 void GEOMETRY_OT_color_attribute_add(struct wmOperatorType *ot);
 void GEOMETRY_OT_color_attribute_remove(struct wmOperatorType *ot);
 void GEOMETRY_OT_color_attribute_render_set(struct wmOperatorType *ot);
+void GEOMETRY_OT_color_attribute_duplicate(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 23f6e6f29f4..acac757ecf1 100644
--- a/source/blender/editors/geometry/geometry_ops.cc
+++ b/source/blender/editors/geometry/geometry_ops.cc
@@ -22,5 +22,6 @@ void ED_operatortypes_geometry(void)
   WM_operatortype_append(GEOMETRY_OT_color_attribute_add);
   WM_operatortype_append(GEOMETRY_OT_color_attribute_remove);
   WM_operatortype_append(GEOMETRY_OT_color_attribute_render_set);
+  WM_operatortype_append(GEOMETRY_OT_color_attribute_duplicate);
   WM_operatortype_append(GEOMETRY_OT_attribute_convert);
 }



More information about the Bf-blender-cvs mailing list