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)
205 return _(
"color equalizer");
210 return _(
"color zones");
216 self, _(
"stretch RGB colors around the achromatic axis from editable dt UCS hue nodes"), _(
"creative"),
217 _(
"linear, RGB, display-referred"), _(
"linear, RGB"), _(
"linear, RGB, display-referred"));
245 return (y - 0.5f) * 2.f *
M_PI_F;
249 return CLAMP(y * 2.f, 0.f, 2.f);
258 return CLAMP(
value / (2.f *
M_PI_F) + 0.5f, 0.f, 1.f);
262 return CLAMP(
value * 0.5f, 0.f, 1.f);
273 return _(
"highlights");
276 return _(
"midtones");
284 return p->curve[ring][channel];
291 return p->curve[ring][channel];
297 return &
p->curve_num_nodes[ring][channel];
304 return p->curve_num_nodes[ring][channel];
330 && !memcmp(a->
curve, b->curve,
sizeof(a->
curve));
342 const float distance = fabsf(x0 - x1);
343 return fminf(distance, 1.f - distance);
362 const int page = (
g &&
g->ring_notebook) ? gtk_notebook_get_current_page(
g->ring_notebook) : -1;
371 const int page = (
g &&
g->channel_notebook[ring]) ? gtk_notebook_get_current_page(
g->channel_notebook[ring]) : -1;
378 g->cursor_sample_valid =
FALSE;
380 memset(
g->cursor_input_display, 0,
sizeof(
g->cursor_input_display));
381 memset(
g->cursor_output_display, 0,
sizeof(
g->cursor_output_display));
386 float *curve_x,
float *curve_y,
float *offset_normalized)
406 *offset_normalized = CLAMP(
value /
M_PI_F, -1.f, 1.f);
411 *offset_normalized = CLAMP(
value - 1.f, -1.f, 1.f);
421 RGB[0] = CLAMP(
RGB[0], 0.f, 1.f);
422 RGB[1] = CLAMP(
RGB[1], 0.f, 1.f);
423 RGB[2] = CLAMP(
RGB[2], 0.f, 1.f);
441 float in[4] = { work_rgb[0], work_rgb[1], work_rgb[2], 0.f };
442 float out[4] = { work_rgb[0], work_rgb[1], work_rgb[2], 0.f };
444 display_rgb[0] =
out[0];
445 display_rgb[1] =
out[1];
446 display_rgb[2] =
out[2];
453 for(
int c = 0; c < 3; c++)
RGB[c] = low[c] * (1.f -
mix) + high[c] *
mix;
464 const float mix = hue - floorf(hue);
466 for(
int c = 0; c < 3; c++)
467 RGB[c] = ring_surface[ring][hue0][c] * (1.f -
mix) + ring_surface[ring][hue1][c] *
mix;
478 const float brightness,
const float hue_position,
const float white,
489 while(segment < DT_IOP_COLOREQUAL_NUM_RINGS + 1 && brightness > anchor_positions[segment + 1]) segment++;
491 const float low_position = anchor_positions[segment];
492 const float high_position = anchor_positions[segment + 1];
494 = (high_position > low_position) ? (brightness - low_position) / (high_position - low_position) : 0.f;
545 const size_t clut_size
561 chroma_scale[ring][hue_sample] = 1.f;
572 const float reference_saturation =
d->reference_saturation[ring];
599 CLAMP(brightness * bright_gain, 0.f, 1.f), 0.f };
608 float Lp, rhop, thetap;
627 const float requested_scale = sat_gain;
628 const float projected_scale = (rhop > 1e-6f) ? (rhoa / rhop) : 1.f;
629 const float effective_scale
630 = (requested_scale <= 1.f) ? requested_scale : fminf(requested_scale, projected_scale);
632 anchor_L[ring][hue_sample] = Lp;
633 anchor_rho[ring][hue_sample] = rhop;
634 anchor_theta[ring][hue_sample] = thetap;
635 delta_L[ring][hue_sample] = La - Lp;
636 chroma_scale[ring][hue_sample] = effective_scale;
664 const float sigma_L = fmaxf(
p->sigma_L * 0.01f, 1e-6f);
665 const float sigma_rho = fmaxf(
p->sigma_rho, 1e-6f);
666 const float sigma_theta = fmaxf(
p->sigma_theta, 1e-6f);
667 const float neutral_protection = fmaxf(
p->neutral_protection, 0.f);
669 delta_L, chroma_scale, delta_theta, 1.f / sigma_L, 1.f / sigma_rho,
670 1.f / sigma_theta, neutral_protection * sigma_rho);
701 const float saturation = reference_saturation[ring];
728 CLAMP(brightness * bright_gain, 0.f, 1.f), 0.f };
737 for(
int c = 0; c < 3; c++)
739 control_nodes[count].
input_rgb[c] = before_rgb[c];
740 control_nodes[count].
output_rgb[c] = after_rgb[c];
764 d->lut_profile = NULL;
765 d->work_profile = NULL;
781 d->white_level = exp2f(
p->white_level);
799 d->white_level = 1.f;
800 d->lut_profile = NULL;
801 memset(
d->reference_saturation, 0,
sizeof(
d->reference_saturation));
802 d->work_profile = NULL;
816 cl_mem dev_in, cl_mem dev_out)
822 const int devid = pipe->
devid;
824 const float white_level = fmaxf(
d->white_level, 1e-6f);
825 const float normalize = 1.f / white_level;
826 const float denormalize = white_level;
827 const float black = 0.f;
828 cl_mem clut_cl = NULL;
829 cl_int err = CL_SUCCESS;
843 if(err != CL_SUCCESS)
goto cleanup;
846 d->lut_profile,
"colorequal work to HLG Rec2020"))
848 err = CL_INVALID_OPERATION;
858 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
869 if(err != CL_SUCCESS)
goto cleanup;
872 d->work_profile,
"colorequal HLG Rec2020 to work"))
874 err = CL_INVALID_OPERATION;
889 return err == CL_SUCCESS;
895 const void *
const ibuf,
void *
const obuf)
909 const float white_level = fmaxf(
d->white_level, 1e-6f);
913 const float *
const in = (
const float *)ibuf +
k *
ch;
914 float *
const out = (
float *)obuf +
k *
ch;
915 out[0] = in[0] / white_level;
916 out[1] = in[1] / white_level;
917 out[2] = in[2] / white_level;
918 if(
ch > 3)
out[3] = in[3];
922 d->lut_profile,
"colorequal work to HLG Rec2020");
930 "colorequal HLG Rec2020 to work");
934 float *
const out = (
float *)obuf +
k *
ch;
935 out[0] *= white_level;
936 out[1] *= white_level;
937 out[2] *= white_level;
964 if(!
g->viewer_lut_dirty &&
g->viewer_lut_valid &&
g->viewer_lut_generation == cache_generation)
return;
977 g->viewer_lut_dirty =
FALSE;
978 g->viewer_lut_valid =
FALSE;
979 g->viewer_lut_generation = 0;
980 g->viewer_control_node_count = 0;
1000 g->viewer_lut.lut_profile, display_profile);
1003 g->viewer_lut_dirty =
FALSE;
1004 g->viewer_lut_valid =
TRUE;
1005 g->viewer_lut_generation = cache_generation;
1010 dt_print(
DT_DEBUG_PERF,
"[colorequal] gui LUT cache sync level=%u total=%.3fms\n",
g->viewer_lut.clut_level,
1026 if(!
g->curve[ring][
ch] ||
g->curve_nodes[ring][
ch] != nodes ||
g->curve[ring][
ch]->c.m_numAnchors != nodes)
1030 g->curve_nodes[ring][
ch] = nodes;
1043 memcpy(&
g->cached_curve_params,
p,
sizeof(*
p));
1044 g->curve_cache_valid =
TRUE;
1052 const float ring_brightness,
const float reference_saturation,
1061 HSB[1] = reference_saturation;
1062 HSB[2] = ring_brightness;
1066 HSB[1] = reference_saturation;
1073 HSB[2] = ring_brightness;
1080 const float graph_height,
const float white,
const float reference_saturation,
1104 cairo_pattern_t *gradient = cairo_pattern_create_linear(0.0, 0.0, graph_width, 0.0);
1114 cairo_set_source(cr, gradient);
1116 cairo_pattern_destroy(gradient);
1133 GtkAllocation allocation;
1134 gtk_widget_get_allocation(widget, &allocation);
1135 GtkStyleContext *context = gtk_widget_get_style_context(widget);
1138 const float graph_width = allocation.width - 2.f * inset;
1152 const float background_saturation
1154 : CLAMP(
g->reference_saturation[ring] * 1.35f, 0.f, 1.f);
1157 cairo_t *cr = cairo_create(cst);
1159 if(!
g->background_surface[ring][channel] ||
g->cached_width[ring][channel] != allocation.width
1160 ||
g->cached_height[ring][channel] != allocation.height
1161 || fabsf(
g->cached_white[ring][channel] - white) > 1e-6f
1162 || fabsf(
g->cached_reference_saturation[ring][channel] - background_saturation) > 1e-6f
1163 ||
g->cached_display_profile[ring][channel] != display_profile)
1165 if(
g->background_surface[ring][channel]) cairo_surface_destroy(
g->background_surface[ring][channel]);
1166 g->background_surface[ring][channel]
1168 cairo_t *background_cr = cairo_create(
g->background_surface[ring][channel]);
1170 gtk_render_background(context, background_cr, 0, 0, allocation.width, allocation.height);
1171 cairo_translate(background_cr, inset, inset);
1172 _draw_graph_background(background_cr, channel, ring, graph_width, graph_height, white, background_saturation,
1175 cairo_rectangle(background_cr, 0.f, 0.f, graph_width, graph_height);
1176 cairo_clip(background_cr);
1180 dt_draw_grid(background_cr, 8, 0, 0, graph_width, graph_height);
1184 cairo_move_to(background_cr, 0.f, 0.5f * graph_height);
1185 cairo_line_to(background_cr, graph_width, 0.5f * graph_height);
1186 cairo_stroke(background_cr);
1188 cairo_reset_clip(background_cr);
1189 cairo_translate(background_cr, 0.f, graph_height);
1190 cairo_pattern_t *axis = cairo_pattern_create_linear(0.0, 0.0, graph_width, 0.0);
1199 white, display_profile,
RGB);
1200 cairo_pattern_add_color_stop_rgba(axis,
x,
RGB[0],
RGB[1],
RGB[2], 1.0);
1204 cairo_set_source(background_cr, axis);
1205 cairo_fill(background_cr);
1206 cairo_pattern_destroy(axis);
1207 cairo_destroy(background_cr);
1209 g->cached_width[ring][channel] = allocation.width;
1210 g->cached_height[ring][channel] = allocation.height;
1211 g->cached_white[ring][channel] = white;
1212 g->cached_reference_saturation[ring][channel] = background_saturation;
1213 g->cached_display_profile[ring][channel] = display_profile;
1216 cairo_set_source_surface(cr,
g->background_surface[ring][channel], 0, 0);
1219 cairo_translate(cr, inset, inset);
1226 cairo_move_to(cr, picker_x, 0.f);
1233 if(
g->cursor_sample_valid && ring == active_ring && channel == active_channel)
1237 cairo_set_source_rgba(cr, 0.f, 0.f, 0.f, 0.75f);
1238 cairo_move_to(cr, cursor_x, 0.f);
1243 cairo_set_source_rgba(cr,
g->cursor_output_display[0],
g->cursor_output_display[1],
g->cursor_output_display[2],
1245 cairo_move_to(cr, cursor_x, 0.f);
1250 cairo_rectangle(cr, 0.f, 0.f, graph_width, graph_height);
1259 const float y = (1.f -
g->draw_ys[ring][channel][
k]) * graph_height;
1262 cairo_move_to(cr,
x, y);
1264 cairo_line_to(cr,
x, y);
1272 for(
int k = 0;
k < nodes;
k++)
1274 const float x = curve[
k].
x * graph_width;
1275 const float y = (1.f - curve[
k].
y) * graph_height;
1279 cairo_stroke_preserve(cr);
1284 if(
g->cursor_sample_valid && ring == active_ring && channel == active_channel)
1286 float curve_x = 0.f;
1287 float curve_y = 0.f;
1288 float offset_normalized = 0.f;
1291 const float marker_x = curve_x * graph_width;
1292 const float marker_y = (1.f - curve_y) * graph_height;
1298 cairo_set_source_rgba(cr, 0.f, 0.f, 0.f, 0.4f);
1299 cairo_arc(cr, marker_x, marker_y, intensity_radius, 0.f, 2.f *
M_PI_F);
1302 if(fabsf(offset_normalized) > 1e-4f)
1305 cairo_set_source_rgba(cr,
g->cursor_output_display[0],
g->cursor_output_display[1],
1306 g->cursor_output_display[2], 0.95);
1307 if(offset_normalized > 0.f)
1308 cairo_arc(cr, marker_x, marker_y, intensity_radius, -
M_PI_F / 2.f,
1309 -
M_PI_F / 2.f + 2.f *
M_PI_F * fabsf(offset_normalized));
1311 cairo_arc_negative(cr, marker_x, marker_y, intensity_radius, -
M_PI_F / 2.f,
1312 -
M_PI_F / 2.f - 2.f *
M_PI_F * fabsf(offset_normalized));
1316 cairo_arc(cr, marker_x, marker_y, outer_radius, 0.f, 2.f *
M_PI_F);
1317 cairo_set_source_rgba(cr,
g->cursor_output_display[0],
g->cursor_output_display[1],
1318 g->cursor_output_display[2], 0.95);
1319 cairo_fill_preserve(cr);
1320 cairo_set_source_rgba(cr, 0.f, 0.f, 0.f, 0.9f);
1323 cairo_arc(cr, marker_x, marker_y, inner_radius, 0.f, 2.f *
M_PI_F);
1324 cairo_set_source_rgba(cr,
g->cursor_input_display[0],
g->cursor_input_display[1],
g->cursor_input_display[2],
1326 cairo_fill_preserve(cr);
1327 cairo_set_source_rgba(cr, 1.f, 1.f, 1.f, 0.8f);
1332 cairo_reset_clip(cr);
1335 cairo_set_source_surface(crf, cst, 0, 0);
1337 cairo_surface_destroy(cst);
1350 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1364 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1370 const float graph_width,
const float graph_height)
1379 for(
int k = 0;
k < nodes;
k++)
1381 const float node_x = curve[
k].
x * graph_width;
1382 const float node_y = (1.f - curve[
k].
y) * graph_height;
1383 const float dx = mouse_x - node_x;
1384 const float dy = mouse_y - node_y;
1385 const float distance = dx * dx + dy * dy;
1405 for(
int k = 1;
k < *nodes;
k++)
1413 if(selected == -1) selected = *nodes;
1419 for(
int k = *nodes;
k > selected;
k--)
1421 curve[
k].
x = curve[
k - 1].
x;
1422 curve[
k].
y = curve[
k - 1].
y;
1425 curve[selected].
x =
x;
1426 curve[selected].
y = y;
1440 float new_x = CLAMP(
x, 0.f, 0.999f);
1441 const float new_y = CLAMP(y, 0.f, 1.f);
1448 else if(node == nodes - 1)
1459 curve[node].
x = new_x;
1460 curve[node].
y = new_y;
1472 GtkAllocation allocation;
1473 gtk_widget_get_allocation(widget, &allocation);
1476 const float graph_height
1481 if(
g->dragging[ring][channel] &&
g->selected[ring][channel] >= 0)
1484 1.f - mouse_y / graph_height))
1487 g->curve_cache_valid =
FALSE;
1488 g->viewer_lut_dirty =
TRUE;
1489 if(
g->cursor_valid &&
g->has_focus)
1495 gtk_widget_queue_draw(widget);
1501 g->selected[ring][channel]
1503 gtk_widget_queue_draw(widget);
1522 GtkAllocation allocation;
1523 gtk_widget_get_allocation(widget, &allocation);
1525 const float graph_height
1530 if(event->button == 1 && event->type == GDK_2BUTTON_PRESS)
1532 *nodes = default_nodes;
1533 for(
int k = 0;
k < default_nodes;
k++) curve[
k] = default_curve[
k];
1535 g->selected[ring][channel] = -1;
1537 g->curve_cache_valid =
FALSE;
1538 g->viewer_lut_dirty =
TRUE;
1539 if(
g->cursor_valid &&
g->has_focus)
1545 gtk_widget_queue_draw(widget);
1553 const int selected =
_add_node(curve, nodes, mouse_x, y);
1557 g->selected[ring][channel] = selected;
1559 g->curve_cache_valid =
FALSE;
1560 g->viewer_lut_dirty =
TRUE;
1561 if(
g->cursor_valid &&
g->has_focus)
1567 gtk_widget_queue_draw(widget);
1573 if(event->button == 1)
1576 (1.f - mouse_y) * graph_height, graph_width, graph_height);
1577 g->dragging[ring][channel] = (
g->selected[ring][channel] >= 0);
1581 if(event->button == 3 &&
g->selected[ring][channel] >= 0 && *nodes > 2)
1583 for(
int k =
g->selected[ring][channel];
k < *nodes - 1;
k++) curve[
k] = curve[
k + 1];
1586 g->selected[ring][channel] = -1;
1588 g->curve_cache_valid =
FALSE;
1589 g->viewer_lut_dirty =
TRUE;
1590 if(
g->cursor_valid &&
g->has_focus)
1596 gtk_widget_queue_draw(widget);
1605 if(event->button == 1)
1613 const gboolean was_dragging =
g->dragging[ring][channel];
1614 g->dragging[ring][channel] =
FALSE;
1639 const int source_ring = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(notebook),
"colorequal-ring"));
1642 dt_conf_set_int(
"plugins/darkroom/colorequal/gui_channel_page", (
int)page_num);
1648 if(ring != source_ring) gtk_notebook_set_current_page(
g->channel_notebook[ring], (
int)page_num);
1652 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1667 dt_conf_set_int(
"plugins/darkroom/colorequal/gui_ring_page", (
int)page_num);
1668 GtkWidget *page_widget = gtk_notebook_get_nth_page(
1669 g->channel_notebook[page_num], gtk_notebook_get_current_page(
g->channel_notebook[page_num]));
1673 g_object_get_data(G_OBJECT(page_widget),
"colorequal-channel"));
1678 if(
g->cursor_valid &&
g->has_focus)
1682 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1691 if(!
g->has_focus)
return 0;
1704 if(wd < 1 || ht < 1)
return 0;
1706 float point[2] = { (float)
x, (
float)y };
1710 const int cursor_x = (int)
point[0];
1711 const int cursor_y = (int)
point[1];
1712 if(cursor_x >= 0 && cursor_x < wd && cursor_y >= 0 && cursor_y < ht)
1714 g->cursor_valid =
TRUE;
1715 g->cursor_pos_x = cursor_x;
1716 g->cursor_pos_y = cursor_y;
1730 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1732 return g->cursor_valid ? 1 : 0;
1744 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1753 if(!
g->has_focus || which != 3 || !
g->cursor_valid || !
g->cursor_sample_valid
1759 if(self->
off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->
off), 1);
1772 const int selected =
_add_node(curve, nodes, curve_x, curve_y);
1773 if(selected < 0)
return 1;
1775 g->selected[ring][channel] = selected;
1777 g->curve_cache_valid =
FALSE;
1778 g->viewer_lut_dirty =
TRUE;
1780 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1794 if(self->
off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->
off), 1);
1802 if(nodes < 1)
return 1;
1804 const float direction = up ? 1.f : -1.f;
1816 for(
int k = 0;
k < nodes;
k++)
1819 const float weight = expf(-(distance * distance) / sigma2);
1839 g->curve_cache_valid =
FALSE;
1840 g->viewer_lut_dirty =
TRUE;
1842 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1849 int32_t pointerx, int32_t pointery)
1864 float curve_x = 0.f;
1865 float curve_y = 0.f;
1866 float offset_normalized = 0.f;
1867 if(!
_cursor_curve_state(&
g->gui_params, ring, channel,
g->cursor_hue, &curve_x, &curve_y, &offset_normalized))
1873 const float pointer_x =
g->cursor_pos_x;
1874 const float pointer_y =
g->cursor_pos_y;
1876 const float inner_radius = outer_radius * 0.55f;
1877 const float intensity_radius = outer_radius * 1.55f;
1878 const float crosshair_gap = outer_radius * 0.25f;
1879 const float crosshair_extent = intensity_radius +
DT_PIXEL_APPLY_DPI(5.f) / zoom_scale;
1882 cairo_set_source_rgba(cr, 0.f, 0.f, 0.f, 0.35f);
1883 cairo_arc(cr, pointer_x, pointer_y, intensity_radius, 0.f, 2.f *
M_PI_F);
1886 if(fabsf(offset_normalized) > 1e-4f)
1889 cairo_set_source_rgba(cr,
g->cursor_output_display[0],
g->cursor_output_display[1],
g->cursor_output_display[2],
1891 if(offset_normalized > 0.f)
1892 cairo_arc(cr, pointer_x, pointer_y, intensity_radius, -
M_PI_F / 2.f,
1893 -
M_PI_F / 2.f + 2.f *
M_PI_F * fabsf(offset_normalized));
1895 cairo_arc_negative(cr, pointer_x, pointer_y, intensity_radius, -
M_PI_F / 2.f,
1896 -
M_PI_F / 2.f - 2.f *
M_PI_F * fabsf(offset_normalized));
1901 cairo_set_source_rgba(cr, 1.f, 1.f, 1.f, 0.6f);
1902 cairo_move_to(cr, pointer_x - crosshair_extent, pointer_y);
1903 cairo_line_to(cr, pointer_x - outer_radius - crosshair_gap, pointer_y);
1904 cairo_move_to(cr, pointer_x + outer_radius + crosshair_gap, pointer_y);
1905 cairo_line_to(cr, pointer_x + crosshair_extent, pointer_y);
1906 cairo_move_to(cr, pointer_x, pointer_y - crosshair_extent);
1907 cairo_line_to(cr, pointer_x, pointer_y - outer_radius - crosshair_gap);
1908 cairo_move_to(cr, pointer_x, pointer_y + outer_radius + crosshair_gap);
1909 cairo_line_to(cr, pointer_x, pointer_y + crosshair_extent);
1912 cairo_arc(cr, pointer_x, pointer_y, outer_radius, 0.f, 2.f *
M_PI_F);
1913 cairo_set_source_rgba(cr,
g->cursor_output_display[0],
g->cursor_output_display[1],
g->cursor_output_display[2],
1915 cairo_fill_preserve(cr);
1916 cairo_set_source_rgba(cr, 0.f, 0.f, 0.f, 0.9f);
1919 cairo_arc(cr, pointer_x, pointer_y, inner_radius, 0.f, 2.f *
M_PI_F);
1920 cairo_set_source_rgba(cr,
g->cursor_input_display[0],
g->cursor_input_display[1],
g->cursor_input_display[2], 0.95);
1921 cairo_fill_preserve(cr);
1922 cairo_set_source_rgba(cr, 1.f, 1.f, 1.f, 0.8f);
1947 if(!widget || !gtk_widget_get_window(widget))
return;
1963 if(
g->cursor_valid && self->
enabled)
1967 _(
"scroll over image to adjust the selected color graph\n"
1968 "right-click to add a node at the sampled hue"));
1980 if(!self->
enabled || !
g->cursor_valid)
2015 const float point_preview[2] = { (float)
g->cursor_pos_x, (
float)
g->cursor_pos_y };
2016 float point_image[2] = { point_preview[0], point_preview[1] };
2019 const float scale_x = (previous_piece->
buf_out.
width > 0)
2025 const float sample_x
2026 = point_image[0] * (float)previous_piece->
buf_out.
width * scale_x - (
float)previous_piece->
roi_out.
x;
2027 const float sample_y
2028 = point_image[1] * (float)previous_piece->
buf_out.
height * scale_y - (
float)previous_piece->
roi_out.
y;
2029 const int xi = CLAMP((
int)lroundf(sample_x), 0, previous_piece->
roi_out.
width - 1);
2030 const int yi = CLAMP((
int)lroundf(sample_y), 0, previous_piece->
roi_out.
height - 1);
2033 const float *
const input_rgbf
2035 input_rgb[0] = input_rgbf[0];
2036 input_rgb[1] = input_rgbf[1];
2037 input_rgb[2] = input_rgbf[2];
2047 g->viewer_lut.clut,
g->viewer_lut.clut_level, &gd->
lock,
2051 const float white_level = fmaxf(exp2f(
g->gui_params.white_level), 1e-6f);
2052 projected_rgb[0] = input_rgb[0] / white_level;
2053 projected_rgb[1] = input_rgb[1] / white_level;
2054 projected_rgb[2] = input_rgb[2] / white_level;
2056 const float neutral = CLAMP((projected_rgb[0] + projected_rgb[1] + projected_rgb[2]) / 3.f, 0.f, 1.f);
2062 if(!isfinite(HSB[0]))
2071 g->cursor_sample_valid =
TRUE;
2083 if(brightness <= 0.15f)
2085 g_snprintf(text,
size,
"%d%% %s", 100, _(
"shadows"));
2087 else if(brightness < 0.45f)
2089 const float t = (brightness - 0.15f) / (0.45f - 0.15f);
2090 const int shadows = CLAMP((
int)lroundf((1.f -
t) * 100.f), 0, 100);
2091 g_snprintf(text,
size,
"%d%% %s, %d%% %s", shadows, _(
"shadows"), 100 - shadows, _(
"midtones"));
2093 else if(brightness < 0.75f)
2095 const float t = (brightness - 0.45f) / (0.75f - 0.45f);
2096 const int midtones = CLAMP((
int)lroundf((1.f -
t) * 100.f), 0, 100);
2097 g_snprintf(text,
size,
"%d%% %s, %d%% %s", midtones, _(
"midtones"), 100 - midtones, _(
"highlights"));
2101 g_snprintf(text,
size,
"%d%% %s", 100, _(
"highlights"));
2110 const dt_iop_module_t *sampled_module = piece && piece->module ? piece->module : self;
2112 if(picker ==
g->white_level)
2118 p->white_level = log2f(max_Ych[0]);
2119 g->gui_params.white_level =
p->white_level;
2125 else if(picker ==
g->module_picker)
2130 gtk_label_set_text(GTK_LABEL(
g->picker_info), _(
"no sample"));
2133 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][
ch]));
2140 char text[128] = { 0 };
2141 const float white_level = fmaxf(exp2f(
g->gui_params.white_level), 1e-6f);
2161 g->picker_valid =
TRUE;
2163 g->picker_brightness = CLAMP(HSB[2], 0.f, 1.f);
2165 gtk_label_set_text(GTK_LABEL(
g->picker_info), text);
2169 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][
ch]));
2182 const float *
const restrict in = (
const float *)
i;
2186 for(
size_t k = 0;
k < (size_t)roi_out->
width * roi_out->
height * 4;
k += 4)
2190 if(isfinite(Ych[0]))
2191 max_Y = fmaxf(max_Y, Ych[0]);
2194 p->white_level = log2f(fmaxf(max_Y, 1e-6f));
2196 g->gui_params.white_level =
p->white_level;
2207 g->curve_cache_valid =
FALSE;
2210 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][
ch]));
2237 if(!
g->preview_signal_connected)
2241 g->preview_signal_connected =
TRUE;
2247 else if(
g->preview_signal_connected)
2250 g->preview_signal_connected =
FALSE;
2269 g->curve[ring][
ch] = NULL;
2270 if(
g->background_surface[ring][
ch]) cairo_surface_destroy(
g->background_surface[ring][
ch]);
2271 g->background_surface[ring][
ch] = NULL;
2274 g->viewer_lut.clut = NULL;
2277 if(
g->preview_signal_connected)
2280 g->preview_signal_connected =
FALSE;
2285 dt_conf_set_int(
"plugins/darkroom/colorequal/gui_ring_page", current_primary);
2287 gtk_notebook_get_current_page(
g->channel_notebook[0]));
2295 g->curve_cache_valid =
FALSE;
2296 g->viewer_lut_dirty =
TRUE;
2297 g->viewer_lut_valid =
FALSE;
2298 g->viewer_lut_generation = 0;
2299 g->preview_signal_connected =
FALSE;
2306 gtk_box_pack_start(GTK_BOX(self->
widget), ring_tabs_box,
TRUE,
TRUE, 0);
2308 g->ring_notebook = GTK_NOTEBOOK(gtk_notebook_new());
2309 gtk_widget_set_name(GTK_WIDGET(
g->ring_notebook),
"colorequal-ring-tabs");
2310 gtk_notebook_set_show_border(
g->ring_notebook,
FALSE);
2312 gtk_box_pack_start(GTK_BOX(ring_tabs_box), GTK_WIDGET(
g->ring_notebook),
TRUE,
TRUE, 0);
2323 gtk_notebook_append_page(
g->ring_notebook, ring_page, ring_label);
2324 gtk_container_child_set(GTK_CONTAINER(
g->ring_notebook), ring_page,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
2326 g->channel_notebook[ring] = GTK_NOTEBOOK(gtk_notebook_new());
2327 g_object_set_data(G_OBJECT(
g->channel_notebook[ring]),
"colorequal-ring", GINT_TO_POINTER(ring));
2330 gtk_box_pack_start(GTK_BOX(ring_page), GTK_WIDGET(
g->channel_notebook[ring]),
TRUE,
TRUE, 0);
2336 g_object_set_data(G_OBJECT(channel_page),
"colorequal-channel", GINT_TO_POINTER(
ch));
2337 g->area[ring][
ch] = GTK_DRAWING_AREA(gtk_drawing_area_new());
2338 gtk_widget_set_hexpand(GTK_WIDGET(
g->area[ring][
ch]),
TRUE);
2339 gtk_widget_add_events(GTK_WIDGET(
g->area[ring][
ch]),
2340 GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
2341 g_object_set_data(G_OBJECT(
g->area[ring][
ch]),
"colorequal-ring", GINT_TO_POINTER(ring));
2342 g_object_set_data(G_OBJECT(
g->area[ring][
ch]),
"colorequal-channel", GINT_TO_POINTER(
ch));
2343 g_signal_connect(G_OBJECT(
g->area[ring][
ch]),
"draw", G_CALLBACK(
_draw_curve), self);
2344 g_signal_connect(G_OBJECT(
g->area[ring][
ch]),
"motion-notify-event",
2348 g_signal_connect(G_OBJECT(
g->area[ring][
ch]),
"button-release-event",
2351 gtk_box_pack_start(GTK_BOX(channel_page),
2353 "plugins/darkroom/colorequal/graphheight", 220, 100),
2355 gtk_notebook_append_page(
g->channel_notebook[ring], channel_page, gtk_label_new(channel_labels[order]));
2356 gtk_container_child_set(GTK_CONTAINER(
g->channel_notebook[ring]), channel_page,
"tab-expand",
TRUE,
2357 "tab-fill",
TRUE, NULL);
2361 GtkWidget *options_label = gtk_label_new(_(
"options"));
2364 gtk_notebook_append_page(
g->ring_notebook, options_page, options_label);
2365 gtk_container_child_set(GTK_CONTAINER(
g->ring_notebook), options_page,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
2368 self->
widget = options_page;
2389 gtk_widget_set_tooltip_text(
g->interpolation, _(
"select the interpolation method"));
2391 self->
widget = module_root;
2394 gtk_box_pack_start(GTK_BOX(ring_tabs_box), picker_box,
FALSE,
FALSE, 0);
2397 gtk_box_pack_start(GTK_BOX(picker_box),
g->module_picker,
FALSE,
FALSE, 0);
2399 g->picker_info = gtk_label_new(_(
"no sample"));
2400 gtk_widget_set_hexpand(
g->picker_info,
TRUE);
2401 gtk_widget_set_halign(
g->picker_info, GTK_ALIGN_START);
2402 gtk_label_set_xalign(GTK_LABEL(
g->picker_info), 0.f);
2403 gtk_box_pack_start(GTK_BOX(picker_box),
g->picker_info,
TRUE,
TRUE, 0);
2405 const int active_ring =
dt_conf_get_int(
"plugins/darkroom/colorequal/gui_ring_page");
2406 const int active_channel =
dt_conf_get_int(
"plugins/darkroom/colorequal/gui_channel_page");
2411 gtk_notebook_set_current_page(
g->ring_notebook, current_ring_page);
2413 gtk_notebook_set_current_page(
g->channel_notebook[ring], current_channel_page);
2419 g->viewer_lut.clut = NULL;
2420 g->viewer_lut.clut_level = 0;
2421 memset(
g->viewer_lut.reference_saturation, 0,
sizeof(
g->viewer_lut.reference_saturation));
2422 g->viewer_lut.lut_profile = NULL;
2423 g->viewer_lut.work_profile = NULL;
2424 g->viewer_control_node_count = 0;
2429 gtk_widget_show_all(self->
widget);
2452 const int lut_program = 28;
2453 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)
#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)
#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 _cacheline_ready_callback(gpointer instance, const guint64 hash, gpointer user_data)
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)
static float * dt_alloc_align_float(size_t pixels)
#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)
#define dt_pthread_rwlock_destroy
#define dt_pthread_rwlock_wrlock
#define dt_pthread_rwlock_t
#define dt_pthread_rwlock_init
#define dt_pthread_rwlock_unlock
#define dt_pthread_rwlock_rdlock
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_order_iccprofile_info_t * work_profile
dt_iop_order_iccprofile_info_t * lut_profile
float reference_saturation[3]
dt_iop_colorequal_data_t cache
int kernel_lut3d_tetrahedral
dt_iop_colorequal_params_t params
uint64_t cache_generation
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]
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
uint64_t viewer_lut_generation
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.