Commit: 9de320d8829157116878e078eb7801f306d242b6
Author: Antonioya
Date:   Mon Aug 27 16:29:19 2018 +0200
Branches: blender2.8
https://developer.blender.org/rB9de320d8829157116878e078eb7801f306d242b6

GP: New operator to copy layers between objects

The operator allows to copy a complete layer with all frames or only active 
frame to a new object.

Can be found in edit specials menu (W key) or in Layers specials menu (last 
button near layer list).

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

M       release/scripts/startup/bl_ui/properties_data_gpencil.py
M       release/scripts/startup/bl_ui/space_view3d.py
M       source/blender/editors/gpencil/gpencil_data.c
M       source/blender/editors/gpencil/gpencil_intern.h
M       source/blender/editors/gpencil/gpencil_ops.c

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

diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py 
b/release/scripts/startup/bl_ui/properties_data_gpencil.py
index a63a8e10c08..601c014bb48 100644
--- a/release/scripts/startup/bl_ui/properties_data_gpencil.py
+++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py
@@ -124,6 +124,9 @@ class GPENCIL_MT_layer_specials(Menu):
 
         layout.operator("gpencil.layer_merge", icon='NLA', text="Merge Down")
 
+        layout.separator()
+        layout.menu("VIEW3D_MT_gpencil_copy_layer")
+
 
 class DATA_PT_gpencil_datapanel(Panel):
     bl_space_type = 'PROPERTIES'
diff --git a/release/scripts/startup/bl_ui/space_view3d.py 
b/release/scripts/startup/bl_ui/space_view3d.py
index 35fb3afb5a6..7f56e2841ae 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -3573,6 +3573,28 @@ class VIEW3D_MT_assign_material(Menu):
             layout.operator("gpencil.stroke_change_color", 
text=mat.name).material = mat.name
 
 
+class VIEW3D_MT_gpencil_copy_layer(Menu):
+    bl_label = "Copy Layer to Object"
+
+    def draw(self, context):
+        layout = self.layout
+        view_layer = context.view_layer
+        obact = context.active_object
+        gpl = context.active_gpencil_layer
+
+        done = False
+        if gpl is not None:
+            for ob in view_layer.objects:
+                if ob.type == 'GPENCIL' and ob != obact:
+                    layout.operator("gpencil.layer_duplicate_object", 
text=ob.name).object = ob.name
+                    done = True
+
+            if done is False:
+                layout.label("No destination object", icon="ERROR")
+        else:
+            layout.label("No layer to copy", icon="ERROR")
+
+
 class VIEW3D_MT_edit_gpencil(Menu):
     bl_label = "Strokes"
 
@@ -4954,6 +4976,9 @@ class VIEW3D_MT_gpencil_edit_specials(Menu):
         layout.separator()
         layout.operator_menu_enum("gpencil.stroke_arrange", "direction", 
text="Arrange Strokes")
 
+        layout.separator()
+        layout.menu("VIEW3D_MT_gpencil_copy_layer")
+
         layout.separator()
 
         layout.operator("gpencil.stroke_join", text="Join").type = 'JOIN'
