[Bf-blender-cvs] [556c71a84ac] master: GPencil: New option to Merge All layers in active one

Antonio Vazquez noreply at git.blender.org
Thu Nov 4 19:46:56 CET 2021


Commit: 556c71a84ac1e017883b6f0af0b4fdf8d21254c6
Author: Antonio Vazquez
Date:   Thu Nov 4 19:40:18 2021 +0100
Branches: master
https://developer.blender.org/rB556c71a84ac1e017883b6f0af0b4fdf8d21254c6

GPencil: New option to Merge All layers in active one

This new option allows to combine all layers in the active one. Also the merge down option has been improved.

Reviewed By: mendio, pablo vazquez (UI)

Differential Revision: https://developer.blender.org/D13054

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

M	release/scripts/startup/bl_ui/properties_data_gpencil.py
M	source/blender/editors/gpencil/gpencil_data.c
M	source/blender/editors/gpencil/gpencil_utils.c
M	source/blender/editors/include/ED_gpencil.h

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

diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py b/release/scripts/startup/bl_ui/properties_data_gpencil.py
index 793c4a52350..34e83573bc9 100644
--- a/release/scripts/startup/bl_ui/properties_data_gpencil.py
+++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py
@@ -110,7 +110,8 @@ class GPENCIL_MT_layer_context_menu(Menu):
 
         layout.separator()
 
-        layout.operator("gpencil.layer_merge", icon='SORT_ASC', text="Merge Down")
+        layout.operator("gpencil.layer_merge", icon='SORT_ASC', text="Merge Down").mode = 'ACTIVE'
+        layout.operator("gpencil.layer_merge", text="Merge All").mode = 'ALL'
 
         layout.separator()
         layout.operator("gpencil.layer_duplicate_object", text="Copy Layer to Selected").only_active = True
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index a77d3bee025..db2104dfdf9 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -1321,78 +1321,102 @@ void GPENCIL_OT_layer_isolate(wmOperatorType *ot)
 }
 
 /* ********************** Merge Layer with the next layer **************************** */
+enum {
+  GP_LAYER_MERGE_ACTIVE = 0,
+  GP_LAYER_MERGE_ALL = 1,
+};
 
-static int gpencil_merge_layer_exec(bContext *C, wmOperator *op)
+static void apply_layer_settings(bGPDlayer *gpl)
 {
-  bGPdata *gpd = ED_gpencil_data_get_active(C);
-  bGPDlayer *gpl_src = BKE_gpencil_layer_active_get(gpd);
-  bGPDlayer *gpl_dst = gpl_src->prev;
+  /* Apply layer attributes. */
+  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+    LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+      gps->fill_opacity_fac *= gpl->opacity;
+      gps->vert_color_fill[3] *= gpl->opacity;
+      for (int p = 0; p < gps->totpoints; p++) {
+        bGPDspoint *pt = &gps->points[p];
+        float factor = (((float)gps->thickness * pt->pressure) + (float)gpl->line_change) /
+                       ((float)gps->thickness * pt->pressure);
+        pt->pressure *= factor;
+        pt->strength *= gpl->opacity;
 
-  if (ELEM(NULL, gpd, gpl_dst, gpl_src)) {
-    BKE_report(op->reports, RPT_ERROR, "No layers to merge");
-    return OPERATOR_CANCELLED;
+        /* Layer transformation. */
+        mul_v3_m4v3(&pt->x, gpl->layer_mat, &pt->x);
+        zero_v3(gpl->location);
+        zero_v3(gpl->rotation);
+        copy_v3_fl(gpl->scale, 1.0f);
+      }
+    }
   }
 
-  /* Collect frames of gpl_dst in hash table to avoid O(n^2) lookups. */
-  GHash *gh_frames_dst = BLI_ghash_int_new_ex(__func__, 64);
-  LISTBASE_FOREACH (bGPDframe *, gpf_dst, &gpl_dst->frames) {
-    BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_dst->framenum), gpf_dst);
-  }
+  gpl->line_change = 0;
+  gpl->opacity = 1.0f;
+  unit_m4(gpl->layer_mat);
+  invert_m4_m4(gpl->layer_invmat, gpl->layer_mat);
+}
 
