62#define DT_IOP_COLOREQUAL_NUM_CHANNELS 3
63#define DT_IOP_COLOREQUAL_NUM_RINGS 3
64#define DT_IOP_COLOREQUAL_MAXNODES 20
65#define DT_IOP_COLOREQUAL_DEFAULT_NODES 8
66#define DT_IOP_COLOREQUAL_GRAPH_RES 360
67#define DT_IOP_COLOREQUAL_GRAPH_GRADIENTS 48
68#define DT_IOP_COLOREQUAL_HUE_SAMPLES 64
69#define DT_IOP_COLOREQUAL_VIEWER_CONTROL_NODES (DT_IOP_COLOREQUAL_NUM_RINGS * DT_IOP_COLOREQUAL_HUE_SAMPLES)
70#define DT_IOP_COLOREQUAL_AXIAL_SAMPLES 64
71#define DT_IOP_COLOREQUAL_CLUT_LEVEL 64
72#define DT_IOP_COLOREQUAL_LOCAL_FIELD_RINGS (DT_IOP_COLOREQUAL_NUM_RINGS + 1)
73#define DT_IOP_COLOREQUAL_MIN_X_DISTANCE 0.01f
74#define DT_IOP_COLOREQUAL_PREVIEW_CURSOR_RADIUS DT_PIXEL_APPLY_DPI(14.f)
75#define DT_IOP_COLOREQUAL_GRAPH_INSET DT_PIXEL_APPLY_DPI(4)
76#define DT_IOP_COLOREQUAL_AXIS_HEIGHT DT_PIXEL_APPLY_DPI(14)
77#define DT_IOP_COLOREQUAL_SCROLL_SIGMA 2.f * M_PI_F / 128.f
78#define DT_IOP_COLOREQUAL_SCROLL_STEP 0.05f
79#define DT_IOP_COLOREQUAL_SCROLL_STEP_FINE 0.02f
80#define DT_IOP_COLOREQUAL_SCROLL_STEP_COARSE 0.10f
81#define DT_IOP_COLOREQUAL_SCROLL_HUE_STEP (5.f * M_PI_F / 180.f)
82#define DT_IOP_COLOREQUAL_SCROLL_HUE_STEP_FINE (1.f * M_PI_F / 180.f)
83#define DT_IOP_COLOREQUAL_SCROLL_HUE_STEP_COARSE (10.f * M_PI_F / 180.f)
212 return _(
"color equalizer");
217 return _(
"color zones");
223 self, _(
"stretch RGB colors around the achromatic axis from editable dt UCS hue nodes"), _(
"creative"),
224 _(
"linear, RGB, display-referred"), _(
"linear, RGB"), _(
"linear, RGB, display-referred"));
252 return (y - 0.5f) * 2.f *
M_PI_F;
256 return CLAMP(y * 2.f, 0.f, 2.f);
265 return CLAMP(
value / (2.f *
M_PI_F) + 0.5f, 0.f, 1.f);
269 return CLAMP(
value * 0.5f, 0.f, 1.f);
280 return _(
"highlights");
283 return _(
"midtones");
291 return p->curve[ring][channel];
298 return p->curve[ring][channel];
304 return &
p->curve_num_nodes[ring][channel];
311 return p->curve_num_nodes[ring][channel];
337 && !memcmp(a->
curve, b->curve,
sizeof(a->
curve));
349 const float distance = fabsf(x0 - x1);
350 return fminf(distance, 1.f - distance);
369 const int page = (
g &&
g->ring_notebook) ? gtk_notebook_get_current_page(
g->ring_notebook) : -1;
378 const int page = (
g &&
g->channel_notebook[ring]) ? gtk_notebook_get_current_page(
g->channel_notebook[ring]) : -1;
385 g->cursor_sample_valid =
FALSE;
387 memset(
g->cursor_input_display, 0,
sizeof(
g->cursor_input_display));
388 memset(
g->cursor_output_display, 0,
sizeof(
g->cursor_output_display));
393 float *curve_x,
float *curve_y,
float *offset_normalized)
413 *offset_normalized = CLAMP(
value /
M_PI_F, -1.f, 1.f);
418 *offset_normalized = CLAMP(
value - 1.f, -1.f, 1.f);
428 RGB[0] = CLAMP(
RGB[0], 0.f, 1.f);
429 RGB[1] = CLAMP(
RGB[1], 0.f, 1.f);
430 RGB[2] = CLAMP(
RGB[2], 0.f, 1.f);
448 float in[4] = { work_rgb[0], work_rgb[1], work_rgb[2], 0.f };
449 float out[4] = { work_rgb[0], work_rgb[1], work_rgb[2], 0.f };
451 display_rgb[0] =
out[0];
452 display_rgb[1] =
out[1];
453 display_rgb[2] =
out[2];
460 for(
int c = 0; c < 3; c++)
RGB[c] = low[c] * (1.f -
mix) + high[c] *
mix;
471 const float mix = hue - floorf(hue);
473 for(
int c = 0; c < 3; c++)
474 RGB[c] = ring_surface[ring][hue0][c] * (1.f -
mix) + ring_surface[ring][hue1][c] *
mix;
485 const float brightness,
const float hue_position,
const float white,
496 while(segment < DT_IOP_COLOREQUAL_NUM_RINGS + 1 && brightness > anchor_positions[segment + 1]) segment++;
498 const float low_position = anchor_positions[segment];
499 const float high_position = anchor_positions[segment + 1];
501 = (high_position > low_position) ? (brightness - low_position) / (high_position - low_position) : 0.f;
552 const size_t clut_size
568 chroma_scale[ring][hue_sample] = 1.f;
579 const float reference_saturation =
d->reference_saturation[ring];
606 CLAMP(brightness * bright_gain, 0.f, 1.f), 0.f };
615 float Lp, rhop, thetap;
634 const float requested_scale = sat_gain;
635 const float projected_scale = (rhop > 1e-6f) ? (rhoa / rhop) : 1.f;
636 const float effective_scale
637 = (requested_scale <= 1.f) ? requested_scale : fminf(requested_scale, projected_scale);
639 anchor_L[ring][hue_sample] = Lp;
640 anchor_rho[ring][hue_sample] = rhop;
641 anchor_theta[ring][hue_sample] = thetap;
642 delta_L[ring][hue_sample] = La - Lp;
643 chroma_scale[ring][hue_sample] = effective_scale;
671 const float sigma_L = fmaxf(
p->sigma_L * 0.01f, 1e-6f);
672 const float sigma_rho = fmaxf(
p->sigma_rho, 1e-6f);
673 const float sigma_theta = fmaxf(
p->sigma_theta, 1e-6f);
674 const float neutral_protection = fmaxf(
p->neutral_protection, 0.f);
676 delta_L, chroma_scale, delta_theta, 1.f / sigma_L, 1.f / sigma_rho,
677 1.f / sigma_theta, neutral_protection * sigma_rho);
708 const float saturation = reference_saturation[ring];
735 CLAMP(brightness * bright_gain, 0.f, 1.f), 0.f };
744 for(
int c = 0; c < 3; c++)
746 control_nodes[count].
input_rgb[c] = before_rgb[c];
747 control_nodes[count].
output_rgb[c] = after_rgb[c];
773 d->lut_profile = NULL;
774 d->work_profile = NULL;
785 d->built_params = *
p;
786 d->clut_valid =
TRUE;
789 d->white_level = exp2f(
p->white_level);
802 d->white_level = 1.f;
803 d->lut_profile = NULL;
804 memset(
d->reference_saturation, 0,
sizeof(
d->reference_saturation));
805 d->work_profile = NULL;
820 cl_mem dev_in, cl_mem dev_out)
826 const int devid = pipe->
devid;
828 const float white_level = fmaxf(
d->white_level, 1e-6f);
829 const float normalize = 1.f / white_level;
830 const float denormalize = white_level;
831 const float black = 0.f;
832 cl_mem clut_cl = NULL;
833 cl_int err = CL_SUCCESS;
847 if(err != CL_SUCCESS)
goto cleanup;
850 d->lut_profile,
"colorequal work to HLG Rec2020"))
852 err = CL_INVALID_OPERATION;
860 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
871 if(err != CL_SUCCESS)
goto cleanup;
874 d->work_profile,
"colorequal HLG Rec2020 to work"))
876 err = CL_INVALID_OPERATION;
891 return err == CL_SUCCESS;
897 const void *
const ibuf,
void *
const obuf)
910 const float white_level = fmaxf(
d->white_level, 1e-6f);
914 const float *
const in = (
const float *)ibuf +
k *
ch;
915 float *
const out = (
float *)obuf +
k *
ch;
916 out[0] = in[0] / white_level;
917 out[1] = in[1] / white_level;
918 out[2] = in[2] / white_level;
919 if(
ch > 3)
out[3] = in[3];
923 d->lut_profile,
"colorequal work to HLG Rec2020");
929 "colorequal HLG Rec2020 to work");
933 float *
const out = (
float *)obuf +
k *
ch;
934 out[0] *= white_level;
935 out[1] *= white_level;
936 out[2] *= white_level;
958 if(!
g->viewer_lut_dirty &&
g->viewer_lut_valid &&
_lut_fields_equal(&
g->viewer_lut_params,
p))
return;
971 g->viewer_lut_dirty =
FALSE;
972 g->viewer_lut_valid =
FALSE;
973 g->viewer_control_node_count = 0;
978 g->viewer_lut_params = *
p;
982 g->viewer_lut.lut_profile, display_profile);
984 g->viewer_lut_dirty =
FALSE;
985 g->viewer_lut_valid =
TRUE;
990 dt_print(
DT_DEBUG_PERF,
"[colorequal] gui LUT cache sync level=%u total=%.3fms\n",
g->viewer_lut.clut_level,
1018 if(!
g->curve[ring][
ch] ||
g->curve_nodes[ring][
ch] != nodes ||
g->curve[ring][
ch]->c.m_numAnchors != nodes)
1022 g->curve_nodes[ring][
ch] = nodes;
1035 memcpy(&
g->cached_curve_params,
p,
sizeof(*
p));
1036 g->curve_cache_valid =
TRUE;
1044 const float ring_brightness,
const float reference_saturation,
1053 HSB[1] = reference_saturation;
1054 HSB[2] = ring_brightness;
1058 HSB[1] = reference_saturation;
1065 HSB[2] = ring_brightness;
1072 const float graph_height,
const float white,
const float reference_saturation,
1096 cairo_pattern_t *gradient = cairo_pattern_create_linear(0.0, 0.0, graph_width, 0.0);
1106 cairo_set_source(cr, gradient);
1108 cairo_pattern_destroy(gradient);
1125 GtkAllocation allocation;
1126 gtk_widget_get_allocation(widget, &allocation);
1127 GtkStyleContext *context = gtk_widget_get_style_context(widget);
1130 const float graph_width = allocation.width - 2.f * inset;
1144 const float background_saturation
1146 : CLAMP(
g->reference_saturation[ring] * 1.35f, 0.f, 1.f);
1149 cairo_t *cr = cairo_create(cst);
1151 if(!
g->background_surface[ring][channel] ||
g->cached_width[ring][channel] != allocation.width
1152 ||
g->cached_height[ring][channel] != allocation.height
1153 || fabsf(
g->cached_white[ring][channel] - white) > 1e-6f
1154 || fabsf(
g->cached_reference_saturation[ring][channel] - background_saturation) > 1e-6f
1155 ||
g->cached_display_profile[ring][channel] != display_profile)
1157 if(
g->background_surface[ring][channel]) cairo_surface_destroy(
g->background_surface[ring][channel]);
1158 g->background_surface[ring][channel]
1160 cairo_t *background_cr = cairo_create(
g->background_surface[ring][channel]);
1162 gtk_render_background(context, background_cr, 0, 0, allocation.width, allocation.height);
1163 cairo_translate(background_cr, inset, inset);
1164 _draw_graph_background(background_cr, channel, ring, graph_width, graph_height, white, background_saturation,
1167 cairo_rectangle(background_cr, 0.f, 0.f, graph_width, graph_height);
1168 cairo_clip(background_cr);
1172 dt_draw_grid(background_cr, 8, 0, 0, graph_width, graph_height);
1176 cairo_move_to(background_cr, 0.f, 0.5f * graph_height);
1177 cairo_line_to(background_cr, graph_width, 0.5f * graph_height);
1178 cairo_stroke(background_cr);
1180 cairo_reset_clip(background_cr);
1181 cairo_translate(background_cr, 0.f, graph_height);
1182 cairo_pattern_t *axis = cairo_pattern_create_linear(0.0, 0.0, graph_width, 0.0);
1191 white, display_profile,
RGB);
1192 cairo_pattern_add_color_stop_rgba(axis,
x,
RGB[0],
RGB[1],
RGB[2], 1.0);
1196 cairo_set_source(background_cr, axis);
1197 cairo_fill(background_cr);
1198 cairo_pattern_destroy(axis);
1199 cairo_destroy(background_cr);
1201 g->cached_width[ring][channel] = allocation.width;
1202 g->cached_height[ring][channel] = allocation.height;
1203 g->cached_white[ring][channel] = white;
1204 g->cached_reference_saturation[ring][channel] = background_saturation;
1205 g->cached_display_profile[ring][channel] = display_profile;
1208 cairo_set_source_surface(cr,
g->background_surface[ring][channel], 0, 0);
1211 cairo_translate(cr, inset, inset);
1218 cairo_move_to(cr, picker_x, 0.f);
1225 if(
g->cursor_sample_valid && ring == active_ring && channel == active_channel)
1229 cairo_set_source_rgba(cr, 0.f, 0.f, 0.f, 0.75f);
1230 cairo_move_to(cr, cursor_x, 0.f);
1235 cairo_set_source_rgba(cr,
g->cursor_output_display[0],
g->cursor_output_display[1],
g->cursor_output_display[2],
1237 cairo_move_to(cr, cursor_x, 0.f);
1242 cairo_rectangle(cr, 0.f, 0.f, graph_width, graph_height);
1251 const float y = (1.f -
g->draw_ys[ring][channel][
k]) * graph_height;
1254 cairo_move_to(cr,
x, y);
1256 cairo_line_to(cr,
x, y);
1264 for(
int k = 0;
k < nodes;
k++)
1266 const float x = curve[
k].
x * graph_width;
1267 const float y = (1.f - curve[
k].
y) * graph_height;
1271 cairo_stroke_preserve(cr);
1276 if(
g->cursor_sample_valid && ring == active_ring && channel == active_channel)
1278 float curve_x = 0.f;
1279 float curve_y = 0.f;
1280 float offset_normalized = 0.f;
1283 const float marker_x = curve_x * graph_width;
1284 const float marker_y = (1.f - curve_y) * graph_height;
1290 cairo_set_source_rgba(cr, 0.f, 0.f, 0.f, 0.4f);
1291 cairo_arc(cr, marker_x, marker_y, intensity_radius, 0.f, 2.f *
M_PI_F);
1294 if(fabsf(offset_normalized) > 1e-4f)
1297 cairo_set_source_rgba(cr,
g->cursor_output_display[0],
g->cursor_output_display[1],
1298 g->cursor_output_display[2], 0.95);
1299 if(offset_normalized > 0.f)
1300 cairo_arc(cr, marker_x, marker_y, intensity_radius, -
M_PI_F / 2.f,
1301 -
M_PI_F / 2.f + 2.f *
M_PI_F * fabsf(offset_normalized));
1303 cairo_arc_negative(cr, marker_x, marker_y, intensity_radius, -
M_PI_F / 2.f,
1304 -
M_PI_F / 2.f - 2.f *
M_PI_F * fabsf(offset_normalized));
1308 cairo_arc(cr, marker_x, marker_y, outer_radius, 0.f, 2.f *
M_PI_F);
1309 cairo_set_source_rgba(cr,
g->cursor_output_display[0],
g->cursor_output_display[1],
1310 g->cursor_output_display[2], 0.95);
1311 cairo_fill_preserve(cr);
1312 cairo_set_source_rgba(cr, 0.f, 0.f, 0.f, 0.9f);
1315 cairo_arc(cr, marker_x, marker_y, inner_radius, 0.f, 2.f *
M_PI_F);
1316 cairo_set_source_rgba(cr,
g->cursor_input_display[0],
g->cursor_input_display[1],
g->cursor_input_display[2],
1318 cairo_fill_preserve(cr);
1319 cairo_set_source_rgba(cr, 1.f, 1.f, 1.f, 0.8f);
1324 cairo_reset_clip(cr);
1327 cairo_set_source_surface(crf, cst, 0, 0);
1329 cairo_surface_destroy(cst);
1334 const guint64 producer_node_key, gpointer user_data)
1337 (
void)producer_node_key;
1344 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1358 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1364 const float graph_width,
const float graph_height)
1373 for(
int k = 0;
k < nodes;
k++)
1375 const float node_x = curve[
k].
x * graph_width;
1376 const float node_y = (1.f - curve[
k].
y) * graph_height;
1377 const float dx = mouse_x - node_x;
1378 const float dy = mouse_y - node_y;
1379 const float distance = dx * dx + dy * dy;
1399 for(
int k = 1;
k < *nodes;
k++)
1407 if(selected == -1) selected = *nodes;
1413 for(
int k = *nodes;
k > selected;
k--)
1415 curve[
k].
x = curve[
k - 1].
x;
1416 curve[
k].
y = curve[
k - 1].
y;
1419 curve[selected].
x =
x;
1420 curve[selected].
y = y;
1434 float new_x = CLAMP(
x, 0.f, 0.999f);
1435 const float new_y = CLAMP(y, 0.f, 1.f);
1442 else if(node == nodes - 1)
1453 curve[node].
x = new_x;
1454 curve[node].
y = new_y;
1466 GtkAllocation allocation;
1467 gtk_widget_get_allocation(widget, &allocation);
1470 const float graph_height
1475 if(
g->dragging[ring][channel] &&
g->selected[ring][channel] >= 0)
1478 1.f - mouse_y / graph_height))
1481 g->curve_cache_valid =
FALSE;
1482 g->viewer_lut_dirty =
TRUE;
1483 if(
g->cursor_valid &&
g->has_focus)
1490 gtk_widget_queue_draw(widget);
1496 g->selected[ring][channel]
1498 gtk_widget_queue_draw(widget);
1517 GtkAllocation allocation;
1518 gtk_widget_get_allocation(widget, &allocation);
1520 const float graph_height
1525 if(event->button == 1 && event->type == GDK_2BUTTON_PRESS)
1527 *nodes = default_nodes;
1528 for(
int k = 0;
k < default_nodes;
k++) curve[
k] = default_curve[
k];
1530 g->selected[ring][channel] = -1;
1532 g->curve_cache_valid =
FALSE;
1533 g->viewer_lut_dirty =
TRUE;
1534 if(
g->cursor_valid &&
g->has_focus)
1541 gtk_widget_queue_draw(widget);
1549 const int selected =
_add_node(curve, nodes, mouse_x, y);
1553 g->selected[ring][channel] = selected;
1555 g->curve_cache_valid =
FALSE;
1556 g->viewer_lut_dirty =
TRUE;
1557 if(
g->cursor_valid &&
g->has_focus)
1564 gtk_widget_queue_draw(widget);
1570 if(event->button == 1)
1573 (1.f - mouse_y) * graph_height, graph_width, graph_height);
1574 g->dragging[ring][channel] = (
g->selected[ring][channel] >= 0);
1578 if(event->button == 3 &&
g->selected[ring][channel] >= 0 && *nodes > 2)
1580 for(
int k =
g->selected[ring][channel];
k < *nodes - 1;
k++) curve[
k] = curve[
k + 1];
1583 g->selected[ring][channel] = -1;
1585 g->curve_cache_valid =
FALSE;
1586 g->viewer_lut_dirty =
TRUE;
1587 if(
g->cursor_valid &&
g->has_focus)
1594 gtk_widget_queue_draw(widget);
1603 if(event->button == 1)
1611 const gboolean was_dragging =
g->dragging[ring][channel];
1612 g->dragging[ring][channel] =
FALSE;
1642 const int source_ring = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(
notebook),
"colorequal-ring"));
1645 dt_conf_set_int(
"plugins/darkroom/colorequal/gui_channel_page", (
int)page_num);
1651 if(ring != source_ring) gtk_notebook_set_current_page(
g->channel_notebook[ring], (
int)page_num);
1655 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1670 dt_conf_set_int(
"plugins/darkroom/colorequal/gui_ring_page", (
int)page_num);
1671 GtkWidget *page_widget = gtk_notebook_get_nth_page(
1672 g->channel_notebook[page_num], gtk_notebook_get_current_page(
g->channel_notebook[page_num]));
1676 g_object_get_data(G_OBJECT(page_widget),
"colorequal-channel"));
1681 if(
g->cursor_valid &&
g->has_focus)
1685 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1694 if(!
g->has_focus)
return 0;
1707 if(wd < 1 || ht < 1)
return 0;
1709 float point[2] = { (float)
x, (
float)y };
1713 const int cursor_x = (int)
point[0];
1714 const int cursor_y = (int)
point[1];
1715 if(cursor_x >= 0 && cursor_x < wd && cursor_y >= 0 && cursor_y < ht)
1717 g->cursor_valid =
TRUE;
1718 g->cursor_pos_x = cursor_x;
1719 g->cursor_pos_y = cursor_y;
1733 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1735 return g->cursor_valid ? 1 : 0;
1747 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1756 if(!
g->has_focus || which != 3 || !
g->cursor_valid || !
g->cursor_sample_valid
1762 if(self->
off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->
off), 1);
1775 const int selected =
_add_node(curve, nodes, curve_x, curve_y);
1776 if(selected < 0)
return 1;
1778 g->selected[ring][channel] = selected;
1780 g->curve_cache_valid =
FALSE;
1781 g->viewer_lut_dirty =
TRUE;
1783 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1798 if(self->
off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->
off), 1);
1806 if(nodes < 1)
return 1;
1808 const float direction = up ? 1.f : -1.f;
1820 for(
int k = 0;
k < nodes;
k++)
1823 const float weight = expf(-(distance * distance) / sigma2);
1843 g->curve_cache_valid =
FALSE;
1844 g->viewer_lut_dirty =
TRUE;
1846 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1854 int32_t pointerx, int32_t pointery)
1862 if(!
g->cursor_sample_valid)
1869 float curve_x = 0.f;
1870 float curve_y = 0.f;
1871 float offset_normalized = 0.f;
1872 if(!
_cursor_curve_state(&
g->gui_params, ring, channel,
g->cursor_hue, &curve_x, &curve_y, &offset_normalized))
1878 const float pointer_x =
g->cursor_pos_x;
1879 const float pointer_y =
g->cursor_pos_y;
1881 const float inner_radius = outer_radius * 0.55f;
1882 const float intensity_radius = outer_radius * 1.55f;
1883 const float crosshair_gap = outer_radius * 0.25f;
1884 const float crosshair_extent = intensity_radius +
DT_PIXEL_APPLY_DPI(5.f) / zoom_scale;
1887 cairo_set_source_rgba(cr, 0.f, 0.f, 0.f, 0.35f);
1888 cairo_arc(cr, pointer_x, pointer_y, intensity_radius, 0.f, 2.f *
M_PI_F);
1891 if(fabsf(offset_normalized) > 1e-4f)
1894 cairo_set_source_rgba(cr,
g->cursor_output_display[0],
g->cursor_output_display[1],
g->cursor_output_display[2],
1896 if(offset_normalized > 0.f)
1897 cairo_arc(cr, pointer_x, pointer_y, intensity_radius, -
M_PI_F / 2.f,
1898 -
M_PI_F / 2.f + 2.f *
M_PI_F * fabsf(offset_normalized));
1900 cairo_arc_negative(cr, pointer_x, pointer_y, intensity_radius, -
M_PI_F / 2.f,
1901 -
M_PI_F / 2.f - 2.f *
M_PI_F * fabsf(offset_normalized));
1906 cairo_set_source_rgba(cr, 1.f, 1.f, 1.f, 0.6f);
1907 cairo_move_to(cr, pointer_x - crosshair_extent, pointer_y);
1908 cairo_line_to(cr, pointer_x - outer_radius - crosshair_gap, pointer_y);
1909 cairo_move_to(cr, pointer_x + outer_radius + crosshair_gap, pointer_y);
1910 cairo_line_to(cr, pointer_x + crosshair_extent, pointer_y);
1911 cairo_move_to(cr, pointer_x, pointer_y - crosshair_extent);
1912 cairo_line_to(cr, pointer_x, pointer_y - outer_radius - crosshair_gap);
1913 cairo_move_to(cr, pointer_x, pointer_y + outer_radius + crosshair_gap);
1914 cairo_line_to(cr, pointer_x, pointer_y + crosshair_extent);
1917 cairo_arc(cr, pointer_x, pointer_y, outer_radius, 0.f, 2.f *
M_PI_F);
1918 cairo_set_source_rgba(cr,
g->cursor_output_display[0],
g->cursor_output_display[1],
g->cursor_output_display[2],
1920 cairo_fill_preserve(cr);
1921 cairo_set_source_rgba(cr, 0.f, 0.f, 0.f, 0.9f);
1924 cairo_arc(cr, pointer_x, pointer_y, inner_radius, 0.f, 2.f *
M_PI_F);
1925 cairo_set_source_rgba(cr,
g->cursor_input_display[0],
g->cursor_input_display[1],
g->cursor_input_display[2], 0.95);
1926 cairo_fill_preserve(cr);
1927 cairo_set_source_rgba(cr, 1.f, 1.f, 1.f, 0.8f);
1952 if(!widget || !gtk_widget_get_window(widget))
return;
1968 if(
g->cursor_valid && self->
enabled)
1972 _(
"scroll over image to adjust the selected color graph\n"
1973 "right-click to add a node at the sampled hue"));
1984 if(!self->
enabled || !
g->cursor_valid)
2019 const float point_preview[2] = { (float)
g->cursor_pos_x, (
float)
g->cursor_pos_y };
2020 float point_image[2] = { point_preview[0], point_preview[1] };
2023 const float scale_x = (previous_piece->
buf_out.
width > 0)
2029 const float sample_x
2030 = point_image[0] * (float)previous_piece->
buf_out.
width * scale_x - (
float)previous_piece->
roi_out.
x;
2031 const float sample_y
2032 = point_image[1] * (float)previous_piece->
buf_out.
height * scale_y - (
float)previous_piece->
roi_out.
y;
2033 const int xi = CLAMP((
int)lroundf(sample_x), 0, previous_piece->
roi_out.
width - 1);
2034 const int yi = CLAMP((
int)lroundf(sample_y), 0, previous_piece->
roi_out.
height - 1);
2037 const float *
const input_rgbf
2039 input_rgb[0] = input_rgbf[0];
2040 input_rgb[1] = input_rgbf[1];
2041 input_rgb[2] = input_rgbf[2];
2051 g->viewer_lut.clut,
g->viewer_lut.clut_level, NULL,
2055 const float white_level = fmaxf(exp2f(
g->gui_params.white_level), 1e-6f);
2056 projected_rgb[0] = input_rgb[0] / white_level;
2057 projected_rgb[1] = input_rgb[1] / white_level;
2058 projected_rgb[2] = input_rgb[2] / white_level;
2060 const float neutral = CLAMP((projected_rgb[0] + projected_rgb[1] + projected_rgb[2]) / 3.f, 0.f, 1.f);
2066 if(!isfinite(HSB[0]))
2075 g->cursor_sample_valid =
TRUE;
2087 if(brightness <= 0.15f)
2089 g_snprintf(text,
size,
"%d%% %s", 100, _(
"shadows"));
2091 else if(brightness < 0.45f)
2093 const float t = (brightness - 0.15f) / (0.45f - 0.15f);
2094 const int shadows = CLAMP((
int)lroundf((1.f -
t) * 100.f), 0, 100);
2095 g_snprintf(text,
size,
"%d%% %s, %d%% %s", shadows, _(
"shadows"), 100 - shadows, _(
"midtones"));
2097 else if(brightness < 0.75f)
2099 const float t = (brightness - 0.45f) / (0.75f - 0.45f);
2100 const int midtones = CLAMP((
int)lroundf((1.f -
t) * 100.f), 0, 100);
2101 g_snprintf(text,
size,
"%d%% %s, %d%% %s", midtones, _(
"midtones"), 100 - midtones, _(
"highlights"));
2105 g_snprintf(text,
size,
"%d%% %s", 100, _(
"highlights"));
2114 const dt_iop_module_t *sampled_module = piece && piece->module ? piece->module : self;
2116 if(picker ==
g->white_level)
2122 p->white_level = log2f(max_Ych[0]);
2123 g->gui_params.white_level =
p->white_level;
2129 else if(picker ==
g->module_picker)
2134 gtk_label_set_text(GTK_LABEL(
g->picker_info), _(
"no sample"));
2137 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][
ch]));
2144 char text[128] = { 0 };
2145 const float white_level = fmaxf(exp2f(
g->gui_params.white_level), 1e-6f);
2165 g->picker_valid =
TRUE;
2167 g->picker_brightness = CLAMP(HSB[2], 0.f, 1.f);
2169 gtk_label_set_text(GTK_LABEL(
g->picker_info), text);
2173 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][
ch]));
2186 const float *
const restrict in = (
const float *)
i;
2190 for(
size_t k = 0;
k < (size_t)roi_out->
width * roi_out->
height * 4;
k += 4)
2194 if(isfinite(Ych[0]))
2195 max_Y = fmaxf(max_Y, Ych[0]);
2198 p->white_level = log2f(fmaxf(max_Y, 1e-6f));
2200 g->gui_params.white_level =
p->white_level;
2211 g->curve_cache_valid =
FALSE;
2214 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][
ch]));
2242 if(!
g->preview_signal_connected)
2246 g->preview_signal_connected =
TRUE;
2252 else if(
g->preview_signal_connected)
2255 g->preview_signal_connected =
FALSE;
2274 g->curve[ring][
ch] = NULL;
2275 if(
g->background_surface[ring][
ch]) cairo_surface_destroy(
g->background_surface[ring][
ch]);
2276 g->background_surface[ring][
ch] = NULL;
2280 g->viewer_lut.clut = NULL;
2283 if(
g->preview_signal_connected)
2286 g->preview_signal_connected =
FALSE;
2291 dt_conf_set_int(
"plugins/darkroom/colorequal/gui_ring_page", current_primary);
2293 gtk_notebook_get_current_page(
g->channel_notebook[0]));
2301 g->curve_cache_valid =
FALSE;
2302 g->viewer_lut_dirty =
TRUE;
2303 g->viewer_lut_valid =
FALSE;
2304 g->preview_signal_connected =
FALSE;
2311 gtk_box_pack_start(GTK_BOX(self->
widget), ring_tabs_box,
TRUE,
TRUE, 0);
2313 g->ring_notebook = GTK_NOTEBOOK(gtk_notebook_new());
2314 gtk_widget_set_name(GTK_WIDGET(
g->ring_notebook),
"colorequal-ring-tabs");
2315 gtk_notebook_set_show_border(
g->ring_notebook,
FALSE);
2317 gtk_box_pack_start(GTK_BOX(ring_tabs_box), GTK_WIDGET(
g->ring_notebook),
TRUE,
TRUE, 0);
2328 gtk_notebook_append_page(
g->ring_notebook, ring_page, ring_label);
2329 gtk_container_child_set(GTK_CONTAINER(
g->ring_notebook), ring_page,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
2331 g->channel_notebook[ring] = GTK_NOTEBOOK(gtk_notebook_new());
2332 g_object_set_data(G_OBJECT(
g->channel_notebook[ring]),
"colorequal-ring", GINT_TO_POINTER(ring));
2335 gtk_box_pack_start(GTK_BOX(ring_page), GTK_WIDGET(
g->channel_notebook[ring]),
TRUE,
TRUE, 0);
2341 g_object_set_data(G_OBJECT(channel_page),
"colorequal-channel", GINT_TO_POINTER(
ch));
2342 g->area[ring][
ch] = GTK_DRAWING_AREA(gtk_drawing_area_new());
2343 gtk_widget_set_hexpand(GTK_WIDGET(
g->area[ring][
ch]),
TRUE);
2344 gtk_widget_add_events(GTK_WIDGET(
g->area[ring][
ch]),
2345 GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
2346 g_object_set_data(G_OBJECT(
g->area[ring][
ch]),
"colorequal-ring", GINT_TO_POINTER(ring));
2347 g_object_set_data(G_OBJECT(
g->area[ring][
ch]),
"colorequal-channel", GINT_TO_POINTER(
ch));
2348 g_signal_connect(G_OBJECT(
g->area[ring][
ch]),
"draw", G_CALLBACK(
_draw_curve), self);
2349 g_signal_connect(G_OBJECT(
g->area[ring][
ch]),
"motion-notify-event",
2353 g_signal_connect(G_OBJECT(
g->area[ring][
ch]),
"button-release-event",
2356 gtk_box_pack_start(GTK_BOX(channel_page),
2358 "plugins/darkroom/colorequal/graphheight", 220, 100),
2360 gtk_notebook_append_page(
g->channel_notebook[ring], channel_page, gtk_label_new(channel_labels[order]));
2361 gtk_container_child_set(GTK_CONTAINER(
g->channel_notebook[ring]), channel_page,
"tab-expand",
TRUE,
2362 "tab-fill",
TRUE, NULL);
2366 GtkWidget *options_label = gtk_label_new(_(
"options"));
2369 gtk_notebook_append_page(
g->ring_notebook, options_page, options_label);
2370 gtk_container_child_set(GTK_CONTAINER(
g->ring_notebook), options_page,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
2373 self->
widget = options_page;
2394 gtk_widget_set_tooltip_text(
g->interpolation, _(
"select the interpolation method"));
2396 self->
widget = module_root;
2399 gtk_box_pack_start(GTK_BOX(ring_tabs_box), picker_box,
FALSE,
FALSE, 0);
2402 gtk_box_pack_start(GTK_BOX(picker_box),
g->module_picker,
FALSE,
FALSE, 0);
2404 g->picker_info = gtk_label_new(_(
"no sample"));
2405 gtk_widget_set_hexpand(
g->picker_info,
TRUE);
2406 gtk_widget_set_halign(
g->picker_info, GTK_ALIGN_START);
2407 gtk_label_set_xalign(GTK_LABEL(
g->picker_info), 0.f);
2408 gtk_box_pack_start(GTK_BOX(picker_box),
g->picker_info,
TRUE,
TRUE, 0);
2410 const int active_ring =
dt_conf_get_int(
"plugins/darkroom/colorequal/gui_ring_page");
2411 const int active_channel =
dt_conf_get_int(
"plugins/darkroom/colorequal/gui_channel_page");
2416 gtk_notebook_set_current_page(
g->ring_notebook, current_ring_page);
2418 gtk_notebook_set_current_page(
g->channel_notebook[ring], current_channel_page);
2424 g->viewer_lut.clut = NULL;
2425 g->viewer_lut.clut_level = 0;
2426 memset(
g->viewer_lut.reference_saturation, 0,
sizeof(
g->viewer_lut.reference_saturation));
2427 g->viewer_lut.lut_profile = NULL;
2428 g->viewer_lut.work_profile = NULL;
2429 g->viewer_control_node_count = 0;
2434 gtk_widget_show_all(self->
widget);
2447 const int lut_program = 28;
2448 const int basic_program = 2;
void cleanup(dt_imageio_module_format_t *self)
static const char neutral[]
void dt_bauhaus_slider_set_soft_range(GtkWidget *widget, float soft_min, float soft_max)
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
static void set_color(cairo_t *cr, GdkRGBA color)
static __DT_CLONE_TARGETS__ void normalize(float *const buffer, const size_t width, const size_t height, const float norm)
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
GtkWidget * dt_color_picker_new_with_cst(dt_iop_module_t *module, dt_iop_color_picker_kind_t kind, GtkWidget *w, const dt_iop_colorspace_type_t cst)
GtkWidget * dt_color_picker_new(dt_iop_module_t *module, dt_iop_color_picker_kind_t kind, GtkWidget *w)
gboolean dt_iop_color_picker_is_visible(const dt_develop_t *dev)
static void _update_gui_lut_cache_throttled(gpointer data)
#define DT_IOP_COLOREQUAL_HUE_SAMPLES
#define DT_IOP_COLOREQUAL_SCROLL_SIGMA
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static void _reset_channel_nodes(dt_iop_colorequal_params_t *p, const dt_iop_colorequal_ring_t ring, const dt_iop_colorequal_channel_t channel)
void init(dt_iop_module_t *module)
static int _add_node(dt_iop_colorequal_node_t *curve, int *nodes, const float x, const float y)
static void _pipe_rgb_to_dt_ucs_hsb(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_aligned_pixel_t RGB, dt_aligned_pixel_t HSB)
static void _mix_rgb_anchors(const dt_aligned_pixel_t low, const dt_aligned_pixel_t high, const float mix, dt_aligned_pixel_t RGB)
const char ** description(struct dt_iop_module_t *self)
static gboolean _area_motion_notify_callback(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
int scrolled(struct dt_iop_module_t *self, double x, double y, int up, uint32_t state)
#define DT_IOP_COLOREQUAL_SCROLL_HUE_STEP
static const char * _ring_label(const dt_iop_colorequal_ring_t ring)
#define DT_IOP_COLOREQUAL_GRAPH_INSET
static gboolean _draw_curve(GtkWidget *widget, cairo_t *crf, gpointer user_data)
static void _update_curve_cache(dt_iop_colorequal_gui_data_t *g, const dt_iop_colorequal_params_t *p)
#define DT_IOP_COLOREQUAL_AXIS_HEIGHT
static void _switch_preview_cursor(dt_iop_module_t *self)
#define DT_IOP_COLOREQUAL_CLUT_LEVEL
static float _curve_periodic_distance(const float x0, const float x1)
void gui_update(dt_iop_module_t *self)
static void _sample_ring_hue(const float ring_surface[3][64][3], const int ring, const float hue_position, dt_aligned_pixel_t RGB)
#define DT_IOP_COLOREQUAL_SCROLL_HUE_STEP_FINE
static gboolean _cursor_curve_state(const dt_iop_colorequal_params_t *p, const dt_iop_colorequal_ring_t ring, const dt_iop_colorequal_channel_t channel, const float hue, float *curve_x, float *curve_y, float *offset_normalized)
static dt_iop_colorequal_channel_t _active_channel_from_gui(const dt_iop_colorequal_gui_data_t *g, const dt_iop_colorequal_ring_t ring)
static dt_iop_colorequal_node_t * _curve_nodes(dt_iop_colorequal_params_t *p, const dt_iop_colorequal_ring_t ring, const dt_iop_colorequal_channel_t channel)
static gboolean _move_selected_node(dt_iop_module_t *self, const dt_iop_colorequal_ring_t ring, const dt_iop_colorequal_channel_t channel, const int node, const float x, const float y)
static void _graph_background_hsb(const dt_iop_colorequal_channel_t channel, const float x, const float y, const float ring_brightness, const float reference_saturation, dt_aligned_pixel_t HSB)
static void _preview_cache_wait_restart(gpointer user_data)
static void _build_clut(dt_iop_colorequal_data_t *d, const dt_iop_colorequal_params_t *p, const dt_iop_order_iccprofile_info_t *lut_profile)
static int _curve_nodes_count_const(const dt_iop_colorequal_params_t *p, const dt_iop_colorequal_ring_t ring, const dt_iop_colorequal_channel_t channel)
void gui_focus(struct dt_iop_module_t *self, gboolean in)
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static void _cacheline_ready_callback(gpointer instance, const guint64 hash, const guint64 producer_node_key, gpointer user_data)
#define DT_IOP_COLOREQUAL_NUM_RINGS
static void _ring_tabs_switch_callback(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data)
static void _draw_graph_background(cairo_t *cr, const dt_iop_colorequal_channel_t channel, const dt_iop_colorequal_ring_t ring, const float graph_width, const float graph_height, const float white, const float reference_saturation, const dt_iop_order_iccprofile_info_t *display_profile)
static gboolean _area_button_press_callback(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
@ DT_IOP_COLOREQUAL_RING_DARK
@ DT_IOP_COLOREQUAL_RING_LIGHT
@ DT_IOP_COLOREQUAL_RING_MID
#define DT_IOP_COLOREQUAL_SCROLL_STEP_COARSE
void gui_init(dt_iop_module_t *self)
static void _channel_tabs_switch_callback(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data)
#define DT_IOP_COLOREQUAL_NUM_CHANNELS
int button_pressed(struct dt_iop_module_t *self, double x, double y, double pressure, int which, int type, uint32_t state)
static gboolean _area_button_release_callback(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
static void _clamp_display_rgb(dt_aligned_pixel_t RGB)
#define DT_IOP_COLOREQUAL_MAXNODES
static const dt_iop_colorequal_node_t * _curve_nodes_const(const dt_iop_colorequal_params_t *p, const dt_iop_colorequal_ring_t ring, const dt_iop_colorequal_channel_t channel)
static dt_iop_colorequal_channel_t _channel_from_page(const int page)
void gui_cleanup(dt_iop_module_t *self)
#define DT_IOP_COLOREQUAL_LOCAL_FIELD_RINGS
static void _update_gui_lut_cache(dt_iop_module_t *self)
void cleanup_global(dt_iop_module_so_t *module)
static void _invalidate_preview_cursor(dt_iop_colorequal_gui_data_t *g)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
static void _format_picker_brightness_position(const float brightness, char *text, const size_t size)
#define DT_IOP_COLOREQUAL_VIEWER_CONTROL_NODES
void gui_post_expose(struct dt_iop_module_t *self, cairo_t *cr, int32_t width, int32_t height, int32_t pointerx, int32_t pointery)
int mouse_leave(struct dt_iop_module_t *self)
static gboolean _lut_fields_equal(const dt_iop_colorequal_params_t *const a, const dt_iop_colorequal_params_t *const b)
static int * _curve_nodes_count(dt_iop_colorequal_params_t *p, const dt_iop_colorequal_ring_t ring, const dt_iop_colorequal_channel_t channel)
#define DT_IOP_COLOREQUAL_GRAPH_RES
static gboolean _curve_fields_equal(const dt_iop_colorequal_params_t *const a, const dt_iop_colorequal_params_t *const b)
dt_iop_colorequal_channel_t
@ DT_IOP_COLOREQUAL_BRIGHTNESS
@ DT_IOP_COLOREQUAL_SATURATION
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static void _work_rgb_to_display_rgb(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_aligned_pixel_t work_rgb, dt_aligned_pixel_t display_rgb)
static void _init_default_curves(dt_iop_colorequal_params_t *p)
#define DT_IOP_COLOREQUAL_GRAPH_GRADIENTS
#define DT_IOP_COLOREQUAL_MIN_X_DISTANCE
#define DT_IOP_COLOREQUAL_SCROLL_HUE_STEP_COARSE
static void _pipe_rgb_to_Ych(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_aligned_pixel_t RGB, dt_aligned_pixel_t Ych)
void init_global(dt_iop_module_so_t *module)
__DT_CLONE_TARGETS__ int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ibuf, void *const obuf)
void autoset(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *i)
static size_t _build_viewer_control_nodes(const dt_iop_colorequal_params_t *p, const dt_iop_order_iccprofile_info_t *lut_profile, dt_lut_viewer_control_node_t *control_nodes)
#define DT_IOP_COLOREQUAL_DEFAULT_NODES
static gboolean _refresh_preview_cursor_sample(dt_iop_module_t *self)
int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
int mouse_moved(struct dt_iop_module_t *self, double x, double y, double pressure, int which)
#define DT_IOP_COLOREQUAL_SCROLL_STEP_FINE
static float _channel_value_from_y(const dt_iop_colorequal_channel_t channel, const float y)
#define DT_IOP_COLOREQUAL_SCROLL_STEP
#define DT_IOP_COLOREQUAL_PREVIEW_CURSOR_RADIUS
void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static int _find_selected_node(const dt_iop_module_t *self, const dt_iop_colorequal_ring_t ring, const dt_iop_colorequal_channel_t channel, const float mouse_x, const float mouse_y, const float graph_width, const float graph_height)
static float _channel_y_from_value(const dt_iop_colorequal_channel_t channel, const float value)
dt_iop_colorequal_interpolation_t
@ DT_IOP_COLOREQUAL_PYRAMID
@ DT_IOP_COLOREQUAL_TRILINEAR
@ DT_IOP_COLOREQUAL_TETRAHEDRAL
static void _sample_ring_anchor(const float ring_surface[3][64][3], const float brightness, const float hue_position, const float white, const dt_iop_order_iccprofile_info_t *const profile, dt_aligned_pixel_t RGB)
static dt_iop_colorequal_ring_t _active_ring_from_gui(const dt_iop_colorequal_gui_data_t *g)
void dt_colorrings_profile_rgb_to_dt_ucs_hsb(const dt_aligned_pixel_t RGB, const float white, const dt_iop_order_iccprofile_info_t *profile, dt_aligned_pixel_t HSB)
void dt_colorrings_hsb_to_profile_rgb(const dt_aligned_pixel_t HSB, const float white, const dt_iop_order_iccprofile_info_t *profile, dt_aligned_pixel_t RGB)
float dt_colorrings_curve_periodic_sample(const dt_colorrings_node_t *curve, const int nodes, const float x)
void dt_colorrings_rgb_to_gray_cyl(const float rgb[3], float *L, float *rho, float *theta)
float dt_colorrings_wrap_hue_pi(float hue)
gboolean dt_colorrings_apply_rgb_lut(const dt_aligned_pixel_t input_rgb, const float white_level, const dt_iop_order_iccprofile_info_t *work_profile, const dt_iop_order_iccprofile_info_t *lut_profile, const float *clut, const uint16_t clut_level, dt_pthread_rwlock_t *clut_lock, const dt_lut3d_interpolation_t interpolation, dt_aligned_pixel_t output_rgb)
float dt_colorrings_ring_brightness(const dt_colorrings_ring_t ring)
void dt_colorrings_compute_reference_saturations(const float white, float reference_saturation[DT_COLORRINGS_NUM_RINGS])
float dt_colorrings_wrap_hue_2pi(float hue)
void dt_colorrings_project_to_cube_shell(const dt_aligned_pixel_t axis, dt_aligned_pixel_t RGB)
float dt_colorrings_hue_to_curve_x(const float hue)
void dt_colorrings_hsb_to_display_rgb(const dt_aligned_pixel_t HSB, const float white, const dt_iop_order_iccprofile_info_t *display_profile, dt_aligned_pixel_t RGB)
float dt_colorrings_wrap_pi(float x)
void dt_colorrings_profile_rgb_to_Ych(const dt_aligned_pixel_t RGB, const dt_iop_order_iccprofile_info_t *profile, dt_aligned_pixel_t Ych)
float dt_colorrings_graph_white(void)
void dt_colorrings_brightness_to_axis_rgb(const float brightness, const float white, const dt_iop_order_iccprofile_info_t *profile, dt_aligned_pixel_t RGB)
float dt_colorrings_curve_x_to_hue(const float x)
void dt_colorrings_fill_lut_local_field(float *lut, const int level, const float anchor_L[DT_COLORRINGS_LOCAL_FIELD_RINGS][DT_COLORRINGS_HUE_SAMPLES], const float anchor_rho[DT_COLORRINGS_LOCAL_FIELD_RINGS][DT_COLORRINGS_HUE_SAMPLES], const float anchor_theta[DT_COLORRINGS_LOCAL_FIELD_RINGS][DT_COLORRINGS_HUE_SAMPLES], const float delta_L[DT_COLORRINGS_LOCAL_FIELD_RINGS][DT_COLORRINGS_HUE_SAMPLES], const float chroma_scale[DT_COLORRINGS_LOCAL_FIELD_RINGS][DT_COLORRINGS_HUE_SAMPLES], const float delta_theta[DT_COLORRINGS_LOCAL_FIELD_RINGS][DT_COLORRINGS_HUE_SAMPLES], const float inv_sigma_L, const float inv_sigma_rho, const float inv_sigma_theta, const float rho0)
@ DT_COLORSPACE_HLG_REC2020
const dt_colormatrix_t dt_aligned_pixel_t out
static dt_aligned_pixel_t RGB
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_lut3d_apply(const float *const in, float *const out, const size_t pixel_nb, const float *const clut, const uint16_t level, const float normalization, const dt_lut3d_interpolation_t interpolation)
Apply one interpolation model over a packed RGB CLUT.
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
void dt_control_queue_redraw_center()
request redraw of center window. This redraws the center view within a gdk critical section to preven...
void dt_control_hinter_message(const struct dt_control_t *s, const char *message)
void dt_control_queue_cursor_by_name(const char *curs_str)
Queue a GTK named cursor for the next cursor commit.
#define dt_control_set_cursor_visible(visible)
void dt_print(dt_debug_thread_t thread, const char *msg,...)
#define dt_free_align(ptr)
static void * dt_calloc_align(size_t size)
#define dt_gui_freeze_begin()
#define dt_gui_freeze_end()
static float * dt_alloc_align_float(size_t pixels)
void void void gboolean dt_gui_widgets_suppressed(void)
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
#define __DT_CLONE_TARGETS__
#define __OMP_PARALLEL_FOR__(...)
static const dt_aligned_pixel_simd_t value
static double dt_get_wtime(void)
static gboolean dt_modifier_is(const GdkModifierType state, const GdkModifierType desired_modifier_mask)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
#define dt_dev_add_history_item(dev, module, enable, redraw)
const dt_dev_pixelpipe_iop_t * dt_dev_pixelpipe_get_module_piece(const dt_dev_pixelpipe_t *pipe, const dt_iop_module_t *module)
void dt_dev_pixelpipe_cache_wait_cleanup(dt_dev_pixelpipe_cache_wait_t *wait, const char *reason)
Cancel one pending GUI cache wait request and clear its runtime state.
const dt_dev_pixelpipe_iop_t * dt_dev_pixelpipe_get_prev_enabled_piece(const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
void dt_dev_pixelpipe_cache_wait_set_owner(dt_dev_pixelpipe_cache_wait_t *wait, const char *owner_tag, gpointer owner_object)
Attach debug ownership metadata to one cache wait request.
gboolean dt_dev_pixelpipe_cache_peek_gui(dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, void **data, dt_pixel_cache_entry_t **cache_entry, dt_dev_pixelpipe_cache_wait_t *wait, dt_dev_pixelpipe_cache_ready_callback_t restart, gpointer restart_data)
#define dt_dev_pixelpipe_update_history_preview(dev)
void dt_dev_coordinates_preview_abs_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
float dt_dev_get_overlay_scale(dt_develop_t *dev)
Get the overlay scale factor in GUI logical coordinates.
void dt_dev_coordinates_image_norm_to_preview_abs(dt_develop_t *dev, float *points, size_t num_points)
gboolean dt_dev_rescale_roi(dt_develop_t *dev, cairo_t *cr, int32_t width, int32_t height)
Scale the ROI to fit within given width/height, centered.
void dt_dev_coordinates_widget_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
Coordinate conversion helpers between widget, normalized image, and absolute image spaces.
static void dt_draw_grid(cairo_t *cr, const int num, const int left, const int top, const int right, const int bottom)
static void dt_draw_curve_destroy(dt_draw_curve_t *c)
static void dt_draw_curve_calc_values_V2(dt_draw_curve_t *c, const float min, const float max, const int res, float *x, float *y, const gboolean periodic)
static void dt_draw_curve_set_point(dt_draw_curve_t *c, const int num, const float x, const float y)
static int dt_draw_curve_add_point(dt_draw_curve_t *c, const float x, const float y)
static dt_draw_curve_t * dt_draw_curve_new(const float min, const float max, unsigned int type)
static void weight(const float *c1, const float *c2, const float sharpen, dt_aligned_pixel_t weight)
const dt_collection_filter_flag_t colors[6]
GtkWidget * dt_ui_resizable_drawing_area(GtkWidget *area, char *config_str, int default_height, int min_height)
Make a self-drawing widget (typically a GtkDrawingArea graph or scope) vertically resizable.
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)
void dt_gui_throttle_cancel(gpointer source)
void dt_gui_throttle_queue(gpointer source, dt_gui_throttle_callback_t callback, gpointer user_data)
static void dt_iop_image_copy_by_size(float *const __restrict__ out, const float *const __restrict__ in, const size_t width, const size_t height, const size_t ch)
void dt_iop_throttled_history_update(gpointer data)
void dt_iop_default_init(dt_iop_module_t *module)
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
@ DT_REQUEST_COLORPICK_OFF
@ IOP_FLAGS_INCLUDE_IN_STYLES
@ IOP_FLAGS_SUPPORTS_BLENDING
#define IOP_GUI_ALLOC(module)
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
static float kernel(const float *x, const float *y)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_output_profile_info(const struct dt_dev_pixelpipe_t *pipe)
dt_iop_order_iccprofile_info_t * dt_ioppr_add_profile_info_to_list(struct dt_develop_t *dev, const dt_colorspaces_color_profile_type_t profile_type, const char *profile_filename, const int intent)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_current_profile_info(dt_iop_module_t *module, const struct dt_dev_pixelpipe_t *pipe)
void dt_ioppr_transform_image_colorspace_rgb(const float *const restrict image_in, float *const restrict image_out, const int width, const int height, const dt_iop_order_iccprofile_info_t *const profile_info_from, const dt_iop_order_iccprofile_info_t *const profile_info_to, const char *message)
int dt_ioppr_transform_image_colorspace_rgb_cl(const int devid, cl_mem dev_img_in, cl_mem dev_img_out, const int width, const int height, const dt_iop_order_iccprofile_info_t *const profile_info_from, const dt_iop_order_iccprofile_info_t *const profile_info_to, const char *message)
static float mix(const float a, const float b, const float t)
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
@ DT_LUT3D_INTERP_PYRAMID
@ DT_LUT3D_INTERP_TETRAHEDRAL
@ DT_LUT3D_INTERP_TRILINEAR
void dt_lut_viewer_destroy(dt_lut_viewer_t **viewer)
void dt_lut_viewer_queue_draw(dt_lut_viewer_t *viewer)
void dt_lut_viewer_set_control_nodes(dt_lut_viewer_t *viewer, const dt_lut_viewer_control_node_t *control_nodes, size_t control_node_count)
GtkWidget * dt_lut_viewer_get_widget(dt_lut_viewer_t *viewer)
dt_lut_viewer_t * dt_lut_viewer_new(dt_gui_module_t *module)
void dt_lut_viewer_set_lut(dt_lut_viewer_t *viewer, const float *clut, uint16_t level, dt_pthread_rwlock_t *clut_lock, const dt_iop_order_iccprofile_info_t *lut_profile, const dt_iop_order_iccprofile_info_t *display_profile)
float dt_aligned_pixel_t[4]
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
int dt_opencl_create_kernel(const int prog, const char *name)
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
void dt_opencl_free_kernel(const int kernel)
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
void dt_opencl_release_mem_object(cl_mem mem)
void dt_dev_pixelpipe_cache_ref_count_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Increase/Decrease the reference count on the cache line as to prevent LRU item removal....
void dt_dev_pixelpipe_cache_rdlock_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the read lock on the entry.
Pixelpipe cache for storing intermediate results in the pixelpipe.
#define DT_PIXELPIPE_CACHE_HASH_INVALID
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
@ DT_SIGNAL_CACHELINE_READY
This signal is raised when one cacheline write lock is released. 1 : uint64_t cacheline hash no retur...
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
struct _GtkWidget GtkWidget
const float uint32_t state[4]
unsigned __int64 uint64_t
struct dt_dev_pixelpipe_cache_t * pixelpipe_cache
struct dt_gui_gtk_t * gui
struct dt_control_signal_t * signals
struct dt_bauhaus_t * bauhaus
struct dt_develop_t * develop
struct dt_control_t * control
dt_iop_buffer_dsc_t dsc_out
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
struct dt_dev_pixelpipe_t * preview_pipe
struct dt_develop_t::@17 roi
dt_iop_buffer_type_t datatype
dt_lut3d_interpolation_t interpolation
dt_iop_colorequal_params_t built_params
dt_iop_order_iccprofile_info_t * work_profile
dt_iop_order_iccprofile_info_t * lut_profile
float reference_saturation[3]
int kernel_lut3d_tetrahedral
int kernel_lut3d_trilinear
dt_iop_colorequal_data_t viewer_lut
dt_lut_viewer_control_node_t viewer_control_nodes[(3 *64)]
gboolean preview_signal_connected
dt_iop_colorequal_params_t gui_params
dt_aligned_pixel_t cursor_input_display
dt_aligned_pixel_t cursor_output_display
GtkNotebook * channel_notebook[3]
uint64_t pending_preview_hash
size_t viewer_control_node_count
GtkWidget * interpolation
GtkNotebook * ring_notebook
dt_dev_pixelpipe_cache_wait_t preview_wait
cairo_surface_t * background_surface[3][3]
gboolean viewer_lut_dirty
GtkDrawingArea * area[3][3]
dt_draw_curve_t * curve[3][3]
const dt_iop_order_iccprofile_info_t * cached_display_profile[3][3]
float reference_saturation[3]
dt_iop_colorequal_params_t viewer_lut_params
float cached_reference_saturation[3][3]
gboolean curve_cache_valid
gboolean viewer_lut_valid
gboolean cursor_sample_valid
dt_iop_colorequal_params_t cached_curve_params
GtkWidget * module_picker
GtkWidget * neutral_protection
dt_iop_colorequal_node_t curve[3][3][20]
dt_iop_colorequal_interpolation_t interpolation
int curve_num_nodes[3][3]
dt_iop_global_data_t * data
dt_dev_request_colorpick_flags_t request_color_pick
GtkDarktableToggleButton * off
dt_iop_params_t * default_params
struct dt_develop_t * dev
dt_iop_gui_data_t * gui_data
dt_iop_global_data_t * global_data
dt_aligned_pixel_t picked_color_min
dt_aligned_pixel_t picked_color_max
dt_aligned_pixel_t picked_color
Region of interest passed through the pixelpipe.