From b85968a243b9b4e633c1b81f12394107014fa4bd Mon Sep 17 00:00:00 2001 From: Stanislaus Krisna Date: Tue, 25 Nov 2025 08:54:54 +1100 Subject: [PATCH 1/9] Fix build script path escape --- build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sh b/build.sh index 0718990a06ea..aeb90d9a9854 100755 --- a/build.sh +++ b/build.sh @@ -371,8 +371,8 @@ if [ $ADDRESS_SANITIZER -ne 0 ] ; then fi -cmd_config="${ASAN_FLAGS}cmake -G \"$BUILD_GENERATOR\" -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ${CMAKE_MORE_OPTIONS} ${CMAKE_OPTIONS_FROM_CMDLINE} \"$DT_SRC_DIR\"" -cmd_build="cmake --build "$BUILD_DIR" -- -j$MAKE_TASKS" +cmd_config="${ASAN_FLAGS}cmake -G \"$BUILD_GENERATOR\" -DCMAKE_INSTALL_PREFIX=\"${INSTALL_PREFIX}\" -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ${CMAKE_MORE_OPTIONS} ${CMAKE_OPTIONS_FROM_CMDLINE} \"$DT_SRC_DIR\"" +cmd_build="cmake --build \"$BUILD_DIR\" -- -j$MAKE_TASKS" cmd_install="${SUDO}cmake --build \"$BUILD_DIR\" --target install -- -j$MAKE_TASKS" From d47d64bcaa570701076d3eb0a9fdeaf7c3cbbb53 Mon Sep 17 00:00:00 2001 From: Stanislaus Krisna Date: Tue, 25 Nov 2025 23:54:11 +1100 Subject: [PATCH 2/9] Add masking tab that combines parametric, drawn, and raster --- src/develop/blend.h | 3 ++- src/develop/blend_gui.c | 19 +++++++++++++++++++ src/develop/imageop.c | 2 ++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/develop/blend.h b/src/develop/blend.h index 4579f20d822a..ef73d05b5ce8 100644 --- a/src/develop/blend.h +++ b/src/develop/blend.h @@ -97,7 +97,8 @@ typedef enum dt_develop_mask_mode_t DEVELOP_MASK_MASK = 1 << 1, // drawn mask DEVELOP_MASK_CONDITIONAL = 1 << 2, // parametric mask DEVELOP_MASK_RASTER = 1 << 3, // raster mask - DEVELOP_MASK_MASK_CONDITIONAL = (DEVELOP_MASK_MASK | DEVELOP_MASK_CONDITIONAL) // drawn & parametric + DEVELOP_MASK_MASK_CONDITIONAL = (DEVELOP_MASK_MASK | DEVELOP_MASK_CONDITIONAL), // drawn & parametric + DEVELOP_MASK_MASK_RASTER = (DEVELOP_MASK_RASTER | DEVELOP_MASK_MASK_CONDITIONAL) // raster, drawn & parametric } dt_develop_mask_mode_t; typedef enum dt_develop_mask_combine_mode_t diff --git a/src/develop/blend_gui.c b/src/develop/blend_gui.c index 6394bd0fc427..ebdc22e58be2 100644 --- a/src/develop/blend_gui.c +++ b/src/develop/blend_gui.c @@ -162,6 +162,8 @@ const dt_introspection_type_enum_tuple_t dt_develop_mask_mode_names[] DEVELOP_MASK_RASTER | DEVELOP_MASK_ENABLED }, { N_("drawn & parametric mask"), DEVELOP_MASK_MASK_CONDITIONAL | DEVELOP_MASK_ENABLED }, + { N_("raster, drawn & parametric mask"), + DEVELOP_MASK_MASK_RASTER | DEVELOP_MASK_ENABLED }, { } }; const dt_introspection_type_enum_tuple_t dt_develop_combine_masks_names[] @@ -1532,6 +1534,14 @@ static gboolean _blendop_masks_modes_raster_toggled(GtkToggleButton *button, DEVELOP_MASK_ENABLED | DEVELOP_MASK_RASTER); } +static gboolean _blendop_masks_modes_mask_raster_toggled(GtkToggleButton *button, + GdkEventButton *event, + dt_iop_module_t *module) +{ + return _blendop_masks_modes_toggle(button, module, + DEVELOP_MASK_ENABLED | DEVELOP_MASK_MASK_RASTER); +} + static gboolean _blendop_blendif_suppress_toggled(GtkToggleButton *togglebutton, GdkEventButton *event, dt_iop_module_t *module) @@ -3470,6 +3480,15 @@ void dt_iop_gui_init_blending(GtkWidget *iopw, dtgtk_cairo_paint_masks_raster, NULL); bd->masks_modes = g_list_append(bd->masks_modes, GUINT_TO_POINTER(DEVELOP_MASK_ENABLED | DEVELOP_MASK_RASTER)); bd->masks_modes_toggles = g_list_append(bd->masks_modes_toggles, GTK_WIDGET(but)); + + // Raster + parametric + but = dt_iop_togglebutton_new(module, "blend`masks", + N_("raster, drawn & parametric mask"), NULL, + G_CALLBACK(_blendop_masks_modes_mask_raster_toggled), + FALSE, 0, 0, + dtgtk_cairo_paint_masks_raster, NULL); + bd->masks_modes = g_list_append(bd->masks_modes, GUINT_TO_POINTER(DEVELOP_MASK_ENABLED | DEVELOP_MASK_MASK_RASTER)); + bd->masks_modes_toggles = g_list_append(bd->masks_modes_toggles, GTK_WIDGET(but)); } GtkWidget *presets_button = dtgtk_button_new(dtgtk_cairo_paint_presets, 0, NULL); diff --git a/src/develop/imageop.c b/src/develop/imageop.c index 33f49acfc94c..ff7e02491270 100644 --- a/src/develop/imageop.c +++ b/src/develop/imageop.c @@ -2798,6 +2798,8 @@ static gboolean _mask_indicator_tooltip(GtkWidget *treeview, const uint32_t mm = module->blend_params->mask_mode; if((mm & DEVELOP_MASK_MASK) && (mm & DEVELOP_MASK_CONDITIONAL)) type=_("drawn + parametric mask"); + else if((mm & DEVELOP_MASK_RASTER) && (mm & DEVELOP_MASK_MASK) && (mm & DEVELOP_MASK_CONDITIONAL)) + type=_("raster, drawn & parametric mask"); else if(mm & DEVELOP_MASK_MASK) type=_("drawn mask"); else if(mm & DEVELOP_MASK_CONDITIONAL) From 7ce9f9e4d38c1111f08daf33083c9c8c0aad185f Mon Sep 17 00:00:00 2001 From: Stanislaus Krisna Date: Wed, 26 Nov 2025 23:31:02 +1100 Subject: [PATCH 3/9] Added raster mask into mask manager shapes --- src/develop/blend.h | 2 +- src/develop/blend_gui.c | 8 + src/develop/masks.h | 11 +- src/develop/masks/masks.c | 2 + src/develop/masks/raster.c | 327 +++++++++++++++++++++++++++++++++++++ 5 files changed, 348 insertions(+), 2 deletions(-) create mode 100644 src/develop/masks/raster.c diff --git a/src/develop/blend.h b/src/develop/blend.h index ef73d05b5ce8..71df17ceda23 100644 --- a/src/develop/blend.h +++ b/src/develop/blend.h @@ -283,7 +283,7 @@ extern const dt_introspection_type_enum_tuple_t dt_develop_combine_masks_names[] extern const dt_introspection_type_enum_tuple_t dt_develop_feathering_guide_names[]; extern const dt_introspection_type_enum_tuple_t dt_develop_invert_mask_names[]; -#define DEVELOP_MASKS_NB_SHAPES 5 +#define DEVELOP_MASKS_NB_SHAPES 6 /** blend gui data */ typedef struct dt_iop_gui_blend_data_t diff --git a/src/develop/blend_gui.c b/src/develop/blend_gui.c index ebdc22e58be2..74a54f5b7d1c 100644 --- a/src/develop/blend_gui.c +++ b/src/develop/blend_gui.c @@ -2799,6 +2799,14 @@ void dt_iop_gui_init_masks(GtkWidget *blendw, dt_iop_module_t *module) FALSE, 0, 0, dtgtk_cairo_paint_masks_eye, abox); + bd->masks_type[5] = DT_MASKS_RASTER; + bd->masks_shapes[5] = dt_iop_togglebutton_new(module, "blend`shapes", + N_("add raster"), + N_("add multiple raster mask"), + G_CALLBACK(_blendop_masks_add_shape), + FALSE, 0, 0, + dtgtk_cairo_paint_masks_circle, abox); + bd->masks_type[0] = DT_MASKS_GRADIENT; bd->masks_shapes[0] = dt_iop_togglebutton_new(module, "blend`shapes", N_("add gradient"), diff --git a/src/develop/masks.h b/src/develop/masks.h index 6977cf900624..cebe61d51d3c 100644 --- a/src/develop/masks.h +++ b/src/develop/masks.h @@ -42,7 +42,8 @@ typedef enum dt_masks_type_t DT_MASKS_GRADIENT = 1 << 4, DT_MASKS_ELLIPSE = 1 << 5, DT_MASKS_BRUSH = 1 << 6, - DT_MASKS_NON_CLONE = 1 << 7 + DT_MASKS_NON_CLONE = 1 << 7, + DT_MASKS_RASTER = 1 << 8, } dt_masks_type_t; /**masts states */ @@ -196,6 +197,13 @@ typedef struct dt_masks_point_group_t float opacity; } dt_masks_point_group_t; +/** structure used to store information regarding raster mask */ +typedef struct dt_masks_point_raster_t +{ + int state; + float opacity; +} dt_masks_point_raster_t; + /** structure used to store pointers to the functions implementing operations on a mask shape */ /** plus a few per-class descriptive data items */ typedef struct dt_masks_functions_t @@ -440,6 +448,7 @@ extern const dt_masks_functions_t dt_masks_functions_brush; extern const dt_masks_functions_t dt_masks_functions_path; extern const dt_masks_functions_t dt_masks_functions_gradient; extern const dt_masks_functions_t dt_masks_functions_group; +extern const dt_masks_functions_t dt_masks_functions_raster; /** init dt_masks_form_gui_t struct with default values */ void dt_masks_init_form_gui(dt_masks_form_gui_t *gui); diff --git a/src/develop/masks/masks.c b/src/develop/masks/masks.c index fe0e72780d62..c6cabf5239a2 100644 --- a/src/develop/masks/masks.c +++ b/src/develop/masks/masks.c @@ -852,6 +852,8 @@ dt_masks_form_t *dt_masks_create(const dt_masks_type_t type) form->functions = &dt_masks_functions_gradient; else if(type & DT_MASKS_GROUP) form->functions = &dt_masks_functions_group; + else if(type & DT_MASKS_RASTER) + form->functions = &dt_masks_functions_raster; if(form->functions && form->functions->sanitize_config) form->functions->sanitize_config(type); diff --git a/src/develop/masks/raster.c b/src/develop/masks/raster.c new file mode 100644 index 000000000000..e39fe645b198 --- /dev/null +++ b/src/develop/masks/raster.c @@ -0,0 +1,327 @@ +/* + This file is part of darktable, + Copyright (C) 2013-2025 darktable developers. + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +*/ +#include "bauhaus/bauhaus.h" +#include "common/debug.h" +#include "common/undo.h" +#include "control/conf.h" +#include "control/control.h" +#include "develop/blend.h" +#include "develop/imageop.h" +#include "develop/masks.h" +#include "develop/openmp_maths.h" +#include "develop/masks.h" + +static void _raster_sanitize_config(dt_masks_type_t type) +{ + // Placeholder +} + +static GSList *_raster_setup_mouse_actions(const struct dt_masks_form_t *const form) +{ + GSList *lm = NULL; + lm = dt_mouse_action_create_simple(lm, DT_MOUSE_ACTION_SCROLL, + GDK_SHIFT_MASK, _("[RASTER] change feather size")); + lm = dt_mouse_action_create_simple(lm, DT_MOUSE_ACTION_SCROLL, + GDK_CONTROL_MASK, _("[RASTER] change opacity")); + return lm; +} + +static void _raster_set_form_name(dt_masks_form_t *const form, + const size_t nb) +{ + snprintf(form->name, sizeof(form->name), _("raster #%d"), (int)nb); +} + +static void _raster_set_hint_message(const dt_masks_form_gui_t *const gui, + const dt_masks_form_t *const form, + const int opacity, + char *const restrict msgbuf, + const size_t msgbuf_len) +{ + // circle has same controls on creation and on edit + g_snprintf(msgbuf, msgbuf_len, + _("feather size: shift+scroll\n" + "opacity: ctrl+scroll (%d%%)"), opacity); +} + +static void _raster_modify_property(dt_masks_form_t *const form, + const dt_masks_property_t prop, + const float old_val, + const float new_val, + float *sum, + int *count, + float *min, + float *max) +{ + +} + +static void _raster_duplicate_points(dt_develop_t *dev, + dt_masks_form_t *const base, + dt_masks_form_t *const dest) +{ + (void)dev; // unused arg, keep compiler from complaining + for(GList *pts = base->points; pts; pts = g_list_next(pts)) + { + dt_masks_point_raster_t *pt = pts->data; + dt_masks_point_raster_t *npt = malloc(sizeof(dt_masks_point_raster_t)); + memcpy(npt, pt, sizeof(dt_masks_point_raster_t)); + dest->points = g_list_append(dest->points, npt); + } +} + +static void _raster_initial_source_pos(const float iwd, + const float iht, + float *x, + float *y) +{ + *x = 0; + *y = 0; +} + +static void _raster_get_distance(const float x, + const float y, + const float as, + dt_masks_form_gui_t *gui, + const int index, + const int num_points, + gboolean *inside, + gboolean *inside_border, + int *near, + gboolean *inside_source, + float *dist) +{ + (void)num_points; // unused arg, keep compiler from complaining + // initialise returned values + *inside_source = FALSE; + *inside = FALSE; + *inside_border = FALSE; + *near = -1; + *dist = FLT_MAX; +} + +static int _raster_get_points(dt_develop_t *dev, + const float x, + const float y, + const float radius, + const float radius2, + const float rotation, + float **points, + int *points_count) +{ + (void)radius2; // keep compiler from complaining about unused arg + (void)rotation; + // float wd, ht; + + dt_free_align(*points); + *points = NULL; + *points_count = 0; + return 1; +} + +static int _raster_get_points_border(dt_develop_t *dev, + struct dt_masks_form_t *form, + float **points, + int *points_count, + float **border, + int *border_count, + const int source, + const dt_iop_module_t *module) +{ + dt_free_align(*points); + *points = NULL; + *points_count = 0; + return 1; +} + +static int _raster_get_mask(const dt_iop_module_t *const restrict module, + const dt_dev_pixelpipe_iop_t *const restrict piece, + dt_masks_form_t *const restrict form, + float **buffer, + int *width, + int *height, + int *posx, + int *posy) +{ + // dt_iop_gui_blend_data_t *bd = module->blend_data; + // gboolean free_mask; + float *raster_mask = NULL; + + if(raster_mask) + { + // Forward raster mask + // dt_iop_image_scaled_copy(buffer, raster_mask, 1.0f, width, height, 1); + // if(free_mask) dt_free_align(raster_mask); + } + else + { + // Fallback when raster mask is not available + dt_iop_image_fill(*buffer, 0.0f, *width, *height, 1); // mask[k] = value; + } + return 1; +} + +static int _raster_get_mask_roi(const dt_iop_module_t *const restrict module, + const dt_dev_pixelpipe_iop_t *const restrict piece, + dt_masks_form_t *const form, + const dt_iop_roi_t *const roi, + float *const restrict buffer) +{ + // TODO: Implement ME!!! + return 0; +} + +static int _raster_get_area(const dt_iop_module_t *const restrict module, + const dt_dev_pixelpipe_iop_t *const restrict piece, + dt_masks_form_t *const restrict form, + int *width, + int *height, + int *posx, + int *posy) +{ + return 1; +} + +static int _raster_get_source_area(dt_iop_module_t *module, + dt_dev_pixelpipe_iop_t *piece, + dt_masks_form_t *form, + int *width, + int *height, + int *posx, + int *posy) +{ + return 1; +} + +static int _raster_events_mouse_moved(dt_iop_module_t *module, + const float pzx, + const float pzy, + const double pressure, + const int which, + const float zoom_scale, + dt_masks_form_t *form, + const dt_mask_id_t parentid, + dt_masks_form_gui_t *gui, + const int index) +{ + if(!gui) return 0; + return 1; +} + +static int _raster_events_mouse_scrolled(dt_iop_module_t *module, + const float pzx, + const float pzy, + const int up, + const uint32_t state, + dt_masks_form_t *form, + const dt_mask_id_t parentid, + dt_masks_form_gui_t *gui, + const int index) +{ + if(!gui) return 0; + return 1; +} + +static int _raster_events_button_pressed(dt_iop_module_t *module, + float pzx, float pzy, + const double pressure, + const int which, + const int type, + const uint32_t state, + dt_masks_form_t *form, + const dt_mask_id_t parentid, + dt_masks_form_gui_t *gui, + const int index) +{ + if(!gui) return 0; + return 1; +} + +static int _raster_events_button_released(dt_iop_module_t *module, + const float pzx, + const float pzy, + const int which, + const uint32_t state, + dt_masks_form_t *form, + const dt_mask_id_t parentid, + dt_masks_form_gui_t *gui, + const int index) +{ + if(!gui) return 0; + + if (gui->creation) + { + // Create raster mask + dt_masks_point_raster_t *raster = malloc(sizeof(dt_masks_point_raster_t)); + + gui->form_dragging = FALSE; + + form->points = g_list_append(form->points, raster); + + dt_iop_module_t *crea_module = gui->creation_module; + dt_masks_gui_form_save_creation(darktable.develop, crea_module, form, gui); + + if(crea_module) + { + // we save the move + dt_dev_add_history_item(darktable.develop, crea_module, TRUE); + // and we switch in edit mode to show all the forms + dt_masks_set_edit_mode(crea_module, DT_MASKS_EDIT_FULL); + dt_masks_iop_update(crea_module); + } + + dt_dev_masks_selection_change(darktable.develop, crea_module, form->formid); + gui->creation_module = NULL; + } + + return 1; +} + +static void _raster_events_post_expose(cairo_t *cr, + const float zoom_scale, + dt_masks_form_gui_t *gui, + const int index, + const int num_points) +{ + // TODO: Implement ME!!! + return; +} + +// The function table for circles. This must be public, i.e. no "static" keyword. +const dt_masks_functions_t dt_masks_functions_raster = { + .point_struct_size = sizeof(struct dt_masks_point_raster_t), + .sanitize_config = _raster_sanitize_config, + .setup_mouse_actions = _raster_setup_mouse_actions, + .set_form_name = _raster_set_form_name, + .set_hint_message = _raster_set_hint_message, + .modify_property = _raster_modify_property, + .duplicate_points = _raster_duplicate_points, + .initial_source_pos = _raster_initial_source_pos, + .get_distance = _raster_get_distance, + .get_points = _raster_get_points, + .get_points_border = _raster_get_points_border, + .get_mask = _raster_get_mask, + .get_mask_roi = _raster_get_mask_roi, + .get_area = _raster_get_area, + .get_source_area = _raster_get_source_area, + .mouse_moved = _raster_events_mouse_moved, + .mouse_scrolled = _raster_events_mouse_scrolled, + .button_pressed = _raster_events_button_pressed, + .button_released = _raster_events_button_released, + .post_expose = _raster_events_post_expose +}; From 73ef304c9fa5de73ac2903b648c11a4a13a3b3a5 Mon Sep 17 00:00:00 2001 From: Stanislaus Krisna Date: Wed, 26 Nov 2025 23:54:42 +1100 Subject: [PATCH 4/9] Include raster shape source code in build step --- src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ed77c93cdad6..725148ed8d22 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -117,6 +117,7 @@ FILE(GLOB SOURCE_FILES "develop/masks/group.c" "develop/masks/masks.c" "develop/masks/path.c" + "develop/masks/raster.c" "develop/pixelpipe.c" "develop/tiling.c" "dtgtk/button.c" From e2fb6869b77410c85e12f763ac9a8cc621229328 Mon Sep 17 00:00:00 2001 From: Stanislaus Krisna Date: Thu, 27 Nov 2025 00:06:44 +1100 Subject: [PATCH 5/9] Implement mask roi --- src/develop/masks/raster.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/develop/masks/raster.c b/src/develop/masks/raster.c index e39fe645b198..b19f933a153a 100644 --- a/src/develop/masks/raster.c +++ b/src/develop/masks/raster.c @@ -182,8 +182,24 @@ static int _raster_get_mask_roi(const dt_iop_module_t *const restrict module, const dt_iop_roi_t *const roi, float *const restrict buffer) { - // TODO: Implement ME!!! - return 0; + const int width = roi->width; + const int height = roi->height; + // dt_iop_gui_blend_data_t *bd = module->blend_data; + // gboolean free_mask; + float *raster_mask = NULL; + + if(raster_mask) + { + // Forward raster mask + // dt_iop_image_scaled_copy(buffer, raster_mask, 1.0f, width, height, 1); + // if(free_mask) dt_free_align(raster_mask); + } + else + { + // Fallback when raster mask is not available + dt_iop_image_fill(buffer, 0.0f, width, height, 1); // mask[k] = value; + } + return 1; } static int _raster_get_area(const dt_iop_module_t *const restrict module, From 81740397bc91e4f4c0ce821d625f4f6903449aaa Mon Sep 17 00:00:00 2001 From: Stanislaus Krisna Date: Thu, 27 Nov 2025 00:07:00 +1100 Subject: [PATCH 6/9] Fix indentation --- src/develop/masks/raster.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/develop/masks/raster.c b/src/develop/masks/raster.c index b19f933a153a..9676ca16ef9d 100644 --- a/src/develop/masks/raster.c +++ b/src/develop/masks/raster.c @@ -158,22 +158,22 @@ static int _raster_get_mask(const dt_iop_module_t *const restrict module, int *posx, int *posy) { - // dt_iop_gui_blend_data_t *bd = module->blend_data; - // gboolean free_mask; - float *raster_mask = NULL; + // dt_iop_gui_blend_data_t *bd = module->blend_data; + // gboolean free_mask; + float *raster_mask = NULL; - if(raster_mask) - { - // Forward raster mask - // dt_iop_image_scaled_copy(buffer, raster_mask, 1.0f, width, height, 1); - // if(free_mask) dt_free_align(raster_mask); - } - else - { - // Fallback when raster mask is not available - dt_iop_image_fill(*buffer, 0.0f, *width, *height, 1); // mask[k] = value; - } - return 1; + if(raster_mask) + { + // Forward raster mask + // dt_iop_image_scaled_copy(buffer, raster_mask, 1.0f, width, height, 1); + // if(free_mask) dt_free_align(raster_mask); + } + else + { + // Fallback when raster mask is not available + dt_iop_image_fill(*buffer, 0.0f, *width, *height, 1); // mask[k] = value; + } + return 1; } static int _raster_get_mask_roi(const dt_iop_module_t *const restrict module, From a206c0d76beb745f1376e7ebe55c31cd66b68f89 Mon Sep 17 00:00:00 2001 From: Stanislaus Krisna Date: Sat, 29 Nov 2025 00:23:55 +1100 Subject: [PATCH 7/9] Attempt to fix bug where raster shape would use raster mask from previous module --- src/develop/masks.h | 1 + src/develop/masks/raster.c | 115 +++++++++++++++++++++++++++---------- 2 files changed, 85 insertions(+), 31 deletions(-) diff --git a/src/develop/masks.h b/src/develop/masks.h index cebe61d51d3c..1d0d9f4cbff9 100644 --- a/src/develop/masks.h +++ b/src/develop/masks.h @@ -200,6 +200,7 @@ typedef struct dt_masks_point_group_t /** structure used to store information regarding raster mask */ typedef struct dt_masks_point_raster_t { + int32_t sourceInstanceId; int state; float opacity; } dt_masks_point_raster_t; diff --git a/src/develop/masks/raster.c b/src/develop/masks/raster.c index 9676ca16ef9d..bfa031ddb086 100644 --- a/src/develop/masks/raster.c +++ b/src/develop/masks/raster.c @@ -149,6 +149,72 @@ static int _raster_get_points_border(dt_develop_t *dev, return 1; } +static int _render_raster_mask(const dt_iop_module_t *const restrict module, + const dt_dev_pixelpipe_iop_t *const restrict piece, + dt_masks_form_t *const restrict form, + float *buffer, + int width, + int height) +{ + const size_t obuffsize = (size_t)width * height; + + // Skip if module is not in focus + // if(!dt_iop_has_focus((dt_iop_module_t *)module)) + // return 0; + + // initialize output buffer with zero + memset(buffer, 0, sizeof(float) * width * height); + + dt_masks_point_raster_t *rasterPoint = form->points->data; + // if(!rasterPoint) + // return 0; + + // Find module with the same ID as the mask ID + // dt_iop_module_t * source = NULL; + // GList *source_iter; + // for(source_iter = piece->pipe->nodes; + // source_iter; + // source_iter = g_list_next(source_iter)) + // { + // dt_dev_pixelpipe_iop_t *candidate = source_iter->data; + // if (candidate->module->instance == rasterPoint->sourceInstanceId) { + // source = candidate->module; + // break; + // } + // } + + // if (!source) { + // // TODO: Show error, log, or message + // return 0; + // } + + gboolean free_mask; + float *raster_mask = dt_dev_get_raster_mask( + (dt_dev_pixelpipe_iop_t *)piece, + module->raster_mask.sink.source, + module->raster_mask.sink.id, + module, + &free_mask + ); + + if(!raster_mask) + return 0; + + // Copy content of mask to prevent modification of the actual mask data + float *const restrict mask = dt_alloc_align_float(obuffsize); + DT_OMP_FOR_SIMD(aligned(mask, raster_mask:64)) + for(size_t i = 0; i < obuffsize; i++) + mask[i] = raster_mask[i] * rasterPoint->opacity; + + // Forward raster mask + dt_iop_image_scaled_copy(buffer, mask, 1.0f, width, height, 1); + + if(free_mask) dt_free_align(raster_mask); + dt_free_align(mask); // Don't forget to free our local mask copy + + return 1; +} + static int _raster_get_mask(const dt_iop_module_t *const restrict module, const dt_dev_pixelpipe_iop_t *const restrict piece, dt_masks_form_t *const restrict form, @@ -159,21 +225,7 @@ static int _raster_get_mask(const dt_iop_module_t *const restrict module, int *posy) { // dt_iop_gui_blend_data_t *bd = module->blend_data; - // gboolean free_mask; - float *raster_mask = NULL; - - if(raster_mask) - { - // Forward raster mask - // dt_iop_image_scaled_copy(buffer, raster_mask, 1.0f, width, height, 1); - // if(free_mask) dt_free_align(raster_mask); - } - else - { - // Fallback when raster mask is not available - dt_iop_image_fill(*buffer, 0.0f, *width, *height, 1); // mask[k] = value; - } - return 1; + return _render_raster_mask(module, piece, form, *buffer, *width, *height); } static int _raster_get_mask_roi(const dt_iop_module_t *const restrict module, @@ -184,22 +236,7 @@ static int _raster_get_mask_roi(const dt_iop_module_t *const restrict module, { const int width = roi->width; const int height = roi->height; - // dt_iop_gui_blend_data_t *bd = module->blend_data; - // gboolean free_mask; - float *raster_mask = NULL; - - if(raster_mask) - { - // Forward raster mask - // dt_iop_image_scaled_copy(buffer, raster_mask, 1.0f, width, height, 1); - // if(free_mask) dt_free_align(raster_mask); - } - else - { - // Fallback when raster mask is not available - dt_iop_image_fill(buffer, 0.0f, width, height, 1); // mask[k] = value; - } - return 1; + return _render_raster_mask(module, piece, form, buffer, width, height); } static int _raster_get_area(const dt_iop_module_t *const restrict module, @@ -210,6 +247,10 @@ static int _raster_get_area(const dt_iop_module_t *const restrict module, int *posx, int *posy) { + *posx = 0; + *posy = 0; + *width = piece->pipe->iwidth; + *height = piece->pipe->iheight; return 1; } @@ -221,6 +262,10 @@ static int _raster_get_source_area(dt_iop_module_t *module, int *posx, int *posy) { + *posx = 0; + *posy = 0; + *width = piece->pipe->iwidth; + *height = piece->pipe->iheight; return 1; } @@ -284,6 +329,14 @@ static int _raster_events_button_released(dt_iop_module_t *module, { // Create raster mask dt_masks_point_raster_t *raster = malloc(sizeof(dt_masks_point_raster_t)); + raster->opacity = 1.0f; + + dt_iop_module_t *sourceMask = module->raster_mask.sink.source; + if (!sourceMask) { + // TODO: Print error + return 0; + } + raster->sourceInstanceId = sourceMask->instance; gui->form_dragging = FALSE; From 208b36199b6add70cd61c53b57a455cd9cf8cc1a Mon Sep 17 00:00:00 2001 From: Stanislaus Krisna Date: Sat, 29 Nov 2025 03:38:42 +1100 Subject: [PATCH 8/9] Remove unused codes --- src/develop/masks.h | 1 + src/develop/masks/raster.c | 26 +------------------------- 2 files changed, 2 insertions(+), 25 deletions(-) diff --git a/src/develop/masks.h b/src/develop/masks.h index 1d0d9f4cbff9..394fe0ce5c57 100644 --- a/src/develop/masks.h +++ b/src/develop/masks.h @@ -201,6 +201,7 @@ typedef struct dt_masks_point_group_t typedef struct dt_masks_point_raster_t { int32_t sourceInstanceId; + dt_mask_id_t maskId; int state; float opacity; } dt_masks_point_raster_t; diff --git a/src/develop/masks/raster.c b/src/develop/masks/raster.c index bfa031ddb086..e855f4130180 100644 --- a/src/develop/masks/raster.c +++ b/src/develop/masks/raster.c @@ -158,35 +158,10 @@ static int _render_raster_mask(const dt_iop_module_t *const restrict module, { const size_t obuffsize = (size_t)width * height; - // Skip if module is not in focus - // if(!dt_iop_has_focus((dt_iop_module_t *)module)) - // return 0; - // initialize output buffer with zero memset(buffer, 0, sizeof(float) * width * height); dt_masks_point_raster_t *rasterPoint = form->points->data; - // if(!rasterPoint) - // return 0; - - // Find module with the same ID as the mask ID - // dt_iop_module_t * source = NULL; - // GList *source_iter; - // for(source_iter = piece->pipe->nodes; - // source_iter; - // source_iter = g_list_next(source_iter)) - // { - // dt_dev_pixelpipe_iop_t *candidate = source_iter->data; - // if (candidate->module->instance == rasterPoint->sourceInstanceId) { - // source = candidate->module; - // break; - // } - // } - - // if (!source) { - // // TODO: Show error, log, or message - // return 0; - // } gboolean free_mask; float *raster_mask = dt_dev_get_raster_mask( @@ -337,6 +312,7 @@ static int _raster_events_button_released(dt_iop_module_t *module, return 0; } raster->sourceInstanceId = sourceMask->instance; + raster->maskId = module->raster_mask.sink.id; gui->form_dragging = FALSE; From ce908a43f5dfbcecea65973ba7f40bb8ce7a6eb5 Mon Sep 17 00:00:00 2001 From: Stanislaus Krisna Date: Sun, 30 Nov 2025 01:21:46 +1100 Subject: [PATCH 9/9] Remove unused button --- src/develop/blend.h | 3 +-- src/develop/blend_gui.c | 19 ------------------- src/develop/imageop.c | 2 -- 3 files changed, 1 insertion(+), 23 deletions(-) diff --git a/src/develop/blend.h b/src/develop/blend.h index 71df17ceda23..2473a8eaeb8e 100644 --- a/src/develop/blend.h +++ b/src/develop/blend.h @@ -97,8 +97,7 @@ typedef enum dt_develop_mask_mode_t DEVELOP_MASK_MASK = 1 << 1, // drawn mask DEVELOP_MASK_CONDITIONAL = 1 << 2, // parametric mask DEVELOP_MASK_RASTER = 1 << 3, // raster mask - DEVELOP_MASK_MASK_CONDITIONAL = (DEVELOP_MASK_MASK | DEVELOP_MASK_CONDITIONAL), // drawn & parametric - DEVELOP_MASK_MASK_RASTER = (DEVELOP_MASK_RASTER | DEVELOP_MASK_MASK_CONDITIONAL) // raster, drawn & parametric + DEVELOP_MASK_MASK_CONDITIONAL = (DEVELOP_MASK_MASK | DEVELOP_MASK_CONDITIONAL) // drawn & parametric } dt_develop_mask_mode_t; typedef enum dt_develop_mask_combine_mode_t diff --git a/src/develop/blend_gui.c b/src/develop/blend_gui.c index 74a54f5b7d1c..bcdc2f5079b4 100644 --- a/src/develop/blend_gui.c +++ b/src/develop/blend_gui.c @@ -162,8 +162,6 @@ const dt_introspection_type_enum_tuple_t dt_develop_mask_mode_names[] DEVELOP_MASK_RASTER | DEVELOP_MASK_ENABLED }, { N_("drawn & parametric mask"), DEVELOP_MASK_MASK_CONDITIONAL | DEVELOP_MASK_ENABLED }, - { N_("raster, drawn & parametric mask"), - DEVELOP_MASK_MASK_RASTER | DEVELOP_MASK_ENABLED }, { } }; const dt_introspection_type_enum_tuple_t dt_develop_combine_masks_names[] @@ -1534,14 +1532,6 @@ static gboolean _blendop_masks_modes_raster_toggled(GtkToggleButton *button, DEVELOP_MASK_ENABLED | DEVELOP_MASK_RASTER); } -static gboolean _blendop_masks_modes_mask_raster_toggled(GtkToggleButton *button, - GdkEventButton *event, - dt_iop_module_t *module) -{ - return _blendop_masks_modes_toggle(button, module, - DEVELOP_MASK_ENABLED | DEVELOP_MASK_MASK_RASTER); -} - static gboolean _blendop_blendif_suppress_toggled(GtkToggleButton *togglebutton, GdkEventButton *event, dt_iop_module_t *module) @@ -3488,15 +3478,6 @@ void dt_iop_gui_init_blending(GtkWidget *iopw, dtgtk_cairo_paint_masks_raster, NULL); bd->masks_modes = g_list_append(bd->masks_modes, GUINT_TO_POINTER(DEVELOP_MASK_ENABLED | DEVELOP_MASK_RASTER)); bd->masks_modes_toggles = g_list_append(bd->masks_modes_toggles, GTK_WIDGET(but)); - - // Raster + parametric - but = dt_iop_togglebutton_new(module, "blend`masks", - N_("raster, drawn & parametric mask"), NULL, - G_CALLBACK(_blendop_masks_modes_mask_raster_toggled), - FALSE, 0, 0, - dtgtk_cairo_paint_masks_raster, NULL); - bd->masks_modes = g_list_append(bd->masks_modes, GUINT_TO_POINTER(DEVELOP_MASK_ENABLED | DEVELOP_MASK_MASK_RASTER)); - bd->masks_modes_toggles = g_list_append(bd->masks_modes_toggles, GTK_WIDGET(but)); } GtkWidget *presets_button = dtgtk_button_new(dtgtk_cairo_paint_presets, 0, NULL); diff --git a/src/develop/imageop.c b/src/develop/imageop.c index ff7e02491270..33f49acfc94c 100644 --- a/src/develop/imageop.c +++ b/src/develop/imageop.c @@ -2798,8 +2798,6 @@ static gboolean _mask_indicator_tooltip(GtkWidget *treeview, const uint32_t mm = module->blend_params->mask_mode; if((mm & DEVELOP_MASK_MASK) && (mm & DEVELOP_MASK_CONDITIONAL)) type=_("drawn + parametric mask"); - else if((mm & DEVELOP_MASK_RASTER) && (mm & DEVELOP_MASK_MASK) && (mm & DEVELOP_MASK_CONDITIONAL)) - type=_("raster, drawn & parametric mask"); else if(mm & DEVELOP_MASK_MASK) type=_("drawn mask"); else if(mm & DEVELOP_MASK_CONDITIONAL)