From 369bc25cbb6f346a30081ae90cf4ac69675ec802 Mon Sep 17 00:00:00 2001 From: Kofa Date: Sat, 15 Nov 2025 09:49:57 +0100 Subject: [PATCH 01/13] agx: Fix crash during initialisation caused by callback triggered before all controls created; also: remove redundant soft limits (matching hard limits) --- src/iop/agx.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/iop/agx.c b/src/iop/agx.c index 005d3c75eac7..254826e96cf0 100644 --- a/src/iop/agx.c +++ b/src/iop/agx.c @@ -199,6 +199,7 @@ typedef struct dt_iop_agx_gui_data_t GtkWidget *completely_reverse_primaries; GtkWidget *post_curve_primaries_controls_vbox; GtkWidget *set_post_curve_primaries_from_pre_button; + gboolean initialized; } dt_iop_agx_gui_data_t; typedef struct tone_mapping_params_t @@ -1730,6 +1731,9 @@ void gui_changed(dt_iop_module_t *self, void *previous) { dt_iop_agx_gui_data_t *g = self->gui_data; + + if (!g->initialized) return; + dt_iop_agx_params_t *p = self->params; if(widget == g->black_exposure_picker) @@ -1809,7 +1813,6 @@ static GtkWidget* _create_basic_curve_controls_box(dt_iop_module_t *self, dt_bauhaus_slider_set_format(slider, "%"); dt_bauhaus_slider_set_digits(slider, 2); dt_bauhaus_slider_set_factor(slider, 100.f); - dt_bauhaus_slider_set_soft_range(slider, 0.f, 1.f); gtk_widget_set_tooltip_text(slider, _("darken or brighten the pivot (linear output power)")); dt_bauhaus_widget_set_quad_tooltip(slider, _("the average luminance of the selected region will be\n" "used to set the pivot relative to mid-gray,\n" @@ -1888,7 +1891,6 @@ static void _add_look_sliders(dt_iop_module_t *section) dt_bauhaus_slider_set_format(slider, "%"); dt_bauhaus_slider_set_digits(slider, 2); dt_bauhaus_slider_set_factor(slider, 100.f); - dt_bauhaus_slider_set_soft_range(slider, 0.f, 1.f); gtk_widget_set_tooltip_text(slider, _("increase to bring hues closer to the original")); } @@ -1955,7 +1957,6 @@ static GtkWidget* _create_advanced_box(dt_iop_module_t *self, // Shoulder length slider = dt_bauhaus_slider_from_params(section, "curve_linear_ratio_above_pivot"); - dt_bauhaus_slider_set_soft_range(slider, 0.f, 1.f); dt_bauhaus_slider_set_format(slider, "%"); dt_bauhaus_slider_set_digits(slider, 2); dt_bauhaus_slider_set_factor(slider, 100.f); @@ -1973,7 +1974,6 @@ static GtkWidget* _create_advanced_box(dt_iop_module_t *self, // Toe length slider = dt_bauhaus_slider_from_params(section, "curve_linear_ratio_below_pivot"); - dt_bauhaus_slider_set_soft_range(slider, 0.f, 1.f); dt_bauhaus_slider_set_format(slider, "%"); dt_bauhaus_slider_set_digits(slider, 2); dt_bauhaus_slider_set_factor(slider, 100.f); @@ -2424,6 +2424,7 @@ static void _notebook_page_changed(GtkNotebook *notebook, void gui_init(dt_iop_module_t *self) { dt_iop_agx_gui_data_t *g = IOP_GUI_ALLOC(agx); + g->initialized = FALSE; static dt_action_def_t notebook_def = {}; g->notebook = dt_ui_notebook_new(¬ebook_def); @@ -2455,6 +2456,8 @@ void gui_init(dt_iop_module_t *self) // Finally, add the remaining sections to the settings page _add_look_box(settings_section, g); _create_primaries_page(self, g); + + g->initialized = TRUE; gui_update(self); } From 8ab30bfaff7272d228c95b8dca564aa03b6d6e5b Mon Sep 17 00:00:00 2001 From: Kofa Date: Sat, 15 Nov 2025 12:46:58 +0100 Subject: [PATCH 02/13] agx: Remove custom 'initialized' field, rely on darktable.gui->reset for protection --- src/iop/agx.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/iop/agx.c b/src/iop/agx.c index 254826e96cf0..e467ab5b99d1 100644 --- a/src/iop/agx.c +++ b/src/iop/agx.c @@ -199,7 +199,6 @@ typedef struct dt_iop_agx_gui_data_t GtkWidget *completely_reverse_primaries; GtkWidget *post_curve_primaries_controls_vbox; GtkWidget *set_post_curve_primaries_from_pre_button; - gboolean initialized; } dt_iop_agx_gui_data_t; typedef struct tone_mapping_params_t @@ -1732,7 +1731,7 @@ void gui_changed(dt_iop_module_t *self, { dt_iop_agx_gui_data_t *g = self->gui_data; - if (!g->initialized) return; + if (darktable.gui->reset) return; dt_iop_agx_params_t *p = self->params; @@ -2424,7 +2423,7 @@ static void _notebook_page_changed(GtkNotebook *notebook, void gui_init(dt_iop_module_t *self) { dt_iop_agx_gui_data_t *g = IOP_GUI_ALLOC(agx); - g->initialized = FALSE; + darktable.gui->reset++; static dt_action_def_t notebook_def = {}; g->notebook = dt_ui_notebook_new(¬ebook_def); @@ -2457,7 +2456,7 @@ void gui_init(dt_iop_module_t *self) _add_look_box(settings_section, g); _create_primaries_page(self, g); - g->initialized = TRUE; + darktable.gui->reset--; gui_update(self); } From 19488cb934d6582dbbc4d6e05c4af608a35b3d4b Mon Sep 17 00:00:00 2001 From: Kofa Date: Sat, 15 Nov 2025 12:57:13 +0100 Subject: [PATCH 03/13] agx: No need for darktable.gui->reset in gui_init, as it's handled by imageop#dt_iop_gui_init --- src/iop/agx.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/iop/agx.c b/src/iop/agx.c index e467ab5b99d1..381962f08d0c 100644 --- a/src/iop/agx.c +++ b/src/iop/agx.c @@ -2423,7 +2423,6 @@ static void _notebook_page_changed(GtkNotebook *notebook, void gui_init(dt_iop_module_t *self) { dt_iop_agx_gui_data_t *g = IOP_GUI_ALLOC(agx); - darktable.gui->reset++; static dt_action_def_t notebook_def = {}; g->notebook = dt_ui_notebook_new(¬ebook_def); @@ -2456,7 +2455,6 @@ void gui_init(dt_iop_module_t *self) _add_look_box(settings_section, g); _create_primaries_page(self, g); - darktable.gui->reset--; gui_update(self); } From ede047f981d4c20572a5f75fe69ddd7d8170ac7f Mon Sep 17 00:00:00 2001 From: Kofa Date: Sat, 15 Nov 2025 22:59:30 +0100 Subject: [PATCH 04/13] agx: Don't call gui_update at the end of gui_init; add _update_curve_warnings to gui_update so initial state is painted correctly --- src/iop/agx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/iop/agx.c b/src/iop/agx.c index 381962f08d0c..aa64d3eaf030 100644 --- a/src/iop/agx.c +++ b/src/iop/agx.c @@ -2225,7 +2225,7 @@ void gui_update(dt_iop_module_t *self) p->disable_primaries_adjustments); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->completely_reverse_primaries), p->completely_reverse_primaries); - + _update_curve_warnings(self); gui_changed(self, NULL, NULL); } @@ -2454,8 +2454,6 @@ void gui_init(dt_iop_module_t *self) // Finally, add the remaining sections to the settings page _add_look_box(settings_section, g); _create_primaries_page(self, g); - - gui_update(self); } static void _set_shared_params(dt_iop_agx_params_t *p) From e96a07aeab44fa5a622c890d56c206c12326b042 Mon Sep 17 00:00:00 2001 From: Kofa Date: Sun, 16 Nov 2025 14:01:14 +0100 Subject: [PATCH 05/13] agx: Don't call gui_changed from gui_update; extract all dynamic redraws into function _update_redraw_dynamic_gui, called from gui_update and gui_changed; extract slider offset, scale, default and value updates into _update_pivot_slider_settings, called from _update_pivot_x (gui_changed and exposure picker callbacks) and from gui_update. --- src/iop/agx.c | 66 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/src/iop/agx.c b/src/iop/agx.c index aa64d3eaf030..7aec3ddc67e1 100644 --- a/src/iop/agx.c +++ b/src/iop/agx.c @@ -1001,6 +1001,23 @@ static primaries_params_t _get_primaries_params(const dt_iop_agx_params_t *p) return primaries_params; } +static void _update_pivot_slider_settings(GtkWidget* const slider, + const dt_iop_agx_params_t* const p) +{ + darktable.gui->reset++; + + const float range = p->range_white_relative_ev - p->range_black_relative_ev; + + dt_bauhaus_slider_set_factor(slider, range); + dt_bauhaus_slider_set_offset(slider, p->range_black_relative_ev); + // 0 EV default with the new exposure params + dt_bauhaus_slider_set_default(slider, -p->range_black_relative_ev / range); + + dt_bauhaus_slider_set(slider, p->curve_pivot_x); + + darktable.gui->reset--; +} + static void _update_pivot_x(const float old_black_ev, const float old_white_ev, dt_iop_module_t *self, dt_iop_agx_params_t *const p) { const dt_iop_agx_gui_data_t *g = self->gui_data; @@ -1019,14 +1036,7 @@ static void _update_pivot_x(const float old_black_ev, const float old_white_ev, // new_range is ensured to be > 0 due to hard limits on sliders p->curve_pivot_x = (clamped_pivot_ev - new_black_ev) / new_range; - darktable.gui->reset++; - GtkWidget* const slider = g->basic_curve_controls.curve_pivot_x; - dt_bauhaus_slider_set_factor(slider, new_range); - dt_bauhaus_slider_set_offset(slider, new_black_ev); - // 0 EV default with the new exposure params - dt_bauhaus_slider_set_default(slider, -new_black_ev / new_range); - dt_bauhaus_slider_set(slider, p->curve_pivot_x); - darktable.gui->reset--; + _update_pivot_slider_settings(g->basic_curve_controls.curve_pivot_x, p); } static void _adjust_relative_exposure_from_exposure_params(dt_iop_module_t *self) @@ -1725,6 +1735,22 @@ static void _update_curve_warnings(dt_iop_module_t *self) ? dtgtk_cairo_paint_warning : NULL, CPF_ACTIVE, NULL); } +static void _update_redraw_dynamic_gui(dt_iop_module_t* const self, + const dt_iop_agx_gui_data_t* const g, + const dt_iop_agx_params_t* const p) +{ + gtk_widget_set_visible(g->curve_gamma, !p->auto_gamma); + gtk_widget_set_visible(g->primaries_controls_vbox, !p->disable_primaries_adjustments); + const gboolean post_curve_primaries_available = !p->completely_reverse_primaries && !p->disable_primaries_adjustments; + gtk_widget_set_visible(g->post_curve_primaries_controls_vbox, post_curve_primaries_available); + gtk_widget_set_sensitive(g->set_post_curve_primaries_from_pre_button, post_curve_primaries_available); + + _update_curve_warnings(self); + + // Trigger redraw when any parameter changes + gtk_widget_queue_draw(GTK_WIDGET(g->graph_drawing_area)); +} + void gui_changed(dt_iop_module_t *self, GtkWidget *widget, void *previous) @@ -1769,17 +1795,6 @@ void gui_changed(dt_iop_module_t *self, darktable.gui->reset--; } - gtk_widget_set_visible(g->curve_gamma, !p->auto_gamma); - gtk_widget_set_visible(g->primaries_controls_vbox, !p->disable_primaries_adjustments); - const gboolean post_curve_primaries_available = !p->completely_reverse_primaries && !p->disable_primaries_adjustments; - gtk_widget_set_visible(g->post_curve_primaries_controls_vbox, post_curve_primaries_available); - gtk_widget_set_sensitive(g->set_post_curve_primaries_from_pre_button, post_curve_primaries_available); - - _update_curve_warnings(self); - - // Trigger redraw when any parameter changes - gtk_widget_queue_draw(GTK_WIDGET(g->graph_drawing_area)); - if(g && p->auto_gamma) { tone_mapping_params_t tone_mapping_params; @@ -1787,6 +1802,8 @@ void gui_changed(dt_iop_module_t *self, _adjust_pivot(self->params, &tone_mapping_params); dt_bauhaus_slider_set(g->curve_gamma, tone_mapping_params.curve_gamma); } + + _update_redraw_dynamic_gui(self, g, p); } static GtkWidget* _create_basic_curve_controls_box(dt_iop_module_t *self, @@ -2212,12 +2229,10 @@ static GtkWidget *_setup_hue_slider(dt_iop_module_t *self, void gui_update(dt_iop_module_t *self) { - dt_iop_agx_gui_data_t *g = self->gui_data; - const dt_iop_agx_params_t *p = self->params; + const dt_iop_agx_gui_data_t* const g = self->gui_data; + const dt_iop_agx_params_t* const p = self->params; - const float range = p->range_white_relative_ev - p->range_black_relative_ev; - dt_bauhaus_slider_set_factor(g->basic_curve_controls.curve_pivot_x, range); - dt_bauhaus_slider_set_offset(g->basic_curve_controls.curve_pivot_x, p->range_black_relative_ev); + _update_pivot_slider_settings(g->basic_curve_controls.curve_pivot_x, p); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->auto_gamma), p->auto_gamma); @@ -2225,9 +2240,8 @@ void gui_update(dt_iop_module_t *self) p->disable_primaries_adjustments); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->completely_reverse_primaries), p->completely_reverse_primaries); - _update_curve_warnings(self); - gui_changed(self, NULL, NULL); + _update_redraw_dynamic_gui(self, g, p); } static void _create_primaries_page(dt_iop_module_t *main, From af3b0d4dcdf5d2a55084240cb898a0671e78dd61 Mon Sep 17 00:00:00 2001 From: Kofa Date: Wed, 10 Dec 2025 19:29:17 +0100 Subject: [PATCH 06/13] agx: don't use float MIN/MAX for gboolean params --- src/iop/agx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/iop/agx.c b/src/iop/agx.c index 7aec3ddc67e1..a3104dcd7a4d 100644 --- a/src/iop/agx.c +++ b/src/iop/agx.c @@ -125,7 +125,7 @@ typedef struct dt_iop_agx_params_t // s_p float curve_shoulder_power; // $MIN: 0.f $MAX: 10.f $DEFAULT: 1.5f $DESCRIPTION: "shoulder power" float curve_gamma; // $MIN: 0.01f $MAX: 100.f $DEFAULT: 2.2f $DESCRIPTION: "curve y gamma" - gboolean auto_gamma; // $MIN: 0.f $MAX: 1.f $DEFAULT: 0.f $DESCRIPTION: "keep the pivot on the diagonal" + gboolean auto_gamma; // $DEFAULT: FALSE $DESCRIPTION: "keep the pivot on the diagonal" // t_ly float curve_target_display_black_ratio; // $MIN: 0.f $MAX: 0.15f $DEFAULT: 0.f $DESCRIPTION: "target black" // s_ly @@ -133,7 +133,7 @@ typedef struct dt_iop_agx_params_t // custom primaries; rotation limits below: +/- 0.5236 radian => +/- 30 degrees dt_iop_agx_base_primaries_t base_primaries; // $DEFAULT: DT_AGX_REC2020 $DESCRIPTION: "base primaries" - gboolean disable_primaries_adjustments; // $MIN: 0.f $MAX: 1.f $DEFAULT: 0.f $DESCRIPTION: "disable adjustments" + gboolean disable_primaries_adjustments; // $DEFAULT: FALSE $DESCRIPTION: "disable adjustments" float red_inset; // $MIN: 0.f $MAX: 0.99f $DEFAULT: 0.f $DESCRIPTION: "red attenuation" float red_rotation; // $MIN: -0.5236f $MAX: 0.5236f $DEFAULT: 0.f $DESCRIPTION: "red rotation" float green_inset; // $MIN: 0.f $MAX: 0.99f $DEFAULT: 0.f $DESCRIPTION: "green attenuation" @@ -151,7 +151,7 @@ typedef struct dt_iop_agx_params_t float blue_unrotation; // $MIN: -0.5236f $MAX: 0.5236f $DEFAULT: 0.f $DESCRIPTION: "blue reverse rotation" // v5 - gboolean completely_reverse_primaries; // $DEFAULT: 0 $DESCRIPTION: "reverse all" + gboolean completely_reverse_primaries; // $DEFAULT: FALSE $DESCRIPTION: "reverse all" } dt_iop_agx_params_t; typedef struct dt_iop_basic_curve_controls_t From e97cf56de9efb0efc146321bbcb9cc4f2ebe60c2 Mon Sep 17 00:00:00 2001 From: Kofa Date: Wed, 10 Dec 2025 21:33:34 +0100 Subject: [PATCH 07/13] agx: don't hide primaries selection if 'disable adjustments' is checked (the idea is to disable (un)rotations and attenuation/purity boost only); use 60% hue preservation for Blender defaults (as that is the Blender default) --- src/iop/agx.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/iop/agx.c b/src/iop/agx.c index a3104dcd7a4d..fc4740aaa204 100644 --- a/src/iop/agx.c +++ b/src/iop/agx.c @@ -2252,6 +2252,11 @@ static void _create_primaries_page(dt_iop_module_t *main, dt_iop_module_t *page = DT_IOP_SECTION_FOR_PARAMS(main, NULL, page_primaries); + GtkWidget *base_primaries_combo = dt_bauhaus_combobox_from_params(page, "base_primaries"); + gtk_widget_set_tooltip_text(base_primaries_combo, + _("color space primaries to use as the base for below adjustments.\n" + "'export profile' uses the profile set in 'output color profile'.")); + g->disable_primaries_adjustments = dt_bauhaus_toggle_from_params(page, "disable_primaries_adjustments"); @@ -2263,7 +2268,6 @@ static void _create_primaries_page(dt_iop_module_t *main, "especially with bright, saturated lights (e.g. LEDs).\n" "mainly intended to be used for experimenting.")); - GtkWidget *primaries_button = dtgtk_button_new(dtgtk_cairo_paint_styles, 0, NULL); gtk_widget_set_tooltip_text(primaries_button, _("reset primaries to a predefined configuration")); g_signal_connect(primaries_button, "clicked", G_CALLBACK(_primaries_popupmenu_callback), main); @@ -2274,11 +2278,6 @@ static void _create_primaries_page(dt_iop_module_t *main, dt_iop_module_t *self = DT_IOP_SECTION_FOR_PARAMS(main, NULL, g->primaries_controls_vbox); - GtkWidget *base_primaries_combo = dt_bauhaus_combobox_from_params(self, "base_primaries"); - gtk_widget_set_tooltip_text(base_primaries_combo, - _("color space primaries to use as the base for below adjustments.\n" - "'export profile' uses the profile set in 'output color profile'.")); - dt_gui_box_add(self->widget, dt_ui_section_label_new(C_("section", "before tone mapping"))); GtkWidget *slider = NULL; @@ -2513,6 +2512,7 @@ void _set_smooth_params(dt_iop_agx_params_t *p) static void _set_blenderlike_params(dt_iop_agx_params_t *p) { _set_shared_params(p); + p->look_original_hue_mix_ratio = 0.6f; // Blender's default _set_blenderlike_primaries(p); // restore the original Blender settings From d90effc870f17cb0905efc74271e7427d23a2853 Mon Sep 17 00:00:00 2001 From: Kofa Date: Mon, 22 Dec 2025 08:23:47 +0100 Subject: [PATCH 08/13] agx: create 'reset primaries' with dt_ui_label_new instead of gtk_label_new --- src/iop/agx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/iop/agx.c b/src/iop/agx.c index fc4740aaa204..6ec7ed99c295 100644 --- a/src/iop/agx.c +++ b/src/iop/agx.c @@ -2272,7 +2272,7 @@ static void _create_primaries_page(dt_iop_module_t *main, gtk_widget_set_tooltip_text(primaries_button, _("reset primaries to a predefined configuration")); g_signal_connect(primaries_button, "clicked", G_CALLBACK(_primaries_popupmenu_callback), main); - g->primaries_controls_vbox = dt_gui_vbox(dt_gui_hbox(gtk_label_new(_("reset primaries")), + g->primaries_controls_vbox = dt_gui_vbox(dt_gui_hbox(dt_ui_label_new(_("reset primaries")), dt_gui_align_right(primaries_button))); dt_gui_box_add(page_primaries, g->primaries_controls_vbox); From a1839b2bc9f86395713e05132c9abe67101a89f1 Mon Sep 17 00:00:00 2001 From: Kofa Date: Mon, 22 Dec 2025 09:28:37 +0100 Subject: [PATCH 09/13] agx: call gui_changed at the end of gui_update; it takes care of calling _update_redraw_dynamic_gui --- src/iop/agx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/iop/agx.c b/src/iop/agx.c index 6ec7ed99c295..12b0ef4fab27 100644 --- a/src/iop/agx.c +++ b/src/iop/agx.c @@ -2241,7 +2241,7 @@ void gui_update(dt_iop_module_t *self) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->completely_reverse_primaries), p->completely_reverse_primaries); - _update_redraw_dynamic_gui(self, g, p); + gui_changed(self, NULL, NULL); } static void _create_primaries_page(dt_iop_module_t *main, From d0570e0569f2706912ee8a4ada88bab066a8432a Mon Sep 17 00:00:00 2001 From: Kofa Date: Sun, 4 Jan 2026 11:28:47 +0100 Subject: [PATCH 10/13] agx: US spelling of 'color' --- src/iop/agx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/iop/agx.c b/src/iop/agx.c index 12b0ef4fab27..5bc62c57cc63 100644 --- a/src/iop/agx.c +++ b/src/iop/agx.c @@ -1298,7 +1298,7 @@ static void _create_matrices(const primaries_params_t *params, // the start of the process. Its inverse (see the next steps), when // applied to RGB values in the curve's working space (which // actually uses the base primaries), will undo the rotation and, - // depending on purity, push colours further from achromatic, + // depending on purity, push colors further from achromatic, // resaturating them. dt_colormatrix_t outset_and_unrotated_to_xyz_transposed; dt_make_transposed_matrices_from_primaries_and_whitepoint @@ -1313,7 +1313,7 @@ static void _create_matrices(const primaries_params_t *params, // 'tmp' is constructed the same way as // inbound_inset_and_rotated_to_xyz_transposed, but this matrix will - // be used to remap colours to the 'base' profile, so we need to + // be used to remap colors to the 'base' profile, so we need to // invert it. dt_colormatrix_t rendering_to_base_transposed; mat3SSEinv(rendering_to_base_transposed, tmp); From 9058bb13db294477491c27cbd9e08321546b689e Mon Sep 17 00:00:00 2001 From: Kofa Date: Sat, 10 Jan 2026 12:25:18 +0100 Subject: [PATCH 11/13] agx: adjusted default params to be closer to sigmoid's; added sigmoid-like presets --- src/iop/agx.c | 64 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/src/iop/agx.c b/src/iop/agx.c index 5bc62c57cc63..74b8e5d310a6 100644 --- a/src/iop/agx.c +++ b/src/iop/agx.c @@ -2469,7 +2469,7 @@ void gui_init(dt_iop_module_t *self) _create_primaries_page(self, g); } -static void _set_shared_params(dt_iop_agx_params_t *p) +static void _set_default_curve_and_look_params(dt_iop_agx_params_t *p) { p->look_slope = 1.f; p->look_brightness = 1.f; @@ -2484,11 +2484,14 @@ static void _set_shared_params(dt_iop_agx_params_t *p) p->range_white_relative_ev = 6.5f; p->dynamic_range_scaling = 0.1f; - p->curve_contrast_around_pivot = 2.8f; + // contrast, toe and shoulder power are about halfway between values required to match + // sigmoid'd scene-referred defaults and those used by its 'smooth' preset, + // giving a similar experience to what many users already know and expect + p->curve_contrast_around_pivot = 3.0f; p->curve_linear_ratio_below_pivot = 0.f; p->curve_linear_ratio_above_pivot = 0.f; - p->curve_toe_power = 1.55f; - p->curve_shoulder_power = 1.55f; + p->curve_toe_power = 1.50f; + p->curve_shoulder_power = 3.30f; p->curve_target_display_black_ratio = 0.f; p->curve_target_display_white_ratio = 1.f; p->auto_gamma = FALSE; @@ -2499,19 +2502,19 @@ static void _set_shared_params(dt_iop_agx_params_t *p) static void _set_neutral_params(dt_iop_agx_params_t *p) { - _set_shared_params(p); + _set_default_curve_and_look_params(p); _set_unmodified_primaries(p); } void _set_smooth_params(dt_iop_agx_params_t *p) { - _set_shared_params(p); + _set_default_curve_and_look_params(p); _set_smooth_primaries(p); } static void _set_blenderlike_params(dt_iop_agx_params_t *p) { - _set_shared_params(p); + _set_default_curve_and_look_params(p); p->look_original_hue_mix_ratio = 0.6f; // Blender's default _set_blenderlike_primaries(p); @@ -2532,7 +2535,7 @@ static void _set_blenderlike_params(dt_iop_agx_params_t *p) static void _set_scene_referred_default_params(dt_iop_agx_params_t *p) { - _set_shared_params(p); + _set_default_curve_and_look_params(p); _set_blenderlike_primaries(p); } @@ -2560,6 +2563,8 @@ void init_presets(dt_iop_module_so_t *self) /////////////////////// // Blender-like presets + // Blender's tone curve has relatively low contrast, so a Blender-like 'punchy' + // variant is also provided _set_blenderlike_params(&p); @@ -2567,12 +2572,45 @@ void init_presets(dt_iop_module_so_t *self) self->op, self->version(), &p, sizeof(p), TRUE, DEVELOP_BLEND_CS_RGB_SCENE); - _make_punchy(&p); dt_gui_presets_add_generic(_("blender-like|punchy"), self->op, self->version(), &p, sizeof(p), TRUE, DEVELOP_BLEND_CS_RGB_SCENE); + /////////////////////// + // sigmoid-like presets, obtained by matching the curves + // these have quite high contrast already, so we omit the punchy variants + + _set_default_curve_and_look_params(&p); + // sigmoid's defaults unmodified primaries, but in AgX, we want the AgX effect, + // so we only match the tone curve + _set_blenderlike_primaries(&p); + + // sigmoid's default has 100% hue preservation + p.look_original_hue_mix_ratio = 1.0; + + // tone curve + p.curve_contrast_around_pivot = 3.07f; + p.curve_toe_power = 1.40f; + p.curve_shoulder_power = 3.71f; + + dt_gui_presets_add_generic(_("sigmoid-like|default"), + self->op, self->version(), &p, sizeof(p), + TRUE, DEVELOP_BLEND_CS_RGB_SCENE); + + _set_smooth_primaries(&p); + // sigmoid|smooth has no hue preservation + p.look_original_hue_mix_ratio = 0.f; + + // tone curve + p.curve_contrast_around_pivot = 2.98f; + p.curve_toe_power = 1.61f; + p.curve_shoulder_power = 3.02f; + + dt_gui_presets_add_generic(_("sigmoid-like|smooth"), + self->op, self->version(), &p, sizeof(p), + TRUE, DEVELOP_BLEND_CS_RGB_SCENE); + ///////////////////////// // Scene-referred preset @@ -2596,15 +2634,11 @@ void init_presets(dt_iop_module_so_t *self) } ///////////////// - // Smooth presets + // Smooth preset _set_smooth_params(&p); - dt_gui_presets_add_generic(_("smooth|base"), self->op, self->version(), &p, sizeof(p), - TRUE, DEVELOP_BLEND_CS_RGB_SCENE); - - _make_punchy(&p); - dt_gui_presets_add_generic(_("smooth|punchy"), self->op, self->version(), &p, sizeof(p), + dt_gui_presets_add_generic(_("smooth"), self->op, self->version(), &p, sizeof(p), TRUE, DEVELOP_BLEND_CS_RGB_SCENE); } From 6780beba025239e30d0f738cf3a61538bbd0bb3f Mon Sep 17 00:00:00 2001 From: Kofa Date: Sat, 10 Jan 2026 12:42:25 +0100 Subject: [PATCH 12/13] agx: sync contrast, toe and shoulder power slider defaults with scene-referred default values --- src/iop/agx.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/iop/agx.c b/src/iop/agx.c index 74b8e5d310a6..23716a99e51e 100644 --- a/src/iop/agx.c +++ b/src/iop/agx.c @@ -115,7 +115,7 @@ typedef struct dt_iop_agx_params_t // Corresponds to p_y, but not directly -- needs application of gamma float curve_pivot_y_linear_output; // $MIN: 0.f $MAX: 1.f $DEFAULT: 0.18f $DESCRIPTION: "pivot target output" // P_slope - float curve_contrast_around_pivot; // $MIN: 0.1f $MAX: 10.f $DEFAULT: 2.4f $DESCRIPTION: "contrast" + float curve_contrast_around_pivot; // $MIN: 0.1f $MAX: 10.f $DEFAULT: 3.0f $DESCRIPTION: "contrast" // related to P_tlength; the number expresses the portion of the y range below the pivot float curve_linear_ratio_below_pivot; // $MIN: 0.f $MAX: 1.f $DEFAULT: 0.f $DESCRIPTION: "toe start" // related to P_slength; the number expresses the portion of the y range below the pivot @@ -123,7 +123,7 @@ typedef struct dt_iop_agx_params_t // t_p float curve_toe_power; // $MIN: 0.f $MAX: 10.f $DEFAULT: 1.5f $DESCRIPTION: "toe power" // s_p - float curve_shoulder_power; // $MIN: 0.f $MAX: 10.f $DEFAULT: 1.5f $DESCRIPTION: "shoulder power" + float curve_shoulder_power; // $MIN: 0.f $MAX: 10.f $DEFAULT: 3.3f $DESCRIPTION: "shoulder power" float curve_gamma; // $MIN: 0.01f $MAX: 100.f $DEFAULT: 2.2f $DESCRIPTION: "curve y gamma" gboolean auto_gamma; // $DEFAULT: FALSE $DESCRIPTION: "keep the pivot on the diagonal" // t_ly @@ -1849,9 +1849,10 @@ static GtkWidget* _create_basic_curve_controls_box(dt_iop_module_t *self, "higher values keep the slope nearly constant for longer,\n" "at the cost of a more sudden drop near white")); dt_bauhaus_widget_set_quad_tooltip(slider, - _("the curve has lost its 'S' shape, shoulder power cannot be applied.\n" + _("shoulder power setting is ineffective, as the curve is no longer S-shaped.\n" "without inverting the shoulder (forcing it to bend upwards), it would be\n" "impossible to reach target white with the selected contrast and pivot position.\n" + "if you see artifacts, or wish to regain the control, try the following:\n" "increase contrast, move the pivot higher (increase pivot target output\n" "or curve y gamma), or increase the distance between the pivot and the right\n" "edge (decrease the pivot shift, move the white point farther from the pivot by\n" @@ -1866,9 +1867,10 @@ static GtkWidget* _create_basic_curve_controls_box(dt_iop_module_t *self, "higher values keep the slope nearly constant for longer,\n" "at the cost of a more sudden drop near black")); dt_bauhaus_widget_set_quad_tooltip(slider, - _("the curve has lost its 'S' shape, toe power cannot be applied.\n" + _("toe power setting is ineffective, as the curve is no longer S-shaped.\n" "without inverting the toe (forcing it to bend downwards), it would be\n" "impossible to reach target black with the selected contrast and pivot position.\n" + "if you see artifacts, or wish to regain the control, try the following:\n" "increase contrast, move the pivot lower (reduce the pivot target output or\n" "curve y gamma), or increase the distance between the pivot and the left edge\n" "(increase the pivot shift, move the black point farther from the pivot by raising\n" From 4e0ef5cbfe7b6bed408b52bb1265f9be0bb65362 Mon Sep 17 00:00:00 2001 From: Kofa Date: Sat, 10 Jan 2026 16:45:39 +0100 Subject: [PATCH 13/13] agx: slight tooltip wording change to make it clear the warning does not indicate an error that must be fixed --- src/iop/agx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/iop/agx.c b/src/iop/agx.c index 23716a99e51e..d54edf0e3b63 100644 --- a/src/iop/agx.c +++ b/src/iop/agx.c @@ -1852,7 +1852,8 @@ static GtkWidget* _create_basic_curve_controls_box(dt_iop_module_t *self, _("shoulder power setting is ineffective, as the curve is no longer S-shaped.\n" "without inverting the shoulder (forcing it to bend upwards), it would be\n" "impossible to reach target white with the selected contrast and pivot position.\n" - "if you see artifacts, or wish to regain the control, try the following:\n" + "this is not an error, the module is still working correctly.\n" + "if you see artifacts, or wish to regain control over the shoulder, try the following:\n" "increase contrast, move the pivot higher (increase pivot target output\n" "or curve y gamma), or increase the distance between the pivot and the right\n" "edge (decrease the pivot shift, move the white point farther from the pivot by\n" @@ -1870,7 +1871,8 @@ static GtkWidget* _create_basic_curve_controls_box(dt_iop_module_t *self, _("toe power setting is ineffective, as the curve is no longer S-shaped.\n" "without inverting the toe (forcing it to bend downwards), it would be\n" "impossible to reach target black with the selected contrast and pivot position.\n" - "if you see artifacts, or wish to regain the control, try the following:\n" + "this is not an error, the module is still working correctly.\n" + "if you see artifacts, or wish to regain control over the toe, try the following:\n" "increase contrast, move the pivot lower (reduce the pivot target output or\n" "curve y gamma), or increase the distance between the pivot and the left edge\n" "(increase the pivot shift, move the black point farther from the pivot by raising\n"