@@ -5105,6 +5130,7 @@ classes = (
     VIEW3D_MT_weight_gpencil,
     VIEW3D_MT_gpencil_animation,
     VIEW3D_MT_gpencil_simplify,
+    VIEW3D_MT_gpencil_copy_layer,
     VIEW3D_MT_edit_curve,
     VIEW3D_MT_edit_curve_ctrlpoints,
     VIEW3D_MT_edit_curve_segments,
diff --git a/source/blender/editors/gpencil/gpencil_data.c 
b/source/blender/editors/gpencil/gpencil_data.c
index d7e58609d2d..954d012fd24 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -418,6 +418,144 @@ void GPENCIL_OT_layer_duplicate(wmOperatorType *ot)
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
+/* ********************* Duplicate Layer in a new object 
************************** */
+enum {
+       GP_LAYER_COPY_OBJECT_ALL_FRAME = 0,
+       GP_LAYER_COPY_OBJECT_ACT_FRAME = 1
+};
+
+bool gp_layer_duplicate_object_poll(bContext *C)
+{
+       ViewLayer *view_layer = CTX_data_view_layer(C);
+       Object *ob = CTX_data_active_object(C);
+       if ((ob == NULL) || (ob->type != OB_GPENCIL))
+               return false;
+
+       bGPdata *gpd = (bGPdata *)ob->data;
+       bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+
+       if (gpl == NULL)
+               return false;
+
+       /* check there are more grease pencil objects */
+       for (Base *base = view_layer->object_bases.first; base; base = 
base->next) {
+               if ((base->object != ob) && (base->object->type == OB_GPENCIL))
+                       return true;
+       }
+
+       return false;
+}
+
+static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
+{
+       Main *bmain = CTX_data_main(C);
+       Scene *scene = CTX_data_scene(C);
+       char name[MAX_ID_NAME - 2];
+       RNA_string_get(op->ptr, "object", name);
+
+       if (name[0] == '\0') {
+               return OPERATOR_CANCELLED;
+       }
+
+       Object *ob_dst = (Object *)BKE_scene_object_find_by_name(scene, name);
+
+       int mode = RNA_enum_get(op->ptr, "mode");
+
+       Object *ob_src = CTX_data_active_object(C);
+       bGPdata *gpd_src = (bGPdata *)ob_src->data;
+       bGPDlayer *gpl_src = BKE_gpencil_layer_getactive(gpd_src);
+
+       /* sanity checks */
+       if (ELEM(NULL, gpd_src, gpl_src, ob_dst)) {
+               return OPERATOR_CANCELLED;
+       }
+       /* cannot copy itself and check destination type */
+       if ((ob_src == ob_dst) || (ob_dst->type != OB_GPENCIL)) {
+               return OPERATOR_CANCELLED;
+       }
+
+       bGPdata *gpd_dst = (bGPdata *)ob_dst->data;
+
+       /* make copy of layer */
+       bGPDlayer *gpl_dst = MEM_dupallocN(gpl_src);
+       gpl_dst->prev = gpl_dst->next = NULL;
+       gpl_dst->runtime.derived_data = NULL;
+       BLI_addtail(&gpd_dst->layers, gpl_dst);
+       BLI_uniquename(&gpd_dst->layers, gpl_dst, DATA_("GP_Layer"), '.', 
offsetof(bGPDlayer, info), sizeof(gpl_dst->info));
+
+       /* copy frames */
+       BLI_listbase_clear(&gpl_dst->frames);
+       for (bGPDframe *gpf_src = gpl_src->frames.first; gpf_src; gpf_src = 
gpf_src->next) {
+
+               if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != 
gpl_src->actframe)) {
+                       continue;
+               }
+
+               /* make a copy of source frame */
+               bGPDframe *gpf_dst = MEM_dupallocN(gpf_src);
+               gpf_dst->prev = gpf_dst->next = NULL;
+               BLI_addtail(&gpl_dst->frames, gpf_dst);
+
+               /* copy strokes */
+               BLI_listbase_clear(&gpf_dst->strokes);
+               for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; 
gps_src = gps_src->next) {
+
+                       /* make copy of source stroke */
+                       bGPDstroke *gps_dst = 
BKE_gpencil_stroke_duplicate(gps_src);
+
+                       /* check if material is in destination object,
+                        * otherwise add the slot with the material
+                        */
+                       Material *ma_src = give_current_material(ob_src, 
gps_src->mat_nr + 1);
+                       int idx = BKE_object_material_slot_find_index(ob_dst, 
ma_src);
+                       if (idx == 0) {
+                               BKE_object_material_slot_add(bmain, ob_dst);
+                               assign_material(bmain, ob_dst, ma_src, 
ob_dst->totcol, BKE_MAT_ASSIGN_USERPREF);
+                               idx = ob_dst->totcol;
+                       }
+
+                       /* reasign the stroke material to the right slot in 
destination object */
+                       gps_dst->mat_nr = idx - 1;
+
+                       /* add new stroke to frame */
+                       BLI_addtail(&gpf_dst->strokes, gps_dst);
+               }
+       }
+
+       /* notifiers */
+       DEG_id_tag_update(&gpd_dst->id, OB_RECALC_OB | OB_RECALC_DATA | 
DEG_TAG_COPY_ON_WRITE);
+       DEG_id_tag_update(&ob_dst->id, DEG_TAG_COPY_ON_WRITE);
+       WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot)
+{
+       static const EnumPropertyItem copy_mode[] = {
+               {GP_LAYER_COPY_OBJECT_ALL_FRAME, "ALL", 0, "All Frames", ""},
+               {GP_LAYER_COPY_OBJECT_ACT_FRAME, "ACTIVE", 0, "Active Frame", 
""},
+               {0, NULL, 0, NULL, NULL}
+       };
+
+       /* identifiers */
+       ot->name = "Duplicate Layer to new Object";
+       ot->idname = "GPENCIL_OT_layer_duplicate_object";
+       ot->description = "Make a copy of the active Grease Pencil layer to new 
object";
+
+       /* callbacks */
+       ot->exec = gp_layer_duplicate_object_exec;
+       ot->poll = gp_layer_duplicate_object_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       ot->prop = RNA_def_string(ot->srna, "object", NULL, MAX_ID_NAME - 2, 
"Object", "Name of the destination object");
+       RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+       RNA_def_enum(ot->srna, "mode", copy_mode, 
GP_LAYER_COPY_OBJECT_ALL_FRAME, "Mode", "");
+}
+
 /* ********************* Duplicate Frame ************************** */
 enum {
        GP_FRAME_DUP_ACTIVE = 0,
diff --git a/source/blender/editors/gpencil/gpencil_intern.h 
b/source/blender/editors/gpencil/gpencil_intern.h
index 9d9fede91af..d2c8435ed70 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -335,6 +335,7 @@ void GPENCIL_OT_layer_add(struct wmOperatorType *ot);
 void GPENCIL_OT_layer_remove(struct wmOperatorType *ot);
 void GPENCIL_OT_layer_move(struct wmOperatorType *ot);
 void GPENCIL_OT_layer_duplicate(struct wmOperatorType *ot);
+void GPENCIL_OT_layer_duplicate_object(struct wmOperatorType *ot);
 
 void GPENCIL_OT_hide(struct wmOperatorType *ot);
 void GPENCIL_OT_reveal(struct wmOperatorType *ot);
diff --git a/source/blender/editors/gpencil/gpencil_ops.c 
b/source/blender/editors/gpencil/gpencil_ops.c
index d39dd085add..ca97a7948e5 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -718,6 +718,7 @@ void ED_operatortypes_gpencil(void)
        WM_operatortype_append(GPENCIL_OT_layer_remove);
        WM_operatortype_append(GPENCIL_OT_layer_move);
        WM_operatortype_append(GPENCIL_OT_layer_duplicate);
+       WM_operatortype_append(GPENCIL_OT_layer_duplicate_object);
 
        WM_operatortype_append(GPENCIL_OT_hide);
        WM_operatortype_append(GPENCIL_OT_reveal);

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to