diff options
Diffstat (limited to 'source/blender/editors/gpencil/gpencil_data.c')
-rw-r--r-- | source/blender/editors/gpencil/gpencil_data.c | 148 |
1 files changed, 90 insertions, 58 deletions
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 ***************************** */ |