-  /* Read all frames from merge layer and add any missing in destination layer,
-   * copying all previous strokes to keep the image equals.
-   * Need to do it in a separated loop to avoid strokes accumulation. */
-  LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
-    /* Try to find frame in destination layer hash table. */
-    bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum));
-    if (!gpf_dst) {
-      gpf_dst = BKE_gpencil_layer_frame_get(gpl_dst, gpf_src->framenum, GP_GETFRAME_ADD_COPY);
-      /* Use same frame type. */
-      gpf_dst->key_type = gpf_src->key_type;
-      BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum), gpf_dst);
-    }
-  }
+static int gpencil_merge_layer_exec(bContext *C, wmOperator *op)
+{
+  bGPdata *gpd = ED_gpencil_data_get_active(C);
+  bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd);
+  bGPDlayer *gpl_dst = gpl_active->prev;
+  const int mode = RNA_enum_get(op->ptr, "mode");
 
-  /* Read all frames from merge layer and add strokes. */
-  LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
-    /* Try to find frame in destination layer hash table. */
-    bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum));
-    /* Apply layer transformation. */
-    LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
-      for (int p = 0; p < gps_src->totpoints; p++) {
-        bGPDspoint *pt = &gps_src->points[p];
-        mul_v3_m4v3(&pt->x, gpl_src->layer_mat, &pt->x);
-      }
+  if (mode == GP_LAYER_MERGE_ACTIVE) {
+    if (ELEM(NULL, gpd, gpl_dst, gpl_active)) {
+      BKE_report(op->reports, RPT_ERROR, "No layers to merge");
+      return OPERATOR_CANCELLED;
     }
-
-    /* Add to tail all strokes. */
-    if (gpf_dst) {
-      BLI_movelisttolist(&gpf_dst->strokes, &gpf_src->strokes);
+  }
+  else {
+    if (ELEM(NULL, gpd, gpl_active)) {
+      BKE_report(op->reports, RPT_ERROR, "No layers to flatten");
+      return OPERATOR_CANCELLED;
     }
   }
 
-  /* Add Masks to destination layer. */
-  LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl_src->mask_layers) {
-    /* Don't add merged layers or missing layer names. */
-    if (!BKE_gpencil_layer_named_get(gpd, mask->name) || STREQ(mask->name, gpl_src->info) ||
-        STREQ(mask->name, gpl_dst->info)) {
-      continue;
+  if (mode == GP_LAYER_MERGE_ACTIVE) {
+    /* Apply destination layer attributes. */
+    apply_layer_settings(gpl_active);
+    ED_gpencil_layer_merge(gpd, gpl_active, gpl_dst, false);
+  }
+  else if (mode == GP_LAYER_MERGE_ALL) {
+    /* Apply layer attributes to all layers. */
+    LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+      apply_layer_settings(gpl);
     }
-    if (!BKE_gpencil_layer_mask_named_get(gpl_dst, mask->name)) {
-      bGPDlayer_Mask *mask_new = MEM_dupallocN(mask);
-      BLI_addtail(&gpl_dst->mask_layers, mask_new);
-      gpl_dst->act_mask++;
+    gpl_dst = gpl_active;
+    /* Merge layers on top of active layer. */
+    if (gpd->layers.last != gpl_dst) {
+      LISTBASE_FOREACH_BACKWARD_MUTABLE (bGPDlayer *, gpl, &gpd->layers) {
+        if (gpl == gpl_dst) {
+          break;
+        }
+        ED_gpencil_layer_merge(gpd, gpl, gpl->prev, false);
+      }
     }
+    /* Merge layers below active layer. */
+    LISTBASE_FOREACH_BACKWARD_MUTABLE (bGPDlayer *, gpl, &gpd->layers) {
+      if (gpl == gpl_dst) {
+        continue;
+      }
+      ED_gpencil_layer_merge(gpd, gpl, gpl_dst, true);
+    }
+    /* Set general layers settings to default values. */
+    gpl_active->blend_mode = eGplBlendMode_Regular;
+    gpl_active->flag &= ~GP_LAYER_LOCKED;
+    gpl_active->flag &= ~GP_LAYER_HIDE;
+    gpl_active->flag |= GP_LAYER_USE_LIGHTS;
+    gpl_active->onion_flag |= GP_LAYER_ONIONSKIN;
+  }
+  else {
+    return OPERATOR_CANCELLED;
   }
-  /* Set destination layer as active. */
-  BKE_gpencil_layer_active_set(gpd, gpl_dst);
-
-  /* Now delete next layer */
-  BKE_gpencil_layer_delete(gpd, gpl_src);
-  BLI_ghash_free(gh_frames_dst, NULL, NULL);
 
-  /* Reorder masking. */
-  BKE_gpencil_layer_mask_sort(gpd, gpl_dst);
+  /* Clear any invalid mask. Some other layer could be using the merged layer. */
+  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+    BKE_gpencil_layer_mask_cleanup(gpd, gpl);
+  }
 
   /* notifiers */
   DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
@@ -1404,10 +1428,16 @@ static int gpencil_merge_layer_exec(bContext *C, wmOperator *op)
 
 void GPENCIL_OT_layer_merge(wmOperatorType *ot)
 {
+  static const EnumPropertyItem merge_modes[] = {
+      {GP_LAYER_MERGE_ACTIVE, "ACTIVE", 0, "Active", "Combine active layer into the layer below"},
+      {GP_LAYER_MERGE_ALL, "ALL", 0, "All", "Combine all layers into the active layer"},
+      {0, NULL, 0, NULL, NULL},
+  };
+
   /* identifiers */
   ot->name = "Merge Down";
   ot->idname = "GPENCIL_OT_layer_merge";
-  ot->description = "Merge the current layer with the layer below";
+  ot->description = "Combine Layers";
 
   /* callbacks */
   ot->exec = gpencil_merge_layer_exec;
@@ -1415,6 +1445,8 @@ void GPENCIL_OT_layer_merge(wmOperatorType *ot)
 
   /* flags */
   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+  ot->prop = RNA_def_enum(ot->srna, "mode", merge_modes, GP_LAYER_MERGE_ACTIVE, "Mode", "");
 }
 
 /* ********************** Change Layer ***************************** */
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index c4319fd7ee2..f3c3aa10632 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -3415,3 +3415,71 @@ void ED_gpencil_stroke_close_by_distance(bGPDstroke *gps, const float threshold)
     BKE_gpencil_stroke_close(gps);
   }
 }
+
+/* Merge two layers. */
+void ED_gpencil_layer_merge(bGPdata *gpd,
+                            bGPDlayer *gpl_src,
+                            bGPDlayer *gpl_dst,
+                            const bool reverse)
+{
+  /* Collect frames of gpl_dst in hash table to avoid O(n^2) lookups. */
+  GHash *gh_frames_dst = BLI_ghash_int_new_ex(__func__, 64);
+  LISTBASE_FOREACH (bGPDframe *, gpf_dst, &gpl_dst->frames) {
+    BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_dst->framenum), gpf_dst);
+  }
+
+  /* Read all frames from merge layer and add any missing in destination layer,
+   * copying all previous strokes to keep the image equals.
+   * Need to do it in a separated loop to avoid strokes accumulation. */
+  LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
+    /* Try to find frame in destination layer hash table. */
+    bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum));
+    if (!gpf_dst) {
+      gpf_dst = BKE_gpencil_layer_frame_get(gpl_dst, gpf_src->framenum, GP_GETFRAME_ADD_COPY);
+      /* Use same frame type. */
+      gpf_dst->key_type = gpf_src->key_type;
+      BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum), gpf_dst);
+    }
+  }
+
+  /* Read all frames from merge layer and add strokes. */
+  LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
+    /* Try to find frame in destination layer hash table. */
+    bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->fram

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list