From 7b3ab49b396c36b2bbe9380bab7a19ed903851da Mon Sep 17 00:00:00 2001 From: askmeaboutloom Date: Mon, 4 Sep 2023 00:11:05 +0200 Subject: [PATCH] Apply parent layer group opacity to frames within Since that's useful for sketches. It kinda breaks with how the system works conceptually, but otherwise parent group opacity would be totally meaningless and ignored, so might as well assign useful semantics to it. --- ChangeLog | 1 + .../libengine/dpengine/canvas_state.c | 19 +++++++++------- .../libengine/dpengine/layer_routes.c | 22 +++++++++++++++++++ .../libengine/dpengine/layer_routes.h | 3 +++ src/drawdance/libengine/dpengine/view_mode.c | 5 ++++- src/drawdance/libengine/dpengine/view_mode.h | 2 +- 6 files changed, 42 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index e0d678587f..1ee659002d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,7 @@ Unreleased Version 2.2.0-pre * Feature: Draw a hatching pattern on frames in the timeline that are the same as the currently visible one, making it easier to figure out if it's being re-used. * Fix: Make flipbook extend the playback range if it was on the last frame and new ones are added to the timeline. * Feature: Bring back dprectool, the command-line tool that converts Drawpile recordings. It should work mostly the same as it did in Drawpile 2.1. + * Feature: Apply parent folder opacity to frames within it, useful for sketch tracks. Thanks to TeaLord9000 for suggesting. 2023-08-26 Version 2.2.0-beta.7 * Fix: Make classic brushes not go brighter when smudging into transparency. Thanks to cada for reporting. diff --git a/src/drawdance/libengine/dpengine/canvas_state.c b/src/drawdance/libengine/dpengine/canvas_state.c index 3c625c9d92..96147c4677 100644 --- a/src/drawdance/libengine/dpengine/canvas_state.c +++ b/src/drawdance/libengine/dpengine/canvas_state.c @@ -1365,12 +1365,13 @@ static void flattening_tile_to_image(DP_TransientTile *tt, DP_Image *img, static DP_TransientTile * flatten_onion_skin(int tile_index, DP_TransientTile *tt, DP_LayerListEntry *lle, - DP_LayerProps *lp, bool include_sublayers, - DP_ViewModeContext *vmc, const DP_OnionSkin *os) + DP_LayerProps *lp, uint16_t parent_opacity, + bool include_sublayers, DP_ViewModeContext *vmc, + const DP_OnionSkin *os) { DP_TransientTile *skin_tt = DP_layer_list_entry_flatten_tile_to( - lle, lp, tile_index, DP_transient_tile_new_blank(0), os->opacity, - include_sublayers, vmc); + lle, lp, tile_index, DP_transient_tile_new_blank(0), + DP_fix15_mul(parent_opacity, os->opacity), include_sublayers, vmc); DP_UPixel15 tint = os->tint; if (tint.a != 0) { @@ -1402,16 +1403,18 @@ DP_TransientTile *DP_canvas_state_flatten_tile_to(DP_CanvasState *cs, DP_LayerListEntry *lle; DP_LayerProps *lp; const DP_OnionSkin *os; - DP_ViewModeContext vmc = - DP_view_mode_context_root_at(&vmcr, cs, i, &lle, &lp, &os); + uint16_t parent_opacity; + DP_ViewModeContext vmc = DP_view_mode_context_root_at( + &vmcr, cs, i, &lle, &lp, &os, &parent_opacity); if (!DP_view_mode_context_excludes_everything(&vmc)) { if (os) { - tt = flatten_onion_skin(tile_index, tt, lle, lp, + tt = flatten_onion_skin(tile_index, tt, lle, lp, parent_opacity, include_sublayers, &vmc, os); } else { tt = DP_layer_list_entry_flatten_tile_to( - lle, lp, tile_index, tt, DP_BIT15, include_sublayers, &vmc); + lle, lp, tile_index, tt, parent_opacity, include_sublayers, + &vmc); } } } diff --git a/src/drawdance/libengine/dpengine/layer_routes.c b/src/drawdance/libengine/dpengine/layer_routes.c index 520495b7fb..92788c1701 100644 --- a/src/drawdance/libengine/dpengine/layer_routes.c +++ b/src/drawdance/libengine/dpengine/layer_routes.c @@ -457,6 +457,28 @@ void DP_layer_routes_entry_children(DP_LayerRoutesEntry *lre, get_children(lre->index_count, lre->indexes, cs, out_ll, out_lpl); } +uint16_t DP_layer_routes_entry_parent_opacity(DP_LayerRoutesEntry *lre, + DP_CanvasState *cs) +{ + DP_ASSERT(lre); + DP_ASSERT(cs); + + int *indexes = lre->indexes; + int group_indexes_count = lre->index_count - 1; + DP_LayerPropsList *lpl = DP_canvas_state_layer_props_noinc(cs); + uint16_t parent_opacity = DP_BIT15; + + for (int i = 0; i < group_indexes_count; ++i) { + int group_index = indexes[i]; + DP_LayerProps *lp = DP_layer_props_list_at_noinc(lpl, group_index); + lpl = DP_layer_props_children_noinc(lp); + parent_opacity = + DP_fix15_mul(parent_opacity, DP_layer_props_opacity(lp)); + } + + return parent_opacity; +} + DP_TransientLayerContent * DP_layer_routes_entry_indexes_transient_content(int index_count, int *indexes, diff --git a/src/drawdance/libengine/dpengine/layer_routes.h b/src/drawdance/libengine/dpengine/layer_routes.h index 3029ff2815..1a6b645c0b 100644 --- a/src/drawdance/libengine/dpengine/layer_routes.h +++ b/src/drawdance/libengine/dpengine/layer_routes.h @@ -105,6 +105,9 @@ void DP_layer_routes_entry_children(DP_LayerRoutesEntry *lre, DP_CanvasState *cs, DP_LayerList **out_ll, DP_LayerPropsList **out_lpl); +uint16_t DP_layer_routes_entry_parent_opacity(DP_LayerRoutesEntry *lre, + DP_CanvasState *cs); + DP_TransientLayerContent * DP_layer_routes_entry_indexes_transient_content(int index_count, int *indexes, DP_TransientCanvasState *tcs); diff --git a/src/drawdance/libengine/dpengine/view_mode.c b/src/drawdance/libengine/dpengine/view_mode.c index 84b9e0e4dd..ecbdbc0819 100644 --- a/src/drawdance/libengine/dpengine/view_mode.c +++ b/src/drawdance/libengine/dpengine/view_mode.c @@ -401,7 +401,7 @@ bool DP_view_mode_context_excludes_everything(const DP_ViewModeContext *vmc) DP_ViewModeContext DP_view_mode_context_root_at( const DP_ViewModeContextRoot *vmcr, DP_CanvasState *cs, int index, DP_LayerListEntry **out_lle, DP_LayerProps **out_lp, - const DP_OnionSkin **out_os) + const DP_OnionSkin **out_os, uint16_t *out_parent_opacity) { DP_ASSERT(vmcr); DP_ASSERT(cs); @@ -425,6 +425,7 @@ DP_ViewModeContext DP_view_mode_context_root_at( *out_lle = DP_layer_routes_entry_layer(lre, cs); *out_lp = DP_layer_routes_entry_props(lre, cs); *out_os = vmt->onion_skin; + *out_parent_opacity = DP_layer_routes_entry_parent_opacity(lre, cs); return make_manual_frame_context(index, vmb); } else { @@ -434,12 +435,14 @@ DP_ViewModeContext DP_view_mode_context_root_at( *out_lle = NULL; *out_lp = NULL; *out_os = NULL; + *out_parent_opacity = DP_BIT15; return make_nothing_context(); } else { *out_lle = DP_layer_list_at_noinc(ll, index); *out_lp = DP_layer_props_list_at_noinc(lpl, index); *out_os = NULL; + *out_parent_opacity = DP_BIT15; return (DP_ViewModeContext){internal_type, {.layer_id = vmf->layer_id}}; } } diff --git a/src/drawdance/libengine/dpengine/view_mode.h b/src/drawdance/libengine/dpengine/view_mode.h index 1a8a17340a..e0881047ce 100644 --- a/src/drawdance/libengine/dpengine/view_mode.h +++ b/src/drawdance/libengine/dpengine/view_mode.h @@ -126,7 +126,7 @@ bool DP_view_mode_context_excludes_everything(const DP_ViewModeContext *vmc); DP_ViewModeContext DP_view_mode_context_root_at( const DP_ViewModeContextRoot *vmcr, DP_CanvasState *cs, int index, DP_LayerListEntry **out_lle, DP_LayerProps **out_lp, - const DP_OnionSkin **out_os); + const DP_OnionSkin **out_os, uint16_t *out_parent_opacity); DP_ViewModeResult DP_view_mode_context_apply(const DP_ViewModeContext *vmc, DP_LayerProps *lp);