71#define DT_IOP_COLOREQUAL_NUM_CHANNELS 3
72#define DT_IOP_COLOREQUAL_NUM_RINGS 3
73#define DT_IOP_COLOREQUAL_MAXNODES 20
74#define DT_IOP_COLOREQUAL_DEFAULT_NODES 8
75#define DT_IOP_COLOREQUAL_GRAPH_RES 360
76#define DT_IOP_COLOREQUAL_GRAPH_GRADIENTS 48
77#define DT_IOP_COLOREQUAL_HUE_SAMPLES 64
78#define DT_IOP_COLOREQUAL_VIEWER_CONTROL_NODES (DT_IOP_COLOREQUAL_NUM_RINGS * DT_IOP_COLOREQUAL_HUE_SAMPLES)
79#define DT_IOP_COLOREQUAL_AXIAL_SAMPLES 64
80#define DT_IOP_COLOREQUAL_CLUT_LEVEL 64
81#define DT_IOP_COLOREQUAL_LOCAL_FIELD_RINGS (DT_IOP_COLOREQUAL_NUM_RINGS + 1)
82#define DT_IOP_COLOREQUAL_MIN_X_DISTANCE 0.01f
83#define DT_IOP_COLOREQUAL_PREVIEW_CURSOR_RADIUS DT_PIXEL_APPLY_DPI(14.f)
84#define DT_IOP_COLOREQUAL_GRAPH_INSET DT_PIXEL_APPLY_DPI(4)
85#define DT_IOP_COLOREQUAL_AXIS_HEIGHT DT_PIXEL_APPLY_DPI(14)
86#define DT_IOP_COLOREQUAL_SCROLL_SIGMA 2.f * M_PI_F / 128.f
87#define DT_IOP_COLOREQUAL_SCROLL_STEP 0.05f
88#define DT_IOP_COLOREQUAL_SCROLL_STEP_FINE 0.02f
89#define DT_IOP_COLOREQUAL_SCROLL_STEP_COARSE 0.10f
90#define DT_IOP_COLOREQUAL_SCROLL_HUE_STEP (5.f * M_PI_F / 180.f)
91#define DT_IOP_COLOREQUAL_SCROLL_HUE_STEP_FINE (1.f * M_PI_F / 180.f)
92#define DT_IOP_COLOREQUAL_SCROLL_HUE_STEP_COARSE (10.f * M_PI_F / 180.f)
221 return _(
"color equalizer");
226 return _(
"color zones");
232 self, _(
"stretch RGB colors around the achromatic axis from editable dt UCS hue nodes"), _(
"creative"),
233 _(
"linear, RGB, display-referred"), _(
"linear, RGB"), _(
"linear, RGB, display-referred"));
261 return (y - 0.5f) * 2.f *
M_PI_F;
265 return CLAMP(y * 2.f, 0.f, 2.f);
274 return CLAMP(
value / (2.f *
M_PI_F) + 0.5f, 0.f, 1.f);
278 return CLAMP(
value * 0.5f, 0.f, 1.f);
289 return _(
"highlights");
292 return _(
"midtones");
300 return p->curve[ring][channel];
307 return p->curve[ring][channel];
313 return &
p->curve_num_nodes[ring][channel];
320 return p->curve_num_nodes[ring][channel];
347 return !memcmp(a->curve_num_nodes, b->curve_num_nodes,
sizeof(a->curve_num_nodes))
348 && !memcmp(a->curve, b->curve,
sizeof(a->curve));
356 return _curve_fields_equal(a, b) && a->sigma_L == b->sigma_L && a->sigma_rho == b->sigma_rho
357 && a->sigma_theta == b->sigma_theta && a->neutral_protection == b->neutral_protection;
362 const float distance = fabsf(x0 - x1);
363 return fminf(distance, 1.f - distance);
382 const int page = (
g &&
g->ring_notebook) ? gtk_notebook_get_current_page(
g->ring_notebook) : -1;
391 const int page = (
g &&
g->channel_notebook[ring]) ? gtk_notebook_get_current_page(
g->channel_notebook[ring]) : -1;
398 g->cursor_sample_valid =
FALSE;
400 memset(
g->cursor_input_display, 0,
sizeof(
g->cursor_input_display));
401 memset(
g->cursor_output_display, 0,
sizeof(
g->cursor_output_display));
406 float *curve_x,
float *curve_y,
float *offset_normalized)
426 *offset_normalized = CLAMP(
value /
M_PI_F, -1.f, 1.f);
431 *offset_normalized = CLAMP(
value - 1.f, -1.f, 1.f);
441 RGB[0] = CLAMP(
RGB[0], 0.f, 1.f);
442 RGB[1] = CLAMP(
RGB[1], 0.f, 1.f);
443 RGB[2] = CLAMP(
RGB[2], 0.f, 1.f);
461 float in[4] = { work_rgb[0], work_rgb[1], work_rgb[2], 0.f };
462 float out[4] = { work_rgb[0], work_rgb[1], work_rgb[2], 0.f };
464 display_rgb[0] =
out[0];
465 display_rgb[1] =
out[1];
466 display_rgb[2] =
out[2];
473 for(
int c = 0; c < 3; c++)
RGB[c] = low[c] * (1.f -
mix) + high[c] *
mix;
484 const float mix = hue - floorf(hue);
486 for(
int c = 0; c < 3; c++)
487 RGB[c] = ring_surface[ring][hue0][c] * (1.f -
mix) + ring_surface[ring][hue1][c] *
mix;
498 const float brightness,
const float hue_position,
const float white,
509 while(segment < DT_IOP_COLOREQUAL_NUM_RINGS + 1 && brightness > anchor_positions[segment + 1]) segment++;
511 const float low_position = anchor_positions[segment];
512 const float high_position = anchor_positions[segment + 1];
514 = (high_position > low_position) ? (brightness - low_position) / (high_position - low_position) : 0.f;
565 const size_t clut_size
581 chroma_scale[ring][hue_sample] = 1.f;
592 const float reference_saturation =
d->reference_saturation[ring];
619 CLAMP(brightness * bright_gain, 0.f, 1.f), 0.f };
628 float Lp, rhop, thetap;
647 const float requested_scale = sat_gain;
648 const float projected_scale = (rhop > 1e-6f) ? (rhoa / rhop) : 1.f;
649 const float effective_scale
650 = (requested_scale <= 1.f) ? requested_scale : fminf(requested_scale, projected_scale);
652 anchor_L[ring][hue_sample] = Lp;
653 anchor_rho[ring][hue_sample] = rhop;
654 anchor_theta[ring][hue_sample] = thetap;
655 delta_L[ring][hue_sample] = La - Lp;
656 chroma_scale[ring][hue_sample] = effective_scale;
684 const float sigma_L = fmaxf(
p->sigma_L * 0.01f, 1e-6f);
685 const float sigma_rho = fmaxf(
p->sigma_rho, 1e-6f);
686 const float sigma_theta = fmaxf(
p->sigma_theta, 1e-6f);
687 const float neutral_protection = fmaxf(
p->neutral_protection, 0.f);
689 delta_L, chroma_scale, delta_theta, 1.f / sigma_L, 1.f / sigma_rho,
690 1.f / sigma_theta, neutral_protection * sigma_rho);
721 const float saturation = reference_saturation[ring];
748 CLAMP(brightness * bright_gain, 0.f, 1.f), 0.f };
757 for(
int c = 0; c < 3; c++)
759 control_nodes[count].
input_rgb[c] = before_rgb[c];
760 control_nodes[count].
output_rgb[c] = after_rgb[c];
805 d->lut_profile = NULL;
806 d->work_profile = NULL;
817 d->built_params = *
p;
818 d->clut_valid =
TRUE;
821 d->white_level = exp2f(
p->white_level);
840 d->white_level = 1.f;
841 d->lut_profile = NULL;
842 memset(
d->reference_saturation, 0,
sizeof(
d->reference_saturation));
843 d->work_profile = NULL;
860 cl_mem dev_in, cl_mem dev_out)
866 const int devid = pipe->
devid;
868 const float white_level = fmaxf(
d->white_level, 1e-6f);
869 const float normalize = 1.f / white_level;
870 const float denormalize = white_level;
871 const float black = 0.f;
872 cl_mem clut_cl = NULL;
873 cl_int err = CL_SUCCESS;
887 if(err != CL_SUCCESS)
goto cleanup;
890 d->lut_profile,
"colorequal work to HLG Rec2020"))
892 err = CL_INVALID_OPERATION;
900 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
911 if(err != CL_SUCCESS)
goto cleanup;
914 d->work_profile,
"colorequal HLG Rec2020 to work"))
916 err = CL_INVALID_OPERATION;
931 return err == CL_SUCCESS;
937 const void *
const ibuf,
void *
const obuf)
950 const float white_level = fmaxf(
d->white_level, 1e-6f);
954 const float *
const in = (
const float *)ibuf +
k *
ch;
955 float *
const out = (
float *)obuf +
k *
ch;
956 out[0] = in[0] / white_level;
957 out[1] = in[1] / white_level;
958 out[2] = in[2] / white_level;
959 if(
ch > 3)
out[3] = in[3];
963 d->lut_profile,
"colorequal work to HLG Rec2020");
969 "colorequal HLG Rec2020 to work");
973 float *
const out = (
float *)obuf +
k *
ch;
974 out[0] *= white_level;
975 out[1] *= white_level;
976 out[2] *= white_level;
998 if(!
g->viewer_lut_dirty &&
g->viewer_lut_valid &&
_lut_fields_equal(&
g->viewer_lut_params,
p))
return;
1011 g->viewer_lut_dirty =
FALSE;
1012 g->viewer_lut_valid =
FALSE;
1013 g->viewer_control_node_count = 0;
1018 g->viewer_lut_params = *
p;
1022 g->viewer_lut.lut_profile, display_profile);
1024 g->viewer_lut_dirty =
FALSE;
1025 g->viewer_lut_valid =
TRUE;
1030 dt_print(
DT_DEBUG_PERF,
"[colorequal] gui LUT cache sync level=%u total=%.3fms\n",
g->viewer_lut.clut_level,
1058 if(!
g->curve[ring][
ch] ||
g->curve_nodes[ring][
ch] != nodes ||
g->curve[ring][
ch]->c.m_numAnchors != nodes)
1062 g->curve_nodes[ring][
ch] = nodes;
1075 memcpy(&
g->cached_curve_params,
p,
sizeof(*
p));
1076 g->curve_cache_valid =
TRUE;
1084 const float ring_brightness,
const float reference_saturation,
1093 HSB[1] = reference_saturation;
1094 HSB[2] = ring_brightness;
1098 HSB[1] = reference_saturation;
1105 HSB[2] = ring_brightness;
1112 const float graph_height,
const float white,
const float reference_saturation,
1136 cairo_pattern_t *gradient = cairo_pattern_create_linear(0.0, 0.0, graph_width, 0.0);
1146 cairo_set_source(cr, gradient);
1148 cairo_pattern_destroy(gradient);
1165 GtkAllocation allocation;
1166 gtk_widget_get_allocation(widget, &allocation);
1167 GtkStyleContext *context = gtk_widget_get_style_context(widget);
1170 const float graph_width = allocation.width - 2.f * inset;
1184 const float background_saturation
1186 : CLAMP(
g->reference_saturation[ring] * 1.35f, 0.f, 1.f);
1189 cairo_t *cr = cairo_create(cst);
1191 if(!
g->background_surface[ring][channel] ||
g->cached_width[ring][channel] != allocation.width
1192 ||
g->cached_height[ring][channel] != allocation.height
1193 || fabsf(
g->cached_white[ring][channel] - white) > 1e-6f
1194 || fabsf(
g->cached_reference_saturation[ring][channel] - background_saturation) > 1e-6f
1195 ||
g->cached_display_profile[ring][channel] != display_profile)
1197 if(
g->background_surface[ring][channel]) cairo_surface_destroy(
g->background_surface[ring][channel]);
1198 g->background_surface[ring][channel]
1200 cairo_t *background_cr = cairo_create(
g->background_surface[ring][channel]);
1202 gtk_render_background(context, background_cr, 0, 0, allocation.width, allocation.height);
1203 cairo_translate(background_cr, inset, inset);
1204 _draw_graph_background(background_cr, channel, ring, graph_width, graph_height, white, background_saturation,
1207 cairo_rectangle(background_cr, 0.f, 0.f, graph_width, graph_height);
1208 cairo_clip(background_cr);
1212 dt_draw_grid(background_cr, 8, 0, 0, graph_width, graph_height);
1216 cairo_move_to(background_cr, 0.f, 0.5f * graph_height);
1217 cairo_line_to(background_cr, graph_width, 0.5f * graph_height);
1218 cairo_stroke(background_cr);
1220 cairo_reset_clip(background_cr);
1221 cairo_translate(background_cr, 0.f, graph_height);
1222 cairo_pattern_t *axis = cairo_pattern_create_linear(0.0, 0.0, graph_width, 0.0);
1231 white, display_profile,
RGB);
1232 cairo_pattern_add_color_stop_rgba(axis,
x,
RGB[0],
RGB[1],
RGB[2], 1.0);
1236 cairo_set_source(background_cr, axis);
1237 cairo_fill(background_cr);
1238 cairo_pattern_destroy(axis);
1239 cairo_destroy(background_cr);
1241 g->cached_width[ring][channel] = allocation.width;
1242 g->cached_height[ring][channel] = allocation.height;
1243 g->cached_white[ring][channel] = white;
1244 g->cached_reference_saturation[ring][channel] = background_saturation;
1245 g->cached_display_profile[ring][channel] = display_profile;
1248 cairo_set_source_surface(cr,
g->background_surface[ring][channel], 0, 0);
1251 cairo_translate(cr, inset, inset);
1258 cairo_move_to(cr, picker_x, 0.f);
1265 if(
g->cursor_sample_valid && ring == active_ring && channel == active_channel)
1269 cairo_set_source_rgba(cr, 0.f, 0.f, 0.f, 0.75f);
1270 cairo_move_to(cr, cursor_x, 0.f);
1275 cairo_set_source_rgba(cr,
g->cursor_output_display[0],
g->cursor_output_display[1],
g->cursor_output_display[2],
1277 cairo_move_to(cr, cursor_x, 0.f);
1282 cairo_rectangle(cr, 0.f, 0.f, graph_width, graph_height);
1291 const float y = (1.f -
g->draw_ys[ring][channel][
k]) * graph_height;
1294 cairo_move_to(cr,
x, y);
1296 cairo_line_to(cr,
x, y);
1304 for(
int k = 0;
k < nodes;
k++)
1306 const float x = curve[
k].
x * graph_width;
1307 const float y = (1.f - curve[
k].
y) * graph_height;
1311 cairo_stroke_preserve(cr);
1316 if(
g->cursor_sample_valid && ring == active_ring && channel == active_channel)
1318 float curve_x = 0.f;
1319 float curve_y = 0.f;
1320 float offset_normalized = 0.f;
1323 const float marker_x = curve_x * graph_width;
1324 const float marker_y = (1.f - curve_y) * graph_height;
1330 cairo_set_source_rgba(cr, 0.f, 0.f, 0.f, 0.4f);
1331 cairo_arc(cr, marker_x, marker_y, intensity_radius, 0.f, 2.f *
M_PI_F);
1334 if(fabsf(offset_normalized) > 1e-4f)
1337 cairo_set_source_rgba(cr,
g->cursor_output_display[0],
g->cursor_output_display[1],
1338 g->cursor_output_display[2], 0.95);
1339 if(offset_normalized > 0.f)
1340 cairo_arc(cr, marker_x, marker_y, intensity_radius, -
M_PI_F / 2.f,
1341 -
M_PI_F / 2.f + 2.f *
M_PI_F * fabsf(offset_normalized));
1343 cairo_arc_negative(cr, marker_x, marker_y, intensity_radius, -
M_PI_F / 2.f,
1344 -
M_PI_F / 2.f - 2.f *
M_PI_F * fabsf(offset_normalized));
1348 cairo_arc(cr, marker_x, marker_y, outer_radius, 0.f, 2.f *
M_PI_F);
1349 cairo_set_source_rgba(cr,
g->cursor_output_display[0],
g->cursor_output_display[1],
1350 g->cursor_output_display[2], 0.95);
1351 cairo_fill_preserve(cr);
1352 cairo_set_source_rgba(cr, 0.f, 0.f, 0.f, 0.9f);
1355 cairo_arc(cr, marker_x, marker_y, inner_radius, 0.f, 2.f *
M_PI_F);
1356 cairo_set_source_rgba(cr,
g->cursor_input_display[0],
g->cursor_input_display[1],
g->cursor_input_display[2],
1358 cairo_fill_preserve(cr);
1359 cairo_set_source_rgba(cr, 1.f, 1.f, 1.f, 0.8f);
1364 cairo_reset_clip(cr);
1367 cairo_set_source_surface(crf, cst, 0, 0);
1369 cairo_surface_destroy(cst);
1374 const guint64 producer_node_key, gpointer user_data)
1377 (
void)producer_node_key;
1384 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1398 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1404 const float graph_width,
const float graph_height)
1413 for(
int k = 0;
k < nodes;
k++)
1415 const float node_x = curve[
k].
x * graph_width;
1416 const float node_y = (1.f - curve[
k].
y) * graph_height;
1417 const float dx = mouse_x - node_x;
1418 const float dy = mouse_y - node_y;
1419 const float distance = dx * dx + dy * dy;
1439 for(
int k = 1;
k < *nodes;
k++)
1455 curve[
k].
x = curve[
k - 1].
x;
1456 curve[
k].
y = curve[
k - 1].
y;
1474 float new_x = CLAMP(
x, 0.f, 0.999f);
1475 const float new_y = CLAMP(y, 0.f, 1.f);
1482 else if(node == nodes - 1)
1493 curve[node].
x = new_x;
1494 curve[node].
y = new_y;
1506 GtkAllocation allocation;
1507 gtk_widget_get_allocation(widget, &allocation);
1510 const float graph_height
1515 if(
g->dragging[ring][channel] &&
g->selected[ring][channel] >= 0)
1518 1.f - mouse_y / graph_height))
1521 g->curve_cache_valid =
FALSE;
1522 g->viewer_lut_dirty =
TRUE;
1523 if(
g->cursor_valid &&
g->has_focus)
1530 gtk_widget_queue_draw(widget);
1536 g->selected[ring][channel]
1538 gtk_widget_queue_draw(widget);
1557 GtkAllocation allocation;
1558 gtk_widget_get_allocation(widget, &allocation);
1560 const float graph_height
1565 if(event->button == 1 && event->type == GDK_2BUTTON_PRESS)
1567 *nodes = default_nodes;
1568 for(
int k = 0;
k < default_nodes;
k++) curve[
k] = default_curve[
k];
1570 g->selected[ring][channel] = -1;
1572 g->curve_cache_valid =
FALSE;
1573 g->viewer_lut_dirty =
TRUE;
1574 if(
g->cursor_valid &&
g->has_focus)
1581 gtk_widget_queue_draw(widget);
1595 g->curve_cache_valid =
FALSE;
1596 g->viewer_lut_dirty =
TRUE;
1597 if(
g->cursor_valid &&
g->has_focus)
1604 gtk_widget_queue_draw(widget);
1610 if(event->button == 1)
1613 (1.f - mouse_y) * graph_height, graph_width, graph_height);
1614 g->dragging[ring][channel] = (
g->selected[ring][channel] >= 0);
1618 if(event->button == 3 &&
g->selected[ring][channel] >= 0 && *nodes > 2)
1620 for(
int k =
g->selected[ring][channel];
k < *nodes - 1;
k++) curve[
k] = curve[
k + 1];
1623 g->selected[ring][channel] = -1;
1625 g->curve_cache_valid =
FALSE;
1626 g->viewer_lut_dirty =
TRUE;
1627 if(
g->cursor_valid &&
g->has_focus)
1634 gtk_widget_queue_draw(widget);
1643 if(event->button == 1)
1651 const gboolean was_dragging =
g->dragging[ring][channel];
1652 g->dragging[ring][channel] =
FALSE;
1679 const int source_ring = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(
notebook),
"colorequal-ring"));
1682 dt_conf_set_int(
"plugins/darkroom/colorequal/gui_channel_page", (
int)page_num);
1688 if(ring != source_ring) gtk_notebook_set_current_page(
g->channel_notebook[ring], (
int)page_num);
1692 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1707 dt_conf_set_int(
"plugins/darkroom/colorequal/gui_ring_page", (
int)page_num);
1708 GtkWidget *page_widget = gtk_notebook_get_nth_page(
1709 g->channel_notebook[page_num], gtk_notebook_get_current_page(
g->channel_notebook[page_num]));
1713 g_object_get_data(G_OBJECT(page_widget),
"colorequal-channel"));
1718 if(
g->cursor_valid &&
g->has_focus)
1722 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1731 if(!
g->has_focus)
return 0;
1744 if(wd < 1 || ht < 1)
return 0;
1746 float point[2] = { (float)
x, (
float)y };
1750 const int cursor_x = (int)
point[0];
1751 const int cursor_y = (int)
point[1];
1752 if(cursor_x >= 0 && cursor_x < wd && cursor_y >= 0 && cursor_y < ht)
1754 g->cursor_valid =
TRUE;
1755 g->cursor_pos_x = cursor_x;
1756 g->cursor_pos_y = cursor_y;
1770 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1772 return g->cursor_valid ? 1 : 0;
1789 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1798 if(!
g->has_focus || which != 3 || !
g->cursor_valid || !
g->cursor_sample_valid
1804 if(self->
gui->
off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->
gui->
off), 1);
1822 g->curve_cache_valid =
FALSE;
1823 g->viewer_lut_dirty =
TRUE;
1825 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1844 if(self->
gui->
off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->
gui->
off), 1);
1852 if(nodes < 1)
return 1;
1854 const float direction = up ? 1.f : -1.f;
1866 for(
int k = 0;
k < nodes;
k++)
1869 const float weight = expf(-(distance * distance) / sigma2);
1889 g->curve_cache_valid =
FALSE;
1890 g->viewer_lut_dirty =
TRUE;
1892 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][channel]));
1900 int32_t pointerx, int32_t pointery)
1908 if(!
g->cursor_sample_valid)
1915 float curve_x = 0.f;
1916 float curve_y = 0.f;
1917 float offset_normalized = 0.f;
1918 if(!
_cursor_curve_state(&
g->gui_params, ring, channel,
g->cursor_hue, &curve_x, &curve_y, &offset_normalized))
1924 const float pointer_x =
g->cursor_pos_x;
1925 const float pointer_y =
g->cursor_pos_y;
1927 const float inner_radius = outer_radius * 0.55f;
1928 const float intensity_radius = outer_radius * 1.55f;
1929 const float crosshair_gap = outer_radius * 0.25f;
1930 const float crosshair_extent = intensity_radius +
DT_PIXEL_APPLY_DPI(5.f) / zoom_scale;
1933 cairo_set_source_rgba(cr, 0.f, 0.f, 0.f, 0.35f);
1934 cairo_arc(cr, pointer_x, pointer_y, intensity_radius, 0.f, 2.f *
M_PI_F);
1937 if(fabsf(offset_normalized) > 1e-4f)
1940 cairo_set_source_rgba(cr,
g->cursor_output_display[0],
g->cursor_output_display[1],
g->cursor_output_display[2],
1942 if(offset_normalized > 0.f)
1943 cairo_arc(cr, pointer_x, pointer_y, intensity_radius, -
M_PI_F / 2.f,
1944 -
M_PI_F / 2.f + 2.f *
M_PI_F * fabsf(offset_normalized));
1946 cairo_arc_negative(cr, pointer_x, pointer_y, intensity_radius, -
M_PI_F / 2.f,
1947 -
M_PI_F / 2.f - 2.f *
M_PI_F * fabsf(offset_normalized));
1952 cairo_set_source_rgba(cr, 1.f, 1.f, 1.f, 0.6f);
1953 cairo_move_to(cr, pointer_x - crosshair_extent, pointer_y);
1954 cairo_line_to(cr, pointer_x - outer_radius - crosshair_gap, pointer_y);
1955 cairo_move_to(cr, pointer_x + outer_radius + crosshair_gap, pointer_y);
1956 cairo_line_to(cr, pointer_x + crosshair_extent, pointer_y);
1957 cairo_move_to(cr, pointer_x, pointer_y - crosshair_extent);
1958 cairo_line_to(cr, pointer_x, pointer_y - outer_radius - crosshair_gap);
1959 cairo_move_to(cr, pointer_x, pointer_y + outer_radius + crosshair_gap);
1960 cairo_line_to(cr, pointer_x, pointer_y + crosshair_extent);
1963 cairo_arc(cr, pointer_x, pointer_y, outer_radius, 0.f, 2.f *
M_PI_F);
1964 cairo_set_source_rgba(cr,
g->cursor_output_display[0],
g->cursor_output_display[1],
g->cursor_output_display[2],
1966 cairo_fill_preserve(cr);
1967 cairo_set_source_rgba(cr, 0.f, 0.f, 0.f, 0.9f);
1970 cairo_arc(cr, pointer_x, pointer_y, inner_radius, 0.f, 2.f *
M_PI_F);
1971 cairo_set_source_rgba(cr,
g->cursor_input_display[0],
g->cursor_input_display[1],
g->cursor_input_display[2], 0.95);
1972 cairo_fill_preserve(cr);
1973 cairo_set_source_rgba(cr, 1.f, 1.f, 1.f, 0.8f);
1998 if(!widget || !gtk_widget_get_window(widget))
return;
2015 if(
g->cursor_valid && self->
enabled)
2019 _(
"scroll over image to adjust the selected color graph\n"
2020 "right-click to add a node at the sampled hue"));
2028 if(!self->
enabled || !
g->cursor_valid)
2064 const float point_preview[2] = { (float)
g->cursor_pos_x, (
float)
g->cursor_pos_y };
2065 float point_image[2] = { point_preview[0], point_preview[1] };
2068 const float scale_x = (previous_piece->
buf_out.
width > 0)
2074 const float sample_x
2075 = point_image[0] * (float)previous_piece->
buf_out.
width * scale_x - (
float)previous_piece->
roi_out.
x;
2076 const float sample_y
2077 = point_image[1] * (float)previous_piece->
buf_out.
height * scale_y - (
float)previous_piece->
roi_out.
y;
2078 const int xi = CLAMP((
int)lroundf(sample_x), 0, previous_piece->
roi_out.
width - 1);
2079 const int yi = CLAMP((
int)lroundf(sample_y), 0, previous_piece->
roi_out.
height - 1);
2082 const float *
const input_rgbf
2084 input_rgb[0] = input_rgbf[0];
2085 input_rgb[1] = input_rgbf[1];
2086 input_rgb[2] = input_rgbf[2];
2096 g->viewer_lut.clut,
g->viewer_lut.clut_level, NULL,
2100 const float white_level = fmaxf(exp2f(
g->gui_params.white_level), 1e-6f);
2101 projected_rgb[0] = input_rgb[0] / white_level;
2102 projected_rgb[1] = input_rgb[1] / white_level;
2103 projected_rgb[2] = input_rgb[2] / white_level;
2105 const float neutral = CLAMP((projected_rgb[0] + projected_rgb[1] + projected_rgb[2]) / 3.f, 0.f, 1.f);
2111 if(!isfinite(HSB[0]))
2120 g->cursor_sample_valid =
TRUE;
2132 if(brightness <= 0.15f)
2134 g_snprintf(text,
size,
"%d%% %s", 100, _(
"shadows"));
2136 else if(brightness < 0.45f)
2138 const float t = (brightness - 0.15f) / (0.45f - 0.15f);
2139 const int shadows = CLAMP((
int)lroundf((1.f -
t) * 100.f), 0, 100);
2140 g_snprintf(text,
size,
"%d%% %s, %d%% %s", shadows, _(
"shadows"), 100 - shadows, _(
"midtones"));
2142 else if(brightness < 0.75f)
2144 const float t = (brightness - 0.45f) / (0.75f - 0.45f);
2145 const int midtones = CLAMP((
int)lroundf((1.f -
t) * 100.f), 0, 100);
2146 g_snprintf(text,
size,
"%d%% %s, %d%% %s", midtones, _(
"midtones"), 100 - midtones, _(
"highlights"));
2150 g_snprintf(text,
size,
"%d%% %s", 100, _(
"highlights"));
2159 const dt_iop_module_t *sampled_module = piece && piece->module ? piece->module : self;
2161 if(picker ==
g->white_level)
2167 p->white_level = log2f(max_Ych[0]);
2168 g->gui_params.white_level =
p->white_level;
2174 else if(picker ==
g->module_picker)
2179 gtk_label_set_text(GTK_LABEL(
g->picker_info), _(
"no sample"));
2182 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][
ch]));
2189 char text[128] = { 0 };
2190 const float white_level = fmaxf(exp2f(
g->gui_params.white_level), 1e-6f);
2210 g->picker_valid =
TRUE;
2212 g->picker_brightness = CLAMP(HSB[2], 0.f, 1.f);
2214 gtk_label_set_text(GTK_LABEL(
g->picker_info), text);
2218 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][
ch]));
2231 const float *
const restrict in = (
const float *)
i;
2235 for(
size_t k = 0;
k < (size_t)roi_out->
width * roi_out->
height * 4;
k += 4)
2239 if(isfinite(Ych[0]))
2240 max_Y = fmaxf(max_Y, Ych[0]);
2243 p->white_level = log2f(fmaxf(max_Y, 1e-6f));
2245 g->gui_params.white_level =
p->white_level;
2256 g->curve_cache_valid =
FALSE;
2259 gtk_widget_queue_draw(GTK_WIDGET(
g->area[ring][
ch]));
2291 if(!
g->preview_signal_connected)
2295 g->preview_signal_connected =
TRUE;
2301 else if(
g->preview_signal_connected)
2304 g->preview_signal_connected =
FALSE;
2325 g->curve[ring][
ch] = NULL;
2326 if(
g->background_surface[ring][
ch]) cairo_surface_destroy(
g->background_surface[ring][
ch]);
2327 g->background_surface[ring][
ch] = NULL;
2331 g->viewer_lut.clut = NULL;
2334 if(
g->preview_signal_connected)
2337 g->preview_signal_connected =
FALSE;
2342 dt_conf_set_int(
"plugins/darkroom/colorequal/gui_ring_page", current_primary);
2344 gtk_notebook_get_current_page(
g->channel_notebook[0]));
2352 g->curve_cache_valid =
FALSE;
2353 g->viewer_lut_dirty =
TRUE;
2354 g->viewer_lut_valid =
FALSE;
2355 g->preview_signal_connected =
FALSE;
2364 g->ring_notebook = GTK_NOTEBOOK(gtk_notebook_new());
2365 gtk_widget_set_name(GTK_WIDGET(
g->ring_notebook),
"colorequal-ring-tabs");
2366 gtk_notebook_set_show_border(
g->ring_notebook,
FALSE);
2368 gtk_box_pack_start(GTK_BOX(ring_tabs_box), GTK_WIDGET(
g->ring_notebook),
TRUE,
TRUE, 0);
2379 gtk_notebook_append_page(
g->ring_notebook, ring_page, ring_label);
2380 gtk_container_child_set(GTK_CONTAINER(
g->ring_notebook), ring_page,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
2382 g->channel_notebook[ring] = GTK_NOTEBOOK(gtk_notebook_new());
2383 g_object_set_data(G_OBJECT(
g->channel_notebook[ring]),
"colorequal-ring", GINT_TO_POINTER(ring));
2386 gtk_box_pack_start(GTK_BOX(ring_page), GTK_WIDGET(
g->channel_notebook[ring]),
TRUE,
TRUE, 0);
2392 g_object_set_data(G_OBJECT(channel_page),
"colorequal-channel", GINT_TO_POINTER(
ch));
2393 g->area[ring][
ch] = GTK_DRAWING_AREA(gtk_drawing_area_new());
2394 gtk_widget_set_hexpand(GTK_WIDGET(
g->area[ring][
ch]),
TRUE);
2395 gtk_widget_add_events(GTK_WIDGET(
g->area[ring][
ch]),
2396 GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
2397 g_object_set_data(G_OBJECT(
g->area[ring][
ch]),
"colorequal-ring", GINT_TO_POINTER(ring));
2398 g_object_set_data(G_OBJECT(
g->area[ring][
ch]),
"colorequal-channel", GINT_TO_POINTER(
ch));
2399 g_signal_connect(G_OBJECT(
g->area[ring][
ch]),
"draw", G_CALLBACK(
_draw_curve), self);
2400 g_signal_connect(G_OBJECT(
g->area[ring][
ch]),
"motion-notify-event",
2404 g_signal_connect(G_OBJECT(
g->area[ring][
ch]),
"button-release-event",
2407 gtk_box_pack_start(GTK_BOX(channel_page),
2409 "plugins/darkroom/colorequal/graphheight", 220, 100),
2411 gtk_notebook_append_page(
g->channel_notebook[ring], channel_page, gtk_label_new(channel_labels[order]));
2412 gtk_container_child_set(GTK_CONTAINER(
g->channel_notebook[ring]), channel_page,
"tab-expand",
TRUE,
2413 "tab-fill",
TRUE, NULL);
2417 GtkWidget *options_label = gtk_label_new(_(
"options"));
2420 gtk_notebook_append_page(
g->ring_notebook, options_page, options_label);
2421 gtk_container_child_set(GTK_CONTAINER(
g->ring_notebook), options_page,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
2445 gtk_widget_set_tooltip_text(
g->interpolation, _(
"select the interpolation method"));
2450 gtk_box_pack_start(GTK_BOX(ring_tabs_box), picker_box,
FALSE,
FALSE, 0);
2453 gtk_box_pack_start(GTK_BOX(picker_box),
g->module_picker,
FALSE,
FALSE, 0);
2455 g->picker_info = gtk_label_new(_(
"no sample"));
2456 gtk_widget_set_hexpand(
g->picker_info,
TRUE);
2457 gtk_widget_set_halign(
g->picker_info, GTK_ALIGN_START);
2458 gtk_label_set_xalign(GTK_LABEL(
g->picker_info), 0.f);
2459 gtk_box_pack_start(GTK_BOX(picker_box),
g->picker_info,
TRUE,
TRUE, 0);
2461 const int active_ring =
dt_conf_get_int(
"plugins/darkroom/colorequal/gui_ring_page");
2462 const int active_channel =
dt_conf_get_int(
"plugins/darkroom/colorequal/gui_channel_page");
2467 gtk_notebook_set_current_page(
g->ring_notebook, current_ring_page);
2469 gtk_notebook_set_current_page(
g->channel_notebook[ring], current_channel_page);
2475 g->viewer_lut.clut = NULL;
2476 g->viewer_lut.clut_level = 0;
2477 memset(
g->viewer_lut.reference_saturation, 0,
sizeof(
g->viewer_lut.reference_saturation));
2478 g->viewer_lut.lut_profile = NULL;
2479 g->viewer_lut.work_profile = NULL;
2480 g->viewer_control_node_count = 0;
2498 const int lut_program = 28;
2499 const int basic_program = 2;
Handle default and user-set shortcuts (accelerators)
GtkWidget * dt_gui_main_window(void)
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 __DT_CLONE_TARGETS__ void normalize(float *const buffer, const size_t width, const size_t height, const float norm)
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
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_iop_order_iccprofile_info_t * dt_colorspaces_add_profile(const dt_colorspaces_color_profile_type_t profile_type, const char *profile_filename, const int intent)
Find-or-build the derived matrix/LUT data for a profile identity, memoised.
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)
OpenCL counterpart of dt_ioppr_transform_image_colorspace_rgb().
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
const dt_colormatrix_t dt_aligned_pixel_t out
static dt_aligned_pixel_t RGB
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
void dt_control_queue_redraw_center()
Request a redraw of the centre view.
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)
struct dt_control_t * dt_control_get_global(void)
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
#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_retained(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)
int32_t dt_dev_roi_request_preview_height(const dt_develop_t *dev)
int32_t dt_dev_roi_request_preview_width(const dt_develop_t *dev)
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_get_pipe_current_profile_info(dt_iop_module_t *module, const struct dt_dev_pixelpipe_t *pipe)
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.
GHashTable * selected
set of checked row labels, mirrored to conf on every change
static void set_color(cairo_t *cr, GdkRGBA color)
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]
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_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
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 dt_iop_gui_data_t * dt_iop_gui_data(const struct dt_iop_module_t *m)
The module's GUI data blob, NULL-safe for headless callers: IOP process() implementations read it for...
#define IOP_GUI_ALLOC(module)
static float kernel(const float *x, const float *y)
static float mix(const float a, const float b, const float t)
_lib_location_type_t type
int32_t dt_get_debug_flags(void)
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
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)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
dt_masks_form_t * dt_masks_get_visible_form(const dt_develop_t *dev)
Return the currently visible form used by the masks GUI.
The interactive half of the masks subsystem: the editing state (dt_masks_form_gui_t),...
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
static void * dt_calloc_align(size_t size)
dt_alloc_align() followed by a zero fill.
static float * dt_alloc_align_float(size_t pixels)
Allocate pixels floats, cacheline-aligned and marked as such.
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
DT_MODULE() for a module whose params struct is introspected.
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)
#define __OMP_PARALLEL_FOR__(...)
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_dev_pixelpipe_cache_ref_count_entry(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(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
@ DT_COLORSPACE_HLG_REC2020
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
struct dt_control_signal_t * dt_control_signal_get_global(void)
@ 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)
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
static const dt_aligned_pixel_simd_t value
const float uint32_t state[4]
unsigned __int64 uint64_t
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_masks_form_gui_t * form_gui
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
dt_iop_params_t * default_params
struct dt_iop_module_gui_t * gui
struct dt_develop_t * dev
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
A profile reduced to the arithmetic the pixel loop can run: two matrices and six tone-curve LUTs,...
Region of interest passed through the pixelpipe.
One consumer's outstanding request, owned by that consumer, not by the queue.
#define __DT_CLONE_TARGETS__
static double dt_get_wtime(void)