65#include <glib/gstdio.h>
125#define _commit_dabs dt_drawlayer_commit_dabs
126#define _flush_layer_cache dt_drawlayer_flush_layer_cache
127#define _sync_widget_cache dt_drawlayer_sync_widget_cache
128#define _set_drawlayer_pipeline_realtime_mode dt_drawlayer_set_pipeline_realtime_mode
129#define _ensure_layer_cache dt_drawlayer_ensure_layer_cache
130#define _release_all_base_patch_extra_refs dt_drawlayer_release_all_base_patch_extra_refs
131#define _drawlayer_wait_for_rasterization_modal dt_drawlayer_wait_for_rasterization_modal
132#define _current_live_padding dt_drawlayer_current_live_padding
133#define _layer_to_widget_coords dt_drawlayer_layer_to_widget_coords
134#define _touch_stroke_commit_hash dt_drawlayer_touch_stroke_commit_hash
135#define _drawlayer_runtime_collect_inputs NULL
136#define _drawlayer_runtime_perform_action NULL
145 char *
name,
size_t name_size);
152 gboolean flush_pending);
167 if(!display_rgb ||
IS_NULL_PTR(pipeline_rgb))
return;
169 pipeline_rgb[0] =
_clamp01(display_rgb[0]);
170 pipeline_rgb[1] =
_clamp01(display_rgb[1]);
171 pipeline_rgb[2] =
_clamp01(display_rgb[2]);
181 float in[4] = { pipeline_rgb[0], pipeline_rgb[1], pipeline_rgb[2], 0.0f };
182 float out[4] = { pipeline_rgb[0], pipeline_rgb[1], pipeline_rgb[2], 0.0f };
184 "drawlayer brush color");
185 pipeline_rgb[0] =
out[0];
186 pipeline_rgb[1] =
out[1];
187 pipeline_rgb[2] =
out[2];
192 pipeline_rgb[0] *= gain;
193 pipeline_rgb[1] *= gain;
194 pipeline_rgb[2] *= gain;
203 g->ui.brush_display_color[0] =
_clamp01(display_rgb[0]);
204 g->ui.brush_display_color[1] =
_clamp01(display_rgb[1]);
205 g->ui.brush_display_color[2] =
_clamp01(display_rgb[2]);
207 g->ui.brush_color_valid =
TRUE;
215 uint32_t map_flags = 0u;
229 float display_rgb[3] = { 0.0f };
230 float pipeline_rgb[3] = { 0.0f };
233 memcpy(display_rgb,
g->ui.brush_display_color,
sizeof(display_rgb));
234 memcpy(pipeline_rgb,
g->ui.brush_pipeline_color,
sizeof(pipeline_rgb));
242 memcpy(display_rgb,
g->ui.brush_display_color,
sizeof(display_rgb));
243 memcpy(pipeline_rgb,
g->ui.brush_pipeline_color,
sizeof(pipeline_rgb));
248 display_rgb[0] =
_clamp01(display_rgb[0]);
249 display_rgb[1] =
_clamp01(display_rgb[1]);
250 display_rgb[2] =
_clamp01(display_rgb[2]);
269 input->
color[0] = pipeline_rgb[0];
270 input->
color[1] = pipeline_rgb[1];
271 input->
color[2] = pipeline_rgb[2];
296 "[drawlayer] raw-input batch=%u event=%u pos=%u widget=(%.3f,%.3f) raster=(%.3f,%.3f) ok=%d\n",
305 g_strlcpy(tmp,
name,
sizeof(tmp));
307 return tmp[0] !=
'\0';
311 char *
key,
const size_t key_size)
320 g_snprintf(
key, key_size,
"%d|%d|%s", (
int)work_profile->
type, (
int)work_profile->
intent,
322 return key[0] !=
'\0';
353 scratch = g_malloc0(
sizeof(*scratch));
361 int *layer_height,
int *origin_x,
int *origin_y)
379 int resolved_width = 0;
380 int resolved_height = 0;
385 if(!
IS_NULL_PTR(layer_width)) *layer_width = resolved_width;
386 if(!
IS_NULL_PTR(layer_height)) *layer_height = resolved_height;
387 return resolved_width > 0 && resolved_height > 0;
391 const int layer_width,
const int layer_height)
400 hash =
dt_hash(hash, (
const char *)&imgid,
sizeof(imgid));
401 hash =
dt_hash(hash, (
const char *)&layer_width,
sizeof(layer_width));
402 hash =
dt_hash(hash, (
const char *)&layer_height,
sizeof(layer_height));
409 return hash ? hash : 1u;
420 const uint64_t new_hash = _drawlayer_params_cache_hash(imgid, params, patch->
width, patch->
height);
442 patch->
width, patch->
height,
"drawlayer sidecar cache", &created))
455 "[drawlayer] cache rekey conflict old=%" PRIu64
" new=%" PRIu64
" -> published snapshot instead\n",
464 g->process.base_patch_loaded_ref =
TRUE;
471 g->process.base_patch_stroke_refs++;
482 g->process.base_patch_loaded_ref =
FALSE;
483 g->process.base_patch_stroke_refs = 0;
487 if(
g->process.base_patch_loaded_ref)
490 g->process.base_patch_loaded_ref =
FALSE;
493 while(
g->process.base_patch_stroke_refs > 0)
496 g->process.base_patch_stroke_refs--;
505 if(
params->layer_name[0] ==
'\0')
537 const gboolean have_sidecar = have_sidecar_path && g_file_test(path, G_FILE_TEST_EXISTS);
543 int layer_height = 0;
544 const gboolean have_pipe_geometry = _resolve_layer_geometry(self, pipe, piece, &layer_width, &layer_height, NULL, NULL);
556 if(!have_pipe_geometry)
560 layer_width = (int)info.
width;
561 layer_height = (int)info.
height;
582 if(layer_width > 0 && layer_height > 0)
588 (
size_t)layer_width * layer_height, layer_width, layer_height,
589 "drawlayer sidecar cache", &created))
601 gboolean warm_loaded =
FALSE;
602 if(have_sidecar && info.
found)
612 layer_height, &warm_patch);
639 const gboolean use_preview_bg,
const float preview_bg)
643 const dt_aligned_pixel_simd_t preview_base = { preview_bg, preview_bg, preview_bg, 1.0f };
645 for(
size_t kk = 0; kk < pixels; kk++)
647 const float *base = input + 4 * kk;
648 const float *layer = layerbuf + 4 * kk;
649 float *pixel = output + 4 * kk;
650 const float src_alpha =
_clamp01(layer[3]);
651 if(src_alpha > 1e-8f)
653 const dt_aligned_pixel_simd_t base_v = use_preview_bg ? preview_base : dt_load_simd_aligned(base);
654 dt_aligned_pixel_simd_t src_v = dt_load_simd_aligned(layer);
655 const float inv_alpha = 1.0f - src_alpha;
656 const dt_aligned_pixel_simd_t inv_alpha_v = { inv_alpha, inv_alpha, inv_alpha, inv_alpha };
657 src_v[3] = src_alpha;
662 const dt_aligned_pixel_simd_t base_v = use_preview_bg ? preview_base : dt_load_simd_aligned(base);
682 if(dirty_rect && dirty_rect->
valid)
684 const int dirty_x0 = CLAMP(dirty_rect->
nw[0], 0,
width);
685 const int dirty_y0 = CLAMP(dirty_rect->
nw[1], 0,
height);
686 const int dirty_x1 = CLAMP(dirty_rect->
se[0], 0,
width);
687 const int dirty_y1 = CLAMP(dirty_rect->
se[1], 0,
height);
688 const int dirty_w = dirty_x1 - dirty_x0;
689 const int dirty_h = dirty_y1 - dirty_y0;
690 if(dirty_w > 0 && dirty_h > 0 && (dirty_w <
width || dirty_h <
height))
692 const size_t origin[] = { (size_t)dirty_x0, (
size_t)dirty_y0, 0 };
693 const size_t region[] = { (size_t)dirty_w, (
size_t)dirty_h, 1 };
694 char *host_origin = (
char *)host_pixels + ((
size_t)dirty_y0 *
width + dirty_x0) * (
size_t)
bpp;
696 CL_TRUE) == CL_SUCCESS)
713 const gboolean force_device_copy,
const gboolean realtime_reuse,
714 const int source_w,
const int source_h,
721 if(force_device_copy)
731 if(realtime_reuse && resolved_entry)
734 gboolean reused_from_cache =
FALSE;
736 "drawlayer source", resolved_entry,
737 &reused_from_cache, NULL);
741 = (reused_from_cache &&
process) ? &
process->cache_dirty_rect : NULL;
743 4 *
sizeof(
float), dirty_rect))
755 (
void *)layer_pixels, resolved_entry, devid, source_w, source_h,
756 4 *
sizeof(
float), CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, NULL);
764 devid, source_w, source_h, 4 *
sizeof(
float), (
void *)layer_pixels, CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR);
768 4 *
sizeof(
float), NULL))
783 const int source_w,
const int source_h,
787 const gboolean can_copy_crop
788 = (fabs(target_roi->
scale - 1.0) <= 1e-6 && target_roi->
x >= 0
789 && target_roi->
y >= 0 && target_roi->
x + target_roi->
width <= source_w
790 && target_roi->
y + target_roi->
height <= source_h);
793 size_t src_origin[3] = { (size_t)target_roi->
x, (
size_t)target_roi->
y, 0 };
794 size_t dst_origin[3] = { 0, 0, 0 };
795 size_t region[3] = { (size_t)target_roi->
width, (
size_t)target_roi->
height, 1 };
798 if(copy_err == CL_SUCCESS)
return CL_SUCCESS;
813 const gboolean realtime_reuse,
const gboolean direct_copy,
814 cl_mem dev_source_rgba,
const int source_w,
const int source_h,
824 layer->
mem = dev_source_rgba;
828 if(realtime_reuse && resolved_entry)
831 "drawlayer layer", resolved_entry, NULL,
843 *err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
849 return *err == CL_SUCCESS;
853 cl_mem dev_background, cl_mem dev_layer_rgba, cl_mem dev_out,
854 const int width,
const int height,
const int background_offset_x,
855 const int background_offset_y)
857 const int offs[2] = { background_offset_x, background_offset_y };
866 if(err != CL_SUCCESS)
return err;
876#define DRAWLAYER_RESAMPLE_DAMAGE_MARGIN 8
893 const double scale = target_roi->
scale;
897 const double sx0 = (
double)src_damage->
nw[0] + source_roi->
x;
898 const double sy0 = (
double)src_damage->
nw[1] + source_roi->
y;
899 const double sx1 = (
double)src_damage->
se[0] + source_roi->
x;
900 const double sy1 = (
double)src_damage->
se[1] + source_roi->
y;
902 int tx0 = (int)floor(sx0 * scale - target_roi->
x) - margin;
903 int ty0 = (int)floor(sy0 * scale - target_roi->
y) - margin;
904 int tx1 = (int)ceil(sx1 * scale - target_roi->
x) + margin;
905 int ty1 = (int)ceil(sy1 * scale - target_roi->
y) + margin;
907 tx0 = CLAMP(tx0, 0, target_roi->
width);
908 ty0 = CLAMP(ty0, 0, target_roi->
height);
909 tx1 = CLAMP(tx1, 0, target_roi->
width);
910 ty1 = CLAMP(ty1, 0, target_roi->
height);
912 if(tx1 <= tx0 || ty1 <= ty0)
return FALSE;
914 if(tx0 == 0 && ty0 == 0 && tx1 == target_roi->
width && ty1 == target_roi->
height)
return FALSE;
923 cl_mem source_mem_override,
const int source_w,
const int source_h,
926 const gboolean direct_copy,
const gboolean use_preview_bg,
927 const float preview_bg,
const gboolean realtime_reuse,
928 const gboolean force_device_copy,
const gboolean allow_partial)
931 || source_h <= 0 || !target_roi || target_roi->width <= 0 || target_roi->
height <= 0)
933 if(kernel_premult_over < 0)
return FALSE;
936 gboolean resolved_entry_ref =
FALSE;
937 if(realtime_reuse && !resolved_entry)
941 resolved_entry_ref = (!
IS_NULL_PTR(resolved_entry));
951 const gboolean partial = allow_partial && !use_preview_bg && !direct_copy && !source_mem_override &&
process
953 source_roi, &target_damage);
957 cl_mem dev_layer_partial = NULL;
958 cl_mem dev_bg_partial = NULL;
959 cl_mem dev_out_partial = NULL;
960 cl_mem dev_background = NULL;
961 int err = CL_SUCCESS;
963 if(source_mem_override)
964 source.
mem = source_mem_override;
966 source_w, source_h,
process, &source))
971 const int dw = target_damage.
se[0] - target_damage.
nw[0];
972 const int dh = target_damage.
se[1] - target_damage.
nw[1];
973 size_t win_origin[3] = { (size_t)target_damage.
nw[0], (
size_t)target_damage.
nw[1], 0 };
974 size_t zero_origin[3] = { 0, 0, 0 };
975 size_t win_region[3] = { (size_t)dw, (
size_t)dh, 1 };
990 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
997 .
x = target_roi->
x + target_damage.
nw[0],
998 .y = target_roi->
y + target_damage.
nw[1],
1001 .scale = target_roi->
scale,
1004 &sub_target_roi, source_roi);
1005 if(err != CL_SUCCESS)
goto cleanup;
1008 if(err != CL_SUCCESS)
goto cleanup;
1011 dev_out_partial, dw, dh, 0, 0);
1012 if(err != CL_SUCCESS)
goto cleanup;
1015 if(err != CL_SUCCESS)
goto cleanup;
1019 target_damage.
nw[0], target_damage.
nw[1], target_roi->
width, target_roi->
height);
1034 source_h, target_roi, source_roi, &layer, &err))
1039 const size_t out_pixels = (size_t)target_roi->
width * target_roi->
height;
1042 "drawlayer process scratch");
1045 for(
size_t kk = 0; kk < out_pixels; kk++)
1047 float *pixel = background + 4 * kk;
1048 pixel[0] = preview_bg;
1049 pixel[1] = preview_bg;
1050 pixel[2] = preview_bg;
1054 background, NULL, devid, target_roi->
width, target_roi->
height,
1055 4 *
sizeof(
float), CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, NULL);
1059 dev_background = dev_in;
1063 if(err != CL_SUCCESS)
goto cleanup;
1086 (
void **)&dev_background);
1087 if(layer.
mem && layer.
mem != source.
mem)
1094 if(!source_mem_override && source.
is_pinned)
1096 (
void **)&source.
mem);
1099 else if(!source_mem_override && source.
mem)
1101 if(resolved_entry_ref)
1115 for(
const unsigned char *c = (
const unsigned char *)
value; *c; c++)
1119 else if(!g_ascii_isprint(*c))
1123 return separators >= 2;
1128 if(
IS_NULL_PTR(path) || path[0] ==
'\0' || !g_file_test(path, G_FILE_TEST_EXISTS))
return 0;
1130 GStatBuf st = { 0 };
1131 if(g_stat(path, &st) != 0)
return 0;
1132 return (int64_t)st.st_mtime;
1136 const float hardness)
1142 float display_rgb[3] = { 0.0f };
1145 const int size_px =
MAX(2, (
int)ceil((2.0f * widget_radius + 2.0f) * ppd));
1147 const gboolean needs_rebuild
1148 = !
g->ui.cursor_surface ||
g->ui.cursor_surface_size != size_px || fabs(
g->ui.cursor_surface_ppd - ppd) > 1e-9
1149 || fabsf(
g->ui.cursor_radius - widget_radius) > 1e-3f || fabsf(
g->ui.cursor_opacity - opacity) > 1e-6f
1150 || fabsf(
g->ui.cursor_hardness - hardness) > 1e-6f ||
g->ui.cursor_shape != shape
1151 || fabsf(
g->ui.cursor_color[0] - display_rgb[0]) > 1e-6f || fabsf(
g->ui.cursor_color[1] - display_rgb[1]) > 1e-6f
1152 || fabsf(
g->ui.cursor_color[2] - display_rgb[2]) > 1e-6f;
1153 if(!needs_rebuild)
return;
1156 g->ui.cursor_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size_px, size_px);
1157 if(cairo_surface_status(
g->ui.cursor_surface) != CAIRO_STATUS_SUCCESS)
1162 cairo_surface_set_device_scale(
g->ui.cursor_surface, ppd, ppd);
1164 unsigned char *data = cairo_image_surface_get_data(
g->ui.cursor_surface);
1165 const int stride = cairo_image_surface_get_stride(
g->ui.cursor_surface);
1166 memset(data, 0, (
size_t)stride * size_px);
1169 .
radius = fmaxf(widget_radius * (
float)ppd, 0.5f),
1171 .hardness = hardness,
1173 .display_color = { display_rgb[0], display_rgb[1], display_rgb[2] },
1176 const float half = 0.5f * (float)size_px;
1178 cairo_surface_mark_dirty(
g->ui.cursor_surface);
1180 g->ui.cursor_surface_size = size_px;
1181 g->ui.cursor_surface_ppd = ppd;
1182 g->ui.cursor_radius = widget_radius;
1183 g->ui.cursor_opacity = opacity;
1184 g->ui.cursor_hardness = hardness;
1185 g->ui.cursor_shape = shape;
1186 g->ui.cursor_color[0] = display_rgb[0];
1187 g->ui.cursor_color[1] = display_rgb[1];
1188 g->ui.cursor_color[2] = display_rgb[2];
1198 if(
main) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(
main));
1199 gtk_window_set_modal(GTK_WINDOW(dialog),
TRUE);
1200 gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog),
TRUE);
1201 gtk_window_set_deletable(GTK_WINDOW(dialog),
FALSE);
1202 gtk_window_set_resizable(GTK_WINDOW(dialog),
FALSE);
1203 gtk_window_set_title(GTK_WINDOW(dialog), title);
1204 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
1206 GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1209 GtkWidget *label = gtk_label_new(message);
1210 gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
1211 gtk_box_pack_start(GTK_BOX(box), spinner,
FALSE,
FALSE, 0);
1212 gtk_box_pack_start(GTK_BOX(box), label,
TRUE,
TRUE, 0);
1214 gtk_box_pack_start(GTK_BOX(content), box,
TRUE,
TRUE, 0);
1215 gtk_spinner_start(GTK_SPINNER(spinner));
1216 gtk_widget_show_all(dialog);
1217 gtk_widget_show_now(dialog);
1218 gtk_window_present(GTK_WINDOW(dialog));
1219 GdkDisplay *display = gtk_widget_get_display(dialog);
1220 if(display) gdk_display_flush(display);
1225 for(
int k = 0;
k < 2;
k++)
1226 gtk_main_iteration_do(
FALSE);
1243 g_main_loop_quit(
state->loop);
1244 return G_SOURCE_REMOVE;
1247 return G_SOURCE_CONTINUE;
1251 const char *title,
const char *message)
1256 GMainLoop *loop = g_main_loop_new(NULL,
FALSE);
1264 g_main_loop_run(loop);
1266 if(source_id) g_source_remove(source_id);
1269 gtk_widget_destroy(wait.
dialog);
1272 g_main_loop_unref(loop);
1280 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
1281 type, GTK_BUTTONS_OK,
"%s", primary);
1282 if(secondary && secondary[0] !=
'\0')
1283 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
"%s", secondary);
1284 gtk_dialog_run(GTK_DIALOG(dialog));
1285 gtk_widget_destroy(dialog);
1289 char *
name,
const size_t name_size)
1293 GtkWidget *dialog = gtk_dialog_new_with_buttons(
1295 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, _(
"Cancel"), GTK_RESPONSE_CANCEL,
1296 _(
"Confirm"), GTK_RESPONSE_ACCEPT, NULL);
1297 GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1302 GtkWidget *label = gtk_label_new(message);
1303 gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
1304 gtk_label_set_line_wrap(GTK_LABEL(label),
TRUE);
1305 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
FALSE, 0);
1307 gtk_entry_set_activates_default(GTK_ENTRY(entry),
TRUE);
1308 if(initial_name && initial_name[0] !=
'\0') gtk_entry_set_text(GTK_ENTRY(entry), initial_name);
1309 gtk_box_pack_start(GTK_BOX(box), entry,
FALSE,
FALSE, 0);
1311 gtk_box_pack_start(GTK_BOX(content), box,
TRUE,
TRUE, 0);
1312 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1313 gtk_widget_show_all(dialog);
1315 gboolean accepted =
FALSE;
1316 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1322 gtk_widget_destroy(dialog);
1331 float display_rgb[3] = { 0.0f };
1360 float display_rgb[3] = { 0.0f };
1374 gtk_widget_queue_draw(
g->controls.brush_shape);
1399 gtk_widget_queue_draw(widget);
1404 const float working_rgb[3],
float display_rgb[3])
1409 const float inv_gain = (gain > 0.0f) ? 1.0f / gain : 1.0f;
1410 const float preview_rgb[3] = {
1411 working_rgb[0] * inv_gain,
1412 working_rgb[1] * inv_gain,
1413 working_rgb[2] * inv_gain,
1416 display_rgb[0] =
_clamp01(preview_rgb[0]);
1417 display_rgb[1] =
_clamp01(preview_rgb[1]);
1418 display_rgb[2] =
_clamp01(preview_rgb[2]);
1427 float in[4] = { preview_rgb[0], preview_rgb[1], preview_rgb[2], 0.0f };
1428 float out[4] = { preview_rgb[0], preview_rgb[1], preview_rgb[2], 0.0f };
1444 const float *picked_min
1446 const float *picked_max
1448 if(picked_max[0] < picked_min[0])
return;
1450 float display_rgb[3] = { 0.0f };
1471 float display_rgb[3] = { 0.0f };
1491 if(memchr(params->layer_name,
'\0',
sizeof(params->layer_name)) == NULL)
1492 memset(params->layer_name, 0,
sizeof(params->layer_name));
1494 params->layer_name[
sizeof(params->layer_name) - 1] =
'\0';
1498 if(g_strcmp0(params->layer_name, sanitized_layer_name))
1499 g_strlcpy(params->layer_name, sanitized_layer_name,
sizeof(params->layer_name));
1501 if(memchr(params->work_profile,
'\0',
sizeof(params->work_profile)) == NULL)
1502 memset(params->work_profile, 0,
sizeof(params->work_profile));
1504 params->work_profile[
sizeof(params->work_profile) - 1] =
'\0';
1508 params->layer_name[0] =
'\0';
1509 params->layer_order = -1;
1510 params->sidecar_timestamp = 0;
1512 if(params->layer_order < -1) params->layer_order = -1;
1514 memset(params->work_profile, 0,
sizeof(params->work_profile));
1517 if(params->layer_order < 0 && params->stroke_commit_hash == 0u)
1518 memset(params->work_profile, 0,
sizeof(params->work_profile));
1520 if(params->work_profile[0] ==
'\0' && !
IS_NULL_PTR(self) && self->
dev)
1524 sizeof(current_profile)))
1525 g_strlcpy(params->work_profile, current_profile,
sizeof(params->work_profile));
1533 if(!(!
IS_NULL_PTR(requested) && requested[0]))
return;
1535 gboolean last_was_space =
FALSE;
1537 for(
size_t in = 0; requested[in] !=
'\0' &&
out + 1 < name_size; in++)
1539 const unsigned char ch = (
unsigned char)requested[in];
1540 if(g_ascii_isspace(
ch))
1542 if(
out > 0 && !last_was_space)
1545 last_was_space =
TRUE;
1551 last_was_space =
FALSE;
1584 .width =
process->base_patch.width,
1585 .height =
process->base_patch.height,
1610 process_roi.
x += (int)lroundf((
float)placement.
offset_x * process_roi.
scale);
1611 process_roi.
y += (int)lroundf((
float)placement.
offset_y * process_roi.
scale);
1640 const int preview_mode = (gui && self && self->
dev && self->
dev->
gui_module == self)
1652 const gboolean have_last_dab,
const float last_dab_x,
1653 const float last_dab_y,
const uint32_t publish_serial)
1657 uint32_t x_bits = 0u;
1658 uint32_t y_bits = 0u;
1661 memcpy(&x_bits, &last_dab_x,
sizeof(x_bits));
1662 memcpy(&y_bits, &last_dab_y,
sizeof(y_bits));
1665 const uint32_t seed[5] = { (uint32_t)dab_count, have_last_dab ? 1u : 0u, x_bits, y_bits, publish_serial };
1667 uint64_t hash = params->stroke_commit_hash ? params->stroke_commit_hash : 5381u;
1668 hash =
dt_hash(hash, (
const char *)seed,
sizeof(seed));
1672 params->stroke_commit_hash = (uint32_t)(hash ? hash : 1u);
1679 GMainContext *
const ui_ctx = g_main_context_default();
1682 g->manager.background_job_running =
g->session.background_job_running;
1695 const gboolean missing = (
g->session.missing_layer_error[0] !=
'\0');
1698 if(
g->controls.notebook)
1700 if(
g->controls.brush_tab) gtk_widget_set_visible(
g->controls.brush_tab, attached);
1701 if(
g->controls.input_tab) gtk_widget_set_visible(
g->controls.input_tab, attached);
1702 if(
g->controls.layer_tab) gtk_widget_set_visible(
g->controls.layer_tab,
TRUE);
1703 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(
g->controls.notebook), attached);
1704 gtk_notebook_set_show_border(GTK_NOTEBOOK(
g->controls.notebook), attached);
1705 if(!attached &&
g->controls.layer_tab)
1706 gtk_notebook_set_current_page(GTK_NOTEBOOK(
g->controls.notebook),
1707 gtk_notebook_page_num(GTK_NOTEBOOK(
g->controls.notebook),
g->controls.layer_tab));
1710 if(
g->controls.preview_title) gtk_widget_set_visible(
g->controls.preview_title, attached);
1711 if(
g->controls.preview_box) gtk_widget_set_visible(
g->controls.preview_box, attached);
1712 if(
g->controls.layer_action_row) gtk_widget_set_visible(
g->controls.layer_action_row,
TRUE);
1713 if(
g->controls.layer_status)
1715 gtk_label_set_text(GTK_LABEL(
g->controls.layer_status), missing ?
g->session.missing_layer_error :
"");
1716 gtk_widget_set_visible(
g->controls.layer_status, missing);
1718 if(
g->controls.delete_layer) gtk_widget_set_visible(
g->controls.delete_layer, attached);
1719 if(
g->controls.rename_layer) gtk_widget_set_visible(
g->controls.rename_layer, attached);
1720 if(
g->controls.layer_fill_title) gtk_widget_set_visible(
g->controls.layer_fill_title, attached);
1721 if(
g->controls.layer_fill_row) gtk_widget_set_visible(
g->controls.layer_fill_row, attached);
1722 if(
g->controls.create_background) gtk_widget_set_visible(
g->controls.create_background, attached);
1723 if(
g->controls.save_layer) gtk_widget_set_visible(
g->controls.save_layer, attached);
1724 if(
g->controls.attach_layer) gtk_widget_set_visible(
g->controls.attach_layer, !attached && have_existing_layers);
1726 if(
g->controls.layer_select) gtk_widget_set_visible(
g->controls.layer_select, attached || have_existing_layers);
1727 if(
g->controls.create_layer) gtk_widget_set_sensitive(
g->controls.create_layer,
TRUE);
1728 if(
g->controls.rename_layer) gtk_widget_set_sensitive(
g->controls.rename_layer, attached);
1729 if(
g->controls.attach_layer) gtk_widget_set_sensitive(
g->controls.attach_layer, have_existing_layers);
1730 if(
g->controls.create_background)
1731 gtk_widget_set_sensitive(
g->controls.create_background, attached && !
g->session.background_job_running);
1732 if(
g->controls.save_layer) gtk_widget_set_sensitive(
g->controls.save_layer, attached);
1740 if(GTK_IS_TOGGLE_BUTTON(
g->controls.preview_bg_image))
1741 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.preview_bg_image),
1743 if(GTK_IS_TOGGLE_BUTTON(
g->controls.preview_bg_white))
1744 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.preview_bg_white),
1746 if(GTK_IS_TOGGLE_BUTTON(
g->controls.preview_bg_grey))
1747 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.preview_bg_grey),
1749 if(GTK_IS_TOGGLE_BUTTON(
g->controls.preview_bg_black))
1750 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.preview_bg_black),
1769 if(
g->manager.painting_active)
1772 dt_print(
DT_DEBUG_PERF,
"[drawlayer] commit_dabs deferred: stroke in progress (record_history=%d)\n",
1792 int sample_count = 0;
1793 gboolean had_stroke =
FALSE;
1794 gboolean had_last_dab =
FALSE;
1795 float last_dab_x = 0.0f;
1796 float last_dab_y = 0.0f;
1798 g->stroke.finish_commit_pending =
FALSE;
1799 sample_count = (int)
g->stroke.stroke_sample_count;
1800 had_stroke = (sample_count > 0);
1801 had_last_dab =
g->stroke.last_dab_valid;
1802 last_dab_x =
g->stroke.last_dab_x;
1803 last_dab_y =
g->stroke.last_dab_y;
1819 if(record_history && self->
dev)
1827 if(self->post_history_commit) self->post_history_commit(self);
1829 g->manager.realtime_active =
FALSE;
1843 if(!(had_stroke && record_history))
1845 g->manager.realtime_active =
FALSE;
1863 .manager = &
g->manager,
1864 .process_state = &
g->process,
1875 .event = DT_DRAWLAYER_RUNTIME_EVENT_GUI_PIPE_FINISHED,
1876 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
1888 gtk_widget_set_visible(GTK_WIDGET(
g->controls.color), paint_mode);
1889 if(
g->controls.color_row) gtk_widget_set_visible(
g->controls.color_row, paint_mode);
1890 if(
g->controls.color_swatch) gtk_widget_set_visible(
g->controls.color_swatch, paint_mode);
1891 if(
g->controls.image_colorpicker) gtk_widget_set_visible(
g->controls.image_colorpicker, paint_mode);
1892 if(
g->controls.image_colorpicker_source) gtk_widget_set_visible(
g->controls.image_colorpicker_source, paint_mode);
1893 gtk_widget_set_visible(
g->controls.softness, show_hardness);
1904 GString *errors = g_string_new(NULL);
1905 gboolean deleted =
FALSE;
1906 int layer_width = 0;
1907 int layer_height = 0;
1908 if(!_resolve_layer_geometry(self, NULL, NULL, &layer_width, &layer_height, NULL, NULL))
1912 layer_height =
geometry.raw_height;
1920 else if(!g_file_test(path, G_FILE_TEST_EXISTS))
1931 params->layer_name[0] =
'\0';
1932 params->layer_order = -1;
1933 params->sidecar_timestamp = 0;
1934 memset(params->work_profile, 0,
sizeof(params->work_profile));
1935 if(
g)
g->session.missing_layer_error[0] =
'\0';
1940 g->process.cache_valid =
FALSE;
1941 g->process.cache_dirty =
FALSE;
1943 g->process.cache_imgid = -1;
1944 g->process.cache_layer_name[0] =
'\0';
1945 g->process.cache_layer_order = -1;
1953 g_string_free(errors,
TRUE);
1964 GtkWidget *dialog = gtk_message_dialog_new(
1966 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
"%s",
1968 ? _(
"Delete the linked drawing layer from the sidecar TIFF before removing this module instance?")
1969 : _(
"Delete the linked drawing layer from the sidecar TIFF?"));
1972 gtk_dialog_add_button(GTK_DIALOG(dialog), _(
"Keep layer"), GTK_RESPONSE_NO);
1973 gtk_dialog_add_button(GTK_DIALOG(dialog), _(
"Delete layer"), GTK_RESPONSE_YES);
1977 gtk_dialog_add_button(GTK_DIALOG(dialog), _(
"Cancel"), GTK_RESPONSE_CANCEL);
1978 gtk_dialog_add_button(GTK_DIALOG(dialog), _(
"Delete"), GTK_RESPONSE_ACCEPT);
1981 const int response = gtk_dialog_run(GTK_DIALOG(dialog));
1982 gtk_widget_destroy(dialog);
1991 if(response != GTK_RESPONSE_ACCEPT)
return FALSE;
2004 if(!
IS_NULL_PTR(requested_name)) g_strlcpy(stripped_requested, requested_name,
sizeof(stripped_requested));
2005 g_strstrip(stripped_requested);
2006 if(stripped_requested[0] ==
'\0')
return FALSE;
2008 if(new_name[0] ==
'\0')
return FALSE;
2010 if(!g_strcmp0(new_name, params->layer_name))
return TRUE;
2012 GString *errors = g_string_new(NULL);
2013 gboolean renamed =
FALSE;
2014 int layer_width = 0;
2015 int layer_height = 0;
2016 if(!_resolve_layer_geometry(self, NULL, NULL, &layer_width, &layer_height, NULL, NULL))
2020 layer_height =
geometry.raw_height;
2032 else if(!g_file_test(path, G_FILE_TEST_EXISTS))
2038 layer_width, layer_height, &info))
2042 g_strlcpy(params->layer_name, new_name,
sizeof(params->layer_name));
2043 params->layer_order = info.
index;
2045 g_strlcpy(
g->process.cache_layer_name, params->layer_name,
sizeof(
g->process.cache_layer_name));
2046 g->process.cache_layer_order = params->layer_order;
2054 g->session.missing_layer_error[0] =
'\0';
2064 g_string_free(errors,
TRUE);
2076 if(!
IS_NULL_PTR(requested_name)) g_strlcpy(stripped_requested, requested_name,
sizeof(stripped_requested));
2077 g_strstrip(stripped_requested);
2078 if(stripped_requested[0] ==
'\0')
return FALSE;
2080 if(new_name[0] ==
'\0')
return FALSE;
2087 _(
"A drawing layer with that name already exists."),
2088 _(
"Choose a different layer name."));
2097 g_strlcpy(params->layer_name, new_name,
sizeof(params->layer_name));
2098 params->layer_order = -1;
2099 params->sidecar_timestamp = 0;
2100 memset(params->work_profile, 0,
sizeof(params->work_profile));
2112 if(!
g->process.cache_valid ||
IS_NULL_PTR(
g->process.base_patch.pixels))
2118 g->process.cache_dirty =
TRUE;
2126 g->session.missing_layer_error[0] =
'\0';
2140 if(
IS_NULL_PTR(filter) || filter_size == 0)
return;
2145 const char *prev_op = NULL;
2146 if(self_piece && self->
dev->
pipe)
2148 for(GList *nodes = self->
dev->
pipe->
nodes; nodes; nodes = g_list_next(nodes))
2151 if(piece == self_piece)
break;
2152 if(piece->
enabled && piece->module && piece->module->op[0]) prev_op = piece->module->op;
2155 if(!
IS_NULL_PTR(prev_op) && prev_op[0]) g_snprintf(filter, filter_size,
"pre:%s", prev_op);
2167 gboolean cleared_initiator =
FALSE;
2168 if(dev && dev->image_storage.id == result->
imgid)
2170 for(GList *modules = dev->iop; modules; modules = g_list_next(modules))
2173 if(!module || g_strcmp0(module->op,
"drawlayer"))
continue;
2180 g->session.background_job_running =
FALSE;
2181 if(
g->controls.create_background) gtk_widget_set_sensitive(
g->controls.create_background,
TRUE);
2182 cleared_initiator =
TRUE;
2193 if(!cleared_initiator && dev)
2195 for(GList *modules = dev->iop; modules; modules = g_list_next(modules))
2198 if(!module || g_strcmp0(module->op,
"drawlayer"))
continue;
2200 if(
IS_NULL_PTR(
g) || !
g->session.background_job_running)
continue;
2201 g->session.background_job_running =
FALSE;
2202 if(
g->controls.create_background) gtk_widget_set_sensitive(
g->controls.create_background,
TRUE);
2207 return G_SOURCE_REMOVE;
2215 if(
g->session.background_job_running)
return FALSE;
2223 int layer_width = 0;
2224 int layer_height = 0;
2225 if(!_resolve_layer_geometry(self, self->
dev->
pipe, piece, &layer_width, &layer_height, NULL, NULL))
return FALSE;
2238 g_strlcpy(current_info.
name, io_info.
name,
sizeof(current_info.
name));
2245 job_params->
dst_x = 0;
2246 job_params->
dst_y = 0;
2257 "drawlayer create background layer");
2266 g->session.background_job_running =
TRUE;
2267 if(
g->controls.create_background) gtk_widget_set_sensitive(
g->controls.create_background,
FALSE);
2270 g->session.background_job_running =
FALSE;
2271 if(
g->controls.create_background) gtk_widget_set_sensitive(
g->controls.create_background,
TRUE);
2287 if(widget ==
g->controls.size || widget ==
g->controls.softness || widget ==
g->controls.brush_shape)
2290 if(widget ==
g->controls.hdr_exposure)
2292 float display_rgb[3] = { 0.0f };
2297 if(widget ==
g->controls.brush_shape || widget ==
g->controls.opacity || widget ==
g->controls.softness || widget ==
g->controls.sprinkles
2298 || widget ==
g->controls.sprinkle_size || widget ==
g->controls.sprinkle_coarseness)
2305 const int layer_order)
2310 g_strlcpy(previous_name, params->layer_name,
sizeof(previous_name));
2311 const int previous_order = params->layer_order;
2313 g_strlcpy(params->layer_name, layer_name,
sizeof(params->layer_name));
2314 params->layer_order = layer_order;
2317 g_strlcpy(params->layer_name, previous_name,
sizeof(params->layer_name));
2318 params->layer_order = previous_order;
2323 g->session.missing_layer_error[0] =
'\0';
2342 if(active < 0)
return;
2365 if(active < 0)
return;
2383 _(
"Enter the new name for the current drawing layer."),
2384 params->layer_name, requested_name,
sizeof(requested_name)))
2416 const size_t count = (size_t)
g->process.base_patch.width *
g->process.base_patch.height;
2417 float *
const pixels =
g->process.base_patch.pixels;
2421 for(
size_t k = 0;
k < count;
k++)
2423 float *pixel = pixels + 4 *
k;
2431 g->process.cache_dirty =
TRUE;
2432 g->process.cache_dirty_rect.valid =
TRUE;
2433 g->process.cache_dirty_rect.nw[0] = 0;
2434 g->process.cache_dirty_rect.nw[1] = 0;
2435 g->process.cache_dirty_rect.se[0] =
g->process.base_patch.width;
2436 g->process.cache_dirty_rect.se[1] =
g->process.base_patch.height;
2456 (
size_t)
g->process.base_patch.width *
g->process.base_patch.height);
2459 g->process.cache_dirty =
TRUE;
2460 g->process.cache_dirty_rect.valid =
TRUE;
2461 g->process.cache_dirty_rect.nw[0] = 0;
2462 g->process.cache_dirty_rect.nw[1] = 0;
2463 g->process.cache_dirty_rect.se[0] =
g->process.base_patch.width;
2464 g->process.cache_dirty_rect.se[1] =
g->process.base_patch.height;
2500 if(!
g->process.cache_valid ||
IS_NULL_PTR(
g->process.base_patch.pixels))
2503 _(
"No drawing layer is loaded in memory."),
2504 _(
"The sidecar save was aborted."));
2510 _(
"Layer name is empty."),
2511 _(
"The sidecar save was aborted."));
2516 GtkWidget *dialog = gtk_message_dialog_new(
2518 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
"%s", _(
"Save the drawing sidecar now?"));
2519 gtk_message_dialog_format_secondary_text(
2520 GTK_MESSAGE_DIALOG(dialog),
"%s",
2521 _(
"This writes the current in-memory drawing layer to the sidecar TIFF immediately."));
2522 gtk_dialog_add_button(GTK_DIALOG(dialog), _(
"Cancel"), GTK_RESPONSE_CANCEL);
2523 gtk_dialog_add_button(GTK_DIALOG(dialog), _(
"Save"), GTK_RESPONSE_ACCEPT);
2525 const int response = gtk_dialog_run(GTK_DIALOG(dialog));
2526 gtk_widget_destroy(dialog);
2527 if(response != GTK_RESPONSE_ACCEPT)
2533 _(
"Waiting for the layer rasterization to finish..."));
2541 _(
"Failed to finalize the drawing stroke."),
2542 _(
"The sidecar was not saved."));
2552 _(
"Failed to write the drawing layer sidecar."),
2553 _(
"The sidecar TIFF could not be updated."));
2561 _(
"Drawing sidecar saved."),
2562 _(
"The current in-memory layer has been written to the sidecar TIFF."));
2573 _(
"Enter the name of the new drawing layer."),
2574 "", requested_name,
sizeof(requested_name)))
2596 if(GTK_WIDGET(button) ==
g->controls.preview_bg_white)
2598 else if(GTK_WIDGET(button) ==
g->controls.preview_bg_grey)
2600 else if(GTK_WIDGET(button) ==
g->controls.preview_bg_black)
2620 const float input_wx = isfinite(pointer_input.
x) ? (float)pointer_input.
x : (float)wx;
2621 const float input_wy = isfinite(pointer_input.
y) ? (float)pointer_input.
y : (float)wy;
2626 .pressure = pressure_norm,
2629 .event_ts = g_get_monotonic_time(),
2630 .stroke_batch =
g->stroke.current_stroke_batch,
2631 .event_index = ++
g->stroke.stroke_event_index,
2632 .stroke_pos = stroke_pos,
2644 uint32_t stroke_batch =
g->stroke.current_stroke_batch + 1u;
2645 if(stroke_batch == 0u) stroke_batch++;
2646 const uint32_t event_index = first_input ? first_input->
event_index : 0u;
2650 g->session.pointer_valid =
TRUE;
2651 g->stroke.current_stroke_batch = stroke_batch;
2654 g->stroke.finish_commit_pending =
FALSE;
2655 g->stroke.stroke_sample_count = 0;
2656 g->stroke.stroke_event_index = event_index;
2657 g->stroke.last_dab_valid =
FALSE;
2671 const gboolean flush_pending)
2675 .raw_input_ok =
TRUE,
2684 .manager = &
g->manager,
2685 .process_state = &
g->process,
2697 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
2698 .flush_pending = flush_pending,
2712 _(
"Waiting for the drawing rasterization to finish..."));
2717 _(
"Waiting for the layer rasterization to finish..."));
2729 return C_(
"modulename",
"drawing");
2735 return dt_iop_set_description(self, _(
"paint premultiplied RGB layers in a TIFF sidecar"), _(
"creative"),
2736 _(
"linear, RGB, scene-referred"), _(
"geometric, RGB"),
2737 _(
"linear, RGB, scene-referred"));
2744 const int program = 3;
2763 module->data = NULL;
2788 module->params = calloc(1, sizeof(dt_iop_drawlayer_params_t));
2789 module->default_params = calloc(1, sizeof(dt_iop_drawlayer_params_t));
2790 module->params_size = sizeof(dt_iop_drawlayer_params_t);
2846 _refresh_piece_base_cache(self, data, &data->
params, pipe, piece);
2857 params->layer_name[0] =
'\0';
2858 params->layer_order = -1;
2859 params->sidecar_timestamp = 0;
2860 memset(params->work_profile, 0,
sizeof(params->work_profile));
2865 g->session.missing_layer_error[0] =
'\0';
2871 .manager = &
g->manager,
2872 .process_state = &
g->process,
2883 .event = DT_DRAWLAYER_RUNTIME_EVENT_GUI_RESYNC,
2884 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
2916 &
g->stroke.finish_commit_pending, &
g->stroke.stroke_sample_count,
2917 &
g->stroke.current_stroke_batch);
2918 g->session.background_job_running =
FALSE;
2919 g->session.last_view_x = 0.0f;
2920 g->session.last_view_y = 0.0f;
2921 g->session.last_view_scale = 1.0f;
2933 g->controls.save_layer = gtk_button_new_with_label(_(
"save sidecar"));
2934 gtk_box_pack_start(GTK_BOX(history_box),
g->controls.save_layer,
TRUE,
TRUE, 0);
2948 g->controls.brush_tab = brush_tab;
2949 g->controls.layer_tab = layer_tab;
2950 g->controls.input_tab = input_tab;
2952 gtk_notebook_append_page(GTK_NOTEBOOK(
notebook), brush_tab, gtk_label_new(_(
"Brush")));
2953 gtk_notebook_append_page(GTK_NOTEBOOK(
notebook), layer_tab, gtk_label_new(_(
"Layer")));
2954 gtk_notebook_append_page(GTK_NOTEBOOK(
notebook), input_tab, gtk_label_new(_(
"Input")));
2955 gtk_container_child_set(GTK_CONTAINER(
notebook), brush_tab,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
2956 gtk_container_child_set(GTK_CONTAINER(
notebook), layer_tab,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
2957 gtk_container_child_set(GTK_CONTAINER(
notebook), input_tab,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
2959 GtkWidget *preview_title = gtk_label_new(_(
"Background"));
2960 g->controls.preview_title = preview_title;
2961 gtk_widget_set_halign(preview_title, GTK_ALIGN_START);
2963 g->controls.preview_box = preview_box;
2964 GSList *preview_group = NULL;
2965 g->controls.preview_bg_image = gtk_radio_button_new_with_label(preview_group, _(
"image"));
2966 preview_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(
g->controls.preview_bg_image));
2967 g->controls.preview_bg_white = gtk_radio_button_new_with_label(preview_group, _(
"white"));
2968 preview_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(
g->controls.preview_bg_white));
2969 g->controls.preview_bg_grey = gtk_radio_button_new_with_label(preview_group, _(
"grey"));
2970 preview_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(
g->controls.preview_bg_grey));
2971 g->controls.preview_bg_black = gtk_radio_button_new_with_label(preview_group, _(
"black"));
2972 gtk_box_pack_start(GTK_BOX(preview_box),
g->controls.preview_bg_image,
TRUE,
TRUE, 0);
2973 gtk_box_pack_start(GTK_BOX(preview_box),
g->controls.preview_bg_white,
TRUE,
TRUE, 0);
2974 gtk_box_pack_start(GTK_BOX(preview_box),
g->controls.preview_bg_grey,
TRUE,
TRUE, 0);
2975 gtk_box_pack_start(GTK_BOX(preview_box),
g->controls.preview_bg_black,
TRUE,
TRUE, 0);
2976 gtk_box_pack_start(GTK_BOX(layer_tab), preview_title,
FALSE,
FALSE, 0);
2977 gtk_box_pack_start(GTK_BOX(layer_tab), preview_box,
FALSE,
FALSE, 0);
2985 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.brush_mode,
TRUE,
TRUE, 0);
2987 GtkWidget *color_title = gtk_label_new(_(
"Color"));
2988 gtk_label_set_xalign(GTK_LABEL(color_title), 0.0f);
2990 gtk_box_pack_start(GTK_BOX(brush_tab), color_title,
TRUE,
TRUE, 0);
2991 g->controls.color = gtk_drawing_area_new();
2993 gtk_widget_add_events(
g->controls.color, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK);
2994 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.color,
TRUE,
TRUE, 0);
2996 g->controls.color_swatch = gtk_drawing_area_new();
2998 gtk_widget_add_events(
g->controls.color_swatch, GDK_BUTTON_PRESS_MASK);
2999 gtk_box_pack_start(GTK_BOX(
g->controls.color_row),
g->controls.color_swatch,
TRUE,
TRUE, 0);
3000 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.color_row,
TRUE,
TRUE, 0);
3007 gtk_box_pack_start(GTK_BOX(picker_controls),
g->controls.image_colorpicker,
TRUE,
TRUE, 0);
3008 gtk_box_pack_start(GTK_BOX(picker_controls),
g->controls.image_colorpicker_source,
TRUE,
TRUE, 0);
3009 gtk_box_pack_start(GTK_BOX(brush_tab), picker_controls,
TRUE,
TRUE, 0);
3011 g->controls.hdr_exposure
3015 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.hdr_exposure,
TRUE,
TRUE, 0);
3017 GtkWidget *geometry_title = gtk_label_new(_(
"Geometry"));
3018 gtk_label_set_xalign(GTK_LABEL(geometry_title), 0.0f);
3020 gtk_box_pack_start(GTK_BOX(brush_tab), geometry_title,
TRUE,
TRUE, 0);
3021 GtkWidget *brush_shape_title = gtk_label_new(_(
"Fall-off"));
3022 gtk_label_set_xalign(GTK_LABEL(brush_shape_title), 0.0f);
3023 gtk_box_pack_start(GTK_BOX(brush_tab), brush_shape_title,
TRUE,
TRUE, 0);
3024 g->controls.brush_shape = gtk_drawing_area_new();
3026 gtk_widget_add_events(
g->controls.brush_shape, GDK_BUTTON_PRESS_MASK);
3027 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.brush_shape,
TRUE,
TRUE, 0);
3033 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.size,
TRUE,
TRUE, 0);
3034 g->controls.distance
3038 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.distance,
TRUE,
TRUE, 0);
3039 g->controls.smoothing
3043 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.smoothing,
TRUE,
TRUE, 0);
3044 g->controls.softness
3049 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.softness,
TRUE,
TRUE, 0);
3051 GtkWidget *thickness_title = gtk_label_new(_(
"Thickness"));
3052 gtk_label_set_xalign(GTK_LABEL(thickness_title), 0.0f);
3054 gtk_box_pack_start(GTK_BOX(brush_tab), thickness_title,
TRUE,
TRUE, 0);
3059 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.opacity,
TRUE,
TRUE, 0);
3064 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.flow,
TRUE,
TRUE, 0);
3066 GtkWidget *texture_title = gtk_label_new(_(
"Texture"));
3067 gtk_label_set_xalign(GTK_LABEL(texture_title), 0.0f);
3069 gtk_box_pack_start(GTK_BOX(brush_tab), texture_title,
TRUE,
TRUE, 0);
3070 g->controls.sprinkles
3074 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.sprinkles,
TRUE,
TRUE, 0);
3075 g->controls.sprinkle_size
3079 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.sprinkle_size,
TRUE,
TRUE, 0);
3080 g->controls.sprinkle_coarseness
3084 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.sprinkle_coarseness,
TRUE,
TRUE, 0);
3087 GtkWidget *layer_status = gtk_label_new(
"");
3088 g->controls.layer_status = layer_status;
3089 gtk_widget_set_halign(layer_status, GTK_ALIGN_START);
3090 gtk_label_set_xalign(GTK_LABEL(layer_status), 0.0f);
3091 gtk_label_set_line_wrap(GTK_LABEL(layer_status),
TRUE);
3092 GtkWidget *layer_fill_title = gtk_label_new(_(
"Fill"));
3093 g->controls.layer_fill_title = layer_fill_title;
3094 gtk_widget_set_halign(layer_fill_title, GTK_ALIGN_START);
3096 g->controls.layer_action_row = layer_action_row;
3098 g->controls.layer_fill_row = layer_fill_row;
3101 g->controls.delete_layer = gtk_button_new_with_label(_(
"delete layer"));
3102 g->controls.create_layer = gtk_button_new_with_label(_(
"create new layer"));
3103 g->controls.rename_layer = gtk_button_new_with_label(_(
"rename layer"));
3104 g->controls.attach_layer = gtk_button_new_with_label(_(
"reuse selected layer"));
3105 g->controls.create_background = gtk_button_new_with_label(_(
"create background from input"));
3106 g->controls.fill_white = gtk_button_new_with_label(_(
"white"));
3107 g->controls.fill_black = gtk_button_new_with_label(_(
"black"));
3108 g->controls.fill_transparent = gtk_button_new_with_label(_(
"transparency"));
3109 gtk_box_pack_start(GTK_BOX(layer_box), layer_status,
FALSE,
FALSE, 0);
3110 gtk_box_pack_start(GTK_BOX(layer_box),
g->controls.layer_select,
FALSE,
FALSE, 0);
3111 gtk_box_pack_start(GTK_BOX(layer_action_row),
g->controls.create_layer,
TRUE,
TRUE, 0);
3112 gtk_box_pack_start(GTK_BOX(layer_action_row),
g->controls.rename_layer,
TRUE,
TRUE, 0);
3113 gtk_box_pack_start(GTK_BOX(layer_action_row),
g->controls.attach_layer,
TRUE,
TRUE, 0);
3114 gtk_box_pack_start(GTK_BOX(layer_action_row),
g->controls.delete_layer,
TRUE,
TRUE, 0);
3115 gtk_box_pack_start(GTK_BOX(layer_box), layer_action_row,
FALSE,
FALSE, 0);
3116 gtk_box_pack_start(GTK_BOX(layer_box), layer_fill_title,
FALSE,
FALSE, 0);
3117 gtk_box_pack_start(GTK_BOX(layer_fill_row),
g->controls.fill_white,
TRUE,
TRUE, 0);
3118 gtk_box_pack_start(GTK_BOX(layer_fill_row),
g->controls.fill_black,
TRUE,
TRUE, 0);
3119 gtk_box_pack_start(GTK_BOX(layer_fill_row),
g->controls.fill_transparent,
TRUE,
TRUE, 0);
3120 gtk_box_pack_start(GTK_BOX(layer_box), layer_fill_row,
FALSE,
FALSE, 0);
3121 gtk_box_pack_start(GTK_BOX(layer_box),
g->controls.create_background,
FALSE,
FALSE, 0);
3122 gtk_box_pack_start(GTK_BOX(layer_tab), layer_box,
FALSE,
FALSE, 0);
3124 GtkWidget *mapping_title = gtk_label_new(_(
"tablet mapping"));
3125 gtk_widget_set_halign(mapping_title, GTK_ALIGN_START);
3130 const char *labels[4] = { _(
"size"), _(
"opacity"), _(
"flow"), _(
"hardness") };
3131 const char *rows[3] = { _(
"pressure"), _(
"tilt"), _(
"acceleration") };
3133 { &
g->controls.map_pressure_size, &
g->controls.map_pressure_opacity, &
g->controls.map_pressure_flow, &
g->controls.map_pressure_softness },
3134 { &
g->controls.map_tilt_size, &
g->controls.map_tilt_opacity, &
g->controls.map_tilt_flow, &
g->controls.map_tilt_softness },
3135 { &
g->controls.map_accel_size, &
g->controls.map_accel_opacity, &
g->controls.map_accel_flow, &
g->controls.map_accel_softness },
3137 GtkWidget **profiles[3] = { &
g->controls.pressure_profile, &
g->controls.tilt_profile, &
g->controls.accel_profile };
3139 for(
int c = 0; c < 4; c++)
3141 GtkWidget *label = gtk_label_new(labels[c]);
3142 gtk_label_set_angle(GTK_LABEL(label), 90.0);
3143 gtk_grid_attach(GTK_GRID(grid), label, c + 1, 0, 1, 1);
3145 gtk_grid_attach(GTK_GRID(grid), gtk_label_new(_(
"profile")), 5, 0, 1, 1);
3147 for(
int r = 0;
r < 3;
r++)
3149 gtk_grid_attach(GTK_GRID(grid), gtk_label_new(rows[
r]), 0,
r + 1, 1, 1);
3150 for(
int c = 0; c < 4; c++)
3152 *targets[
r][c] = gtk_check_button_new();
3153 gtk_grid_attach(GTK_GRID(grid), *targets[
r][c], c + 1,
r + 1, 1, 1);
3162 gtk_grid_attach(GTK_GRID(grid), *profiles[
r], 5,
r + 1, 1, 1);
3165 gtk_box_pack_start(GTK_BOX(input_tab), mapping_title,
FALSE,
FALSE, 0);
3166 gtk_box_pack_start(GTK_BOX(input_tab), grid,
FALSE,
FALSE, 0);
3170 g_signal_connect(G_OBJECT(
g->controls.brush_mode),
"value-changed", G_CALLBACK(
_widget_changed), self);
3177 g_signal_connect(G_OBJECT(
g->controls.image_colorpicker_source),
"value-changed", G_CALLBACK(
_widget_changed), self);
3178 g_signal_connect(G_OBJECT(
g->controls.size),
"value-changed", G_CALLBACK(
_widget_changed), self);
3179 g_signal_connect(G_OBJECT(
g->controls.distance),
"value-changed", G_CALLBACK(
_widget_changed), self);
3180 g_signal_connect(G_OBJECT(
g->controls.smoothing),
"value-changed", G_CALLBACK(
_widget_changed), self);
3181 g_signal_connect(G_OBJECT(
g->controls.opacity),
"value-changed", G_CALLBACK(
_widget_changed), self);
3182 g_signal_connect(G_OBJECT(
g->controls.flow),
"value-changed", G_CALLBACK(
_widget_changed), self);
3183 g_signal_connect(G_OBJECT(
g->controls.sprinkles),
"value-changed", G_CALLBACK(
_widget_changed), self);
3184 g_signal_connect(G_OBJECT(
g->controls.sprinkle_size),
"value-changed", G_CALLBACK(
_widget_changed), self);
3185 g_signal_connect(G_OBJECT(
g->controls.sprinkle_coarseness),
"value-changed", G_CALLBACK(
_widget_changed), self);
3186 g_signal_connect(G_OBJECT(
g->controls.softness),
"value-changed", G_CALLBACK(
_widget_changed), self);
3187 g_signal_connect(G_OBJECT(
g->controls.hdr_exposure),
"value-changed", G_CALLBACK(
_widget_changed), self);
3188 g_signal_connect(G_OBJECT(
g->controls.layer_select),
"value-changed", G_CALLBACK(
_layer_selected), self);
3189 g_signal_connect(
g->controls.preview_bg_image,
"toggled", G_CALLBACK(
_preview_bg_toggled), self);
3190 g_signal_connect(
g->controls.preview_bg_white,
"toggled", G_CALLBACK(
_preview_bg_toggled), self);
3191 g_signal_connect(
g->controls.preview_bg_grey,
"toggled", G_CALLBACK(
_preview_bg_toggled), self);
3192 g_signal_connect(
g->controls.preview_bg_black,
"toggled", G_CALLBACK(
_preview_bg_toggled), self);
3203 for(
int r = 0;
r < 3;
r++)
3205 for(
int c = 0; c < 4; c++) g_signal_connect(*targets[
r][c],
"toggled", G_CALLBACK(
_widget_changed), self);
3206 g_signal_connect(G_OBJECT(*profiles[
r]),
"value-changed", G_CALLBACK(
_widget_changed), self);
3219 .manager = &
g->manager,
3220 .process_state = &
g->process,
3231 .event = DT_DRAWLAYER_RUNTIME_EVENT_GUI_RESYNC,
3232 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
3262 if(
g->controls.color) gtk_widget_queue_draw(
g->controls.color);
3264 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_pressure_size))
3265 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_pressure_size),
3267 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_pressure_opacity))
3268 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_pressure_opacity),
3270 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_pressure_flow))
3271 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_pressure_flow),
3273 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_pressure_softness))
3274 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_pressure_softness),
3277 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_tilt_size))
3278 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_tilt_size),
3280 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_tilt_opacity))
3281 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_tilt_opacity),
3283 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_tilt_flow))
3284 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_tilt_flow),
3286 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_tilt_softness))
3287 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_tilt_softness),
3290 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_accel_size))
3291 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_accel_size),
3293 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_accel_opacity))
3294 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_accel_opacity),
3296 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_accel_flow))
3297 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_accel_flow),
3299 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_accel_softness))
3300 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_accel_softness),
3303 if(
g->controls.pressure_profile)
3306 if(
g->controls.accel_profile)
3321 .manager = &
g->manager,
3322 .process_state = &
g->process,
3333 .event = DT_DRAWLAYER_RUNTIME_EVENT_GUI_RESYNC,
3334 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
3346 g->session.missing_layer_error[0] =
'\0';
3352 .manager = &
g->manager,
3353 .process_state = &
g->process,
3376 const int pending_samples =
g ? (int)
g->stroke.stroke_sample_count : 0;
3377 const gboolean had_pending_edits
3378 = (
g && (
g->process.cache_dirty ||
g->stroke.stroke_sample_count > 0));
3384 .manager = &
g->manager,
3385 .process_state = &
g->process,
3399 if(had_pending_edits && params)
3401 g->stroke.last_dab_y, 0u);
3410 if(self->post_history_commit) self->post_history_commit(self);
3423 .manager = &
g->manager,
3424 .process_state = &
g->process,
3467 memset(&
g->session.live_patch, 0,
sizeof(
g->session.live_patch));
3491 const float pressure_norm
3493 const float tilt_norm =
_clamp01((pointer_input && pointer_input->
has_tilt) ? pointer_input->
tilt : 0.0f);
3522 state->pressure = pressure_norm;
3523 state->tilt = tilt_norm;
3524 state->acceleration = accel_norm;
3525 state->radius = fmaxf(0.5f, radius);
3535 char lines[3][128] = { { 0 } };
3536 g_snprintf(lines[0],
sizeof(lines[0]), _(
"size %.1f px hardness %.2f%%"),
state->radius * 2.0f,
3537 state->hardness * 100.0f);
3538 g_snprintf(lines[1],
sizeof(lines[1]), _(
"opacity %.2f%% flow %.2f%%"),
state->opacity * 100.0f,
3539 state->flow * 100.0f);
3540 g_snprintf(lines[2],
sizeof(lines[2]), _(
"pressure %.2f%% tilt %.2f%% acceleration %.2f%%"),
3541 state->pressure * 100.0f,
state->tilt * 100.0f,
state->acceleration * 100.0f);
3548 cairo_select_font_face(cr,
"Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
3549 cairo_set_font_size(cr, fs);
3550 for(
int i = 0;
i < 3;
i++)
3552 cairo_text_extents_t ext = { 0 };
3553 cairo_text_extents(cr, lines[
i], &ext);
3554 max_w = fmax(max_w, ext.x_advance);
3557 const double box_w = max_w + 2.0 * pad;
3558 const double box_h = 3.0 * line_h + 2.0 * pad;
3563 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.55);
3564 cairo_rectangle(cr,
x, y, box_w, box_h);
3567 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.92);
3568 for(
int i = 0;
i < 3;
i++)
3571 cairo_show_text(cr, lines[
i]);
3584 cairo_set_line_width(cr, 1.0);
3585 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.8);
3587 if(
g->session.pointer_valid)
3591 const float widget_x = isfinite(pointer_input.
x)
3592 ? (float)pointer_input.
x
3593 : ((pointerx >= 0 && pointery >= 0) ? (
float)pointerx : -1.0f);
3594 const float widget_y = isfinite(pointer_input.
y)
3595 ? (float)pointer_input.
y
3596 : ((pointerx >= 0 && pointery >= 0) ? (
float)pointery : -1.0f);
3597 if(widget_x < 0.0f || widget_y < 0.0f)
3605 float radius = hud.
radius;
3609 float draw_x = widget_x;
3610 float draw_y = widget_y;
3630 const float draw_radius = fmaxf(0.5f, widget_radius);
3634 if(
g->ui.cursor_surface)
3636 const float surface_half_extent = 0.5f * (float)
g->ui.cursor_surface_size / (
float)
g->ui.cursor_surface_ppd;
3637 cairo_set_source_surface(cr,
g->ui.cursor_surface, draw_x - surface_half_extent, draw_y - surface_half_extent);
3643 cairo_set_source_rgba(cr, 0., 0., 0., 0.5);
3644 cairo_set_line_width(cr, 2.5);
3645 cairo_arc(cr, draw_x, draw_y, draw_radius + 1.0f, 0.0, 2.0 *
M_PI);
3648 cairo_set_source_rgba(cr, 1., 1., 1., 0.5);
3649 cairo_set_line_width(cr, 1.0);
3650 cairo_arc(cr, draw_x, draw_y, draw_radius, 0.0, 2.0 *
M_PI);
3672 .manager = &
g->manager,
3673 .process_state = &
g->process,
3705 .manager = &
g->manager,
3706 .process_state = &
g->process,
3727 if(!
g->session.pointer_valid)
3734 .manager = &
g->manager,
3735 .process_state = &
g->process,
3746 .event = DT_DRAWLAYER_RUNTIME_EVENT_GUI_MOUSE_ENTER,
3747 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
3752 if(
g->manager.painting_active)
3760 .manager = &
g->manager,
3761 .process_state = &
g->process,
3763 .raw_input = &input,
3782 dt_print(
DT_DEBUG_PERF,
"[drawlayer] stroke abort from mouse_moved: dispatch.ok=%d raw_input_ok=%d\n",
3787 .event = DT_DRAWLAYER_RUNTIME_EVENT_GUI_STROKE_ABORT,
3788 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
3800 .manager = &
g->manager,
3801 .process_state = &
g->process,
3817 return g->manager.painting_active ? 1 : 0;
3836 const float input_wx = isfinite(pointer_input.
x) ? (float)pointer_input.
x : (float)
x;
3837 const float input_wy = isfinite(pointer_input.
y) ? (float)pointer_input.
y : (float)y;
3839 uint32_t stroke_batch =
g->stroke.current_stroke_batch + 1u;
3840 if(stroke_batch == 0u) stroke_batch++;
3844 .pressure = pressure_norm,
3847 .event_ts = g_get_monotonic_time(),
3848 .stroke_batch = stroke_batch,
3859 .manager = &
g->manager,
3860 .process_state = &
g->process,
3862 .raw_input = &first,
3890 if(
g->manager.painting_active)
3894 const float input_wx = isfinite(pointer_input.
x) ? (float)pointer_input.
x : (float)
x;
3895 const float input_wy = isfinite(pointer_input.
y) ? (float)pointer_input.
y : (float)y;
3902 .event_ts = g_get_monotonic_time(),
3903 .stroke_batch =
g->stroke.current_stroke_batch,
3904 .event_index = ++
g->stroke.stroke_event_index,
3914 .manager = &
g->manager,
3915 .process_state = &
g->process,
3950 const float factor = increase ? 1.1f : 0.9f;
3963 .manager = &
g->manager,
3964 .process_state = &
g->process,
3987 const gint64 process_t0 = g_get_monotonic_time();
3995 gui ? &gui->
process : NULL, display_pipe, &data->runtime_manager,
3996 &data->runtime_process, &data->runtime_display_pipe);
4002 _refresh_piece_base_cache(self, runtime_data, runtime_params, (
dt_dev_pixelpipe_t *)pipe,
4008 .runtime_params = runtime_params,
4040 gboolean fallback = (runtime_params->
layer_name[0] ==
'\0');
4051 if(!fallback) fallback = !_update_runtime_state(&runtime_request, &source);
4055 const gboolean reuse_device_buffers = realtime;
4058 int source_width = source.
width;
4059 int source_height = source.
height;
4061 const float *source_pixels = source.
pixels;
4065 goto process_cl_fallback;
4080 const gboolean allow_partial = realtime && g_valid && g_devout && g_hash && g_roi;
4083 "[drawlayer] partial gate declined: valid=%d devout=%d hash=%d roi=%d\n",
4084 g_valid, g_devout, g_hash, g_roi);
4088 source_width, source_height, runtime_request.
process_state, &target_roi, &source_roi, direct_copy,
4090 reuse_device_buffers,
FALSE, allow_partial);
4094 if(ok && realtime && !preview_bg.
enabled && layer_hash != 0)
4116 (g_get_monotonic_time() - process_t0) / 1000.0, ok ? 1 : 0);
4124 (g_get_monotonic_time() - process_t0) / 1000.0);
4135 const void *
const ivoid,
void *
const ovoid)
4145 gui ? &gui->
process : NULL, display_pipe, &data->runtime_manager,
4146 &data->runtime_process, &data->runtime_display_pipe);
4152 _refresh_piece_base_cache(self, runtime_data, runtime_params, (
dt_dev_pixelpipe_t *)pipe,
4158 .runtime_params = runtime_params,
4165 .use_opencl =
FALSE,
4183 const float *input = (
const float *)ivoid;
4184 float *output = (
float *)
ovoid;
4185 const size_t pixels = (size_t)roi_out->
width * roi_out->
height;
4186 const gint64 process_t0 = g_get_monotonic_time();
4193 gboolean fallback = (runtime_params->
layer_name[0] ==
'\0');
4197 if(!fallback) fallback = !_update_runtime_state(&runtime_request, &source);
4200 const float *layer_pixels = source.
pixels;
4206 float *layerbuf = NULL;
4209 "drawlayer process scratch");
4217 goto fallback_pass_through;
4226 layer_pixels = layerbuf;
4232 (g_get_monotonic_time() - process_t0) / 1000.0);
4247fallback_pass_through:
4250 (g_get_monotonic_time() - process_t0) / 1000.0);
GtkWidget * dt_gui_main_window(void)
struct dt_ui_t * dt_gui_get_ui(void)
GtkWidget * dt_gui_center_widget(void)
void cleanup(dt_imageio_module_format_t *self)
int dt_bauhaus_combobox_get(GtkWidget *widget)
int dt_bauhaus_combobox_length(GtkWidget *widget)
const char * dt_bauhaus_combobox_get_text(GtkWidget *widget)
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
GtkWidget * dt_bauhaus_slider_new_with_range(dt_bauhaus_t *bh, dt_gui_module_t *self, float min, float max, float step, float defval, int digits)
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
void dt_bauhaus_slider_set_factor(GtkWidget *widget, float factor)
Dab-level brush rasterization API for drawlayer.
@ DT_DRAWLAYER_BRUSH_MODE_PAINT
@ DT_DRAWLAYER_BRUSH_SHAPE_GAUSSIAN
@ DT_DRAWLAYER_BRUSH_SHAPE_LINEAR
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)
@ DT_COLOR_PICKER_POINT_AREA
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)
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
const dt_colormatrix_t dt_aligned_pixel_t out
dt_store_simd_aligned(out, dt_mat3x4_mul_vec4(vin, dt_colormatrix_row_to_simd(matrix, 0), dt_colormatrix_row_to_simd(matrix, 1), dt_colormatrix_row_to_simd(matrix, 2)))
int dt_conf_get_bool(const char *name)
void dt_conf_set_float(const char *name, float val)
void dt_control_get_pointer_input(dt_control_pointer_input_t *input)
void dt_control_log(const char *msg,...)
void dt_control_queue_redraw_center()
Request a redraw of the centre view.
void dt_control_mouse_is_painting(gboolean state)
#define dt_control_set_cursor_visible(visible)
struct dt_control_t * dt_control_get_global(void)
gboolean dt_drawlayer_layer_canvas_for_pipe(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, int *width, int *height)
gboolean dt_drawlayer_raw_placement_for_frame(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_iop_roi_t *const frame, dt_drawlayer_raw_placement_t *placement)
float dt_drawlayer_widget_brush_radius(dt_iop_module_t *self, const dt_drawlayer_brush_dab_t *dab, const float fallback)
gboolean dt_drawlayer_widget_to_layer_coords(dt_iop_module_t *self, const double wx, const double wy, float *lx, float *ly)
Shared coordinate transforms and geometry computations for drawlayer.
struct dt_develop_t * dt_dev_get_global(void)
struct dt_gui_gtk_t * dt_gui_get_global(void)
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
dt_dev_image_geometry_t dt_dev_geometry_snapshot(const dt_develop_t *dev)
gboolean dt_dev_add_history_item_ext(dt_develop_t *dev, struct dt_iop_module_t *module, gboolean enable, gboolean force_new_item) REQUIRES(dev -> history_mutex)
Append or update a history item for a module.
uint64_t dt_dev_history_compute_hash(dt_develop_t *dev) REQUIRES_SHARED(dev -> history_mutex)
Get the integrity checksum of the whole history stack. This should be done ONLY when history is chang...
void dt_dev_write_history(dt_develop_t *dev, gboolean async)
Thread-safe wrapper around dt_dev_write_history_ext() for dev->image_storage.id.
void dt_dev_history_notify_change(dt_develop_t *dev, const int32_t imgid)
Notify the rest of the app that history changes were written.
#define dt_dev_add_history_item(dev, module, enable, redraw)
#define dt_dev_pixelpipe_update_history_all(dev)
float dt_dev_viewport_center_y(const dt_develop_t *dev)
float dt_dev_viewport_center_x(const dt_develop_t *dev)
float dt_dev_viewport_scaling(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_CLONE_TARGETS__ dt_iop_order_iccprofile_info_t * dt_ioppr_get_iop_work_profile_info(struct dt_iop_module_t *module, GList *iop_list)
dt_dev_pixelpipe_iop_t * dt_dev_distort_get_iop_pipe(struct dt_dev_pixelpipe_t *pipe, struct dt_iop_module_t *module)
float dt_dev_get_overlay_scale(dt_develop_t *dev)
Get the overlay scale factor in GUI logical coordinates.
void dt_dev_undo_start_record(dt_develop_t *dev)
void dt_dev_undo_end_record(dt_develop_t *dev)
static void dt_dev_set_history_hash(dt_develop_t *dev, const uint64_t history_hash)
GtkWidget * geometry
its size, under the preview
static gboolean _rekey_shared_base_patch(drawlayer_patch_t *patch, const int32_t imgid, const dt_iop_drawlayer_params_t *params)
static void _retain_base_patch_loaded_ref(dt_iop_drawlayer_gui_data_t *g)
void init(dt_iop_module_t *module)
Allocate and initialize module parameter blocks.
static void _sanitize_requested_layer_name(const char *requested, char *name, size_t name_size)
void dt_drawlayer_touch_stroke_commit_hash(dt_iop_drawlayer_params_t *params, const int dab_count, const gboolean have_last_dab, const float last_dab_x, const float last_dab_y, const uint32_t publish_serial)
const char ** description(struct dt_iop_module_t *self)
Module description strings used by UI/help.
#define _set_drawlayer_pipeline_realtime_mode
int default_group()
Return default iop group for drawlayer module.
gboolean dt_drawlayer_flush_layer_cache(dt_iop_module_t *self)
static void _draw_brush_hud(cairo_t *cr, const drawlayer_hud_brush_state_t *state)
void gui_reset(dt_iop_module_t *self)
Reset GUI/session state for current drawlayer instance.
static gboolean _confirm_delete_layer(dt_iop_module_t *self, const gboolean removing_module)
static gboolean _background_layer_job_done_idle(gpointer user_data)
#define _drawlayer_wait_for_rasterization_modal
static drawlayer_process_scratch_t * _get_process_scratch(void)
void dt_drawlayer_show_runtime_feedback(const dt_iop_drawlayer_gui_data_t *g, const dt_drawlayer_runtime_feedback_t feedback)
static void _preview_bg_toggled(GtkToggleButton *button, gpointer user_data)
#define _flush_layer_cache
int mouse_leave(dt_iop_module_t *self)
Mouse leave handler.
static gboolean _apply_selected_layer_attachment(dt_iop_module_t *self, dt_iop_drawlayer_gui_data_t *g, dt_iop_drawlayer_params_t *params, const char *layer_name, const int layer_order)
Apply one selected on-disk layer from the combobox to module params/history.
static gboolean _fill_current_layer(dt_iop_module_t *self, const float value)
gboolean dt_drawlayer_sync_widget_cache(dt_iop_module_t *self)
void gui_focus(dt_iop_module_t *self, gboolean in)
Focus transition hook (enter/leave) for drawlayer GUI mode.
static int _drawlayer_run_premult_over_kernel(const int devid, const int kernel_premult_over, cl_mem dev_background, cl_mem dev_layer_rgba, cl_mem dev_out, const int width, const int height, const int background_offset_x, const int background_offset_y)
static gboolean _color_picker_set_from_position(dt_iop_module_t *self, const float x, const float y)
void gui_update(dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
static void _attach_selected_layer_clicked(GtkButton *button, gpointer user_data)
__DT_CLONE_TARGETS__ int process(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
CPU processing path for layer-over-input compositing.
static dt_drawlayer_runtime_result_t _update_gui_runtime_manager(dt_iop_module_t *self, dt_iop_drawlayer_gui_data_t *g, dt_drawlayer_runtime_event_t event, gboolean flush_pending)
int button_pressed(dt_iop_module_t *self, double x, double y, double pressure, int which, int type, uint32_t state)
Button press handler (starts stroke capture on left button).
static gboolean _color_picker_motion(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
static gboolean _prompt_layer_name_dialog(const char *title, const char *message, const char *initial_name, char *name, size_t name_size)
static void _fill_transparent_clicked(GtkButton *button, gpointer user_data)
#define _release_all_base_patch_extra_refs
void dt_drawlayer_begin_gui_stroke_capture(dt_iop_module_t *self, const dt_drawlayer_paint_raw_input_t *first_input)
static void _show_drawlayer_modal_message(const GtkMessageType type, const char *primary, const char *secondary)
static void _destroy_process_scratch(gpointer data)
static void _create_layer_clicked(GtkButton *button, gpointer user_data)
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
void dt_drawlayer_release_all_base_patch_extra_refs(dt_iop_drawlayer_gui_data_t *g)
static int64_t _sidecar_timestamp_from_path(const char *path)
static void _save_layer_clicked(GtkButton *button, gpointer user_data)
static gboolean _get_current_work_profile_key(dt_iop_module_t *self, GList *iop_list, dt_dev_pixelpipe_t *pipe, char *key, const size_t key_size)
static void _layer_selected(GtkWidget *widget, gpointer user_data)
static gboolean _drawlayer_sync_host_image_to_device(const int devid, cl_mem device_image, void *host_pixels, const int width, const int height, const int bpp, const dt_drawlayer_damaged_rect_t *dirty_rect)
static gboolean _brush_profile_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
static void _build_pre_module_filter_string(dt_iop_module_t *self, char *filter, const size_t filter_size)
const char * name()
Module display name.
static void _sync_brush_profile_preview_widget(dt_iop_module_t *self)
static void _widget_changed(GtkWidget *widget, gpointer user_data)
static void _brush_pipeline_color_from_display(dt_iop_module_t *self, const float display_rgb[3], float pipeline_rgb[3])
Convert one display-space brush color snapshot to pipeline space.
static gboolean _clear_current_layer(dt_iop_module_t *self)
static void _sync_cached_brush_colors(dt_iop_module_t *self, const float display_rgb[3])
Cache brush colors in GUI state so stroke input snapshots don't re-transform per event.
int scrolled(dt_iop_module_t *self, double x, double y, int up, uint32_t state)
Scroll handler used for interactive brush-size changes.
gboolean dt_drawlayer_commit_dabs(dt_iop_module_t *self, gboolean record_history)
void quiesce(dt_iop_module_t *self)
Destroy GUI resources and stop background worker.
void gui_init(dt_iop_module_t *self)
Build GUI widgets and initialize worker/caches.
static int _drawlayer_copy_or_resample_layer_roi(const int devid, cl_mem dev_source_rgba, cl_mem dev_layer_rgba, const int source_w, const int source_h, const dt_iop_roi_t *const target_roi, const dt_iop_roi_t *const source_roi)
static gboolean _create_background_layer_from_input(dt_iop_module_t *self)
void dt_drawlayer_set_pipeline_realtime_mode(dt_iop_module_t *self, gboolean state)
static drawlayer_wait_dialog_t _show_drawlayer_wait_dialog(const char *title, const char *message)
static void _rename_layer_clicked(GtkButton *button, gpointer user_data)
static gboolean _color_picker_button_release(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
static gboolean _color_swatch_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
#define _touch_stroke_commit_hash
static gboolean _drawlayer_acquire_layer_image(const int devid, dt_pixel_cache_entry_t *resolved_entry, const gboolean realtime_reuse, const gboolean direct_copy, cl_mem dev_source_rgba, const int source_w, const int source_h, const dt_iop_roi_t *const target_roi, const dt_iop_roi_t *const source_roi, drawlayer_cl_image_handle_t *layer, int *err)
static gboolean _color_picker_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
void gui_cleanup(dt_iop_module_t *self)
static int _blend_layer_over_input_cl(const int devid, const int kernel_premult_over, cl_mem dev_out, cl_mem dev_in, drawlayer_process_scratch_t *scratch, const float *layer_pixels, dt_pixel_cache_entry_t *source_entry, cl_mem source_mem_override, const int source_w, const int source_h, dt_drawlayer_process_state_t *process, const dt_iop_roi_t *const target_roi, const dt_iop_roi_t *const source_roi, const gboolean direct_copy, const gboolean use_preview_bg, const float preview_bg, const gboolean realtime_reuse, const gboolean force_device_copy, const gboolean allow_partial)
#define _drawlayer_runtime_perform_action
static gboolean _drawlayer_modal_wait_tick(gpointer user_data)
static void _sync_preview_bg_buttons(dt_iop_module_t *self)
static gboolean _delete_current_layer(dt_iop_module_t *self)
void cleanup_global(dt_iop_module_so_t *module)
Release global OpenCL resources for drawlayer.
gboolean module_will_remove(dt_iop_module_t *self)
Hook called before module removal from history stack.
static gboolean _drawlayer_map_source_damage_to_target(const dt_drawlayer_damaged_rect_t *src_damage, const dt_iop_roi_t *const target_roi, const dt_iop_roi_t *const source_roi, dt_drawlayer_damaged_rect_t *out)
static gboolean _drawlayer_acquire_source_image(const int devid, const float *layer_pixels, dt_pixel_cache_entry_t *resolved_entry, const gboolean force_device_copy, const gboolean realtime_reuse, const int source_w, const int source_h, dt_drawlayer_process_state_t *process, drawlayer_cl_image_handle_t *source)
int mouse_moved(dt_iop_module_t *self, double x, double y, double pressure, int which)
Mouse motion handler.
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Return default colorspace expected by drawlayer process paths.
static gboolean _color_swatch_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
int flags()
Return module capability flags.
static gboolean _working_rgb_to_display_rgb(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const float working_rgb[3], float display_rgb[3])
static gboolean _profile_key_is_sane(const char *value)
static gboolean _color_picker_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
int button_released(dt_iop_module_t *self, double x, double y, int which, uint32_t state)
Button release handler (ends current stroke).
#define _layer_to_widget_coords
static gboolean _create_new_layer(dt_iop_module_t *self, const char *requested_name)
void commit_params(dt_iop_module_t *self, dt_iop_params_t *params, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Commit params to runtime piece and refresh base cache state.
void change_image(dt_iop_module_t *self)
Invalidate module state when active image changes.
static void _develop_ui_pipe_finished_callback(gpointer instance, gpointer user_data)
#define _drawlayer_runtime_collect_inputs
static void _create_background_clicked(GtkButton *button, gpointer user_data)
void dt_drawlayer_wait_for_rasterization_modal(const dt_iop_drawlayer_gui_data_t *g, const char *title, const char *message)
dt_drawlayer_runtime_context_t drawlayer_runtime_host_context_t
static gboolean _brush_profile_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
static GPrivate _drawlayer_process_scratch_key
static __DT_CLONE_TARGETS__ void _blend_layer_over_input(float *output, const float *input, const float *layerbuf, const size_t pixels, const gboolean use_preview_bg, const float preview_bg)
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Cleanup per-pipe runtime data.
void gui_post_expose(dt_iop_module_t *self, cairo_t *cr, int32_t width, int32_t height, int32_t pointerx, int32_t pointery)
Draw post-expose overlay (cursor, HUD, temp preview).
static void _fill_black_clicked(GtkButton *button, gpointer user_data)
dt_drawlayer_runtime_request_t drawlayer_runtime_request_t
void dt_drawlayer_end_gui_stroke_capture(dt_iop_module_t *self)
static void _sync_layer_controls(dt_iop_module_t *self)
static void _fill_input_layer_coords(dt_iop_module_t *self, dt_drawlayer_paint_raw_input_t *input)
static gboolean _layer_name_non_empty(const char *name)
static void _fill_input_brush_settings(dt_iop_module_t *self, dt_drawlayer_paint_raw_input_t *input)
void init_global(dt_iop_module_so_t *module)
Initialize global OpenCL resources for drawlayer kernels.
static gboolean _rename_current_layer_from_gui(dt_iop_module_t *self, const char *requested_name)
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)
OpenCL processing path for layer-over-input compositing.
#define DRAWLAYER_RESAMPLE_DAMAGE_MARGIN
static void _compute_hud_brush_state(const dt_control_pointer_input_t *pointer_input, drawlayer_hud_brush_state_t *state)
#define _ensure_layer_cache
void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Apply selected picker color to drawlayer brush color.
static void _sync_mode_sensitive_widgets(dt_iop_module_t *self)
static void _fill_white_clicked(GtkButton *button, gpointer user_data)
static void _sanitize_params(dt_iop_module_t *self, dt_iop_drawlayer_params_t *params)
static void _ensure_cursor_stamp_surface(dt_iop_module_t *self, const float widget_radius, const float opacity, const float hardness)
static gboolean _build_raw_input_event(dt_iop_module_t *self, const double wx, const double wy, const double pressure, const dt_drawlayer_paint_stroke_pos_t stroke_pos, dt_drawlayer_paint_raw_input_t *input)
static void _refresh_layer_widgets(dt_iop_module_t *self)
static void _retain_base_patch_stroke_ref(dt_iop_drawlayer_gui_data_t *g)
static void _delete_layer_clicked(GtkButton *button, gpointer user_data)
static int dt_pthread_rwlock_wrlock(dt_pthread_rwlock_t *rwlock) ACQUIRE(rwlock) NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_rwlock_unlock(dt_pthread_rwlock_t *rwlock) RELEASE_GENERIC(rwlock) NO_THREAD_SAFETY_ANALYSIS
static uint64_t dt_hash(uint64_t hash, const char *str, size_t size)
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)
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
void dt_iop_gui_leave_critical_section(dt_iop_module_t *const module)
Release what dt_iop_gui_enter_critical_section() took. Also a no-op headless.
void dt_iop_request_focus(dt_iop_module_t *module)
Move darkroom focus to module, or clear it with NULL.
@ IOP_FLAGS_SUPPORTS_BLENDING
void dt_iop_gui_enter_critical_section(dt_iop_module_t *const module)
Take the module's GUI lock, serialising access to its dt_iop_gui_data_t.
gboolean dt_mask_scroll_increases(int up)
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)
int dt_iop_clip_and_zoom_roi_cl(int devid, cl_mem dev_out, cl_mem dev_in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in)
const struct dt_interpolation * dt_interpolation_new(enum dt_interpolation_type type)
void dt_interpolation_resample(const struct dt_interpolation *itor, float *out, const dt_iop_roi_t *const roi_out, const float *const in, const dt_iop_roi_t *const roi_in)
int dt_interpolation_resample_cl(const struct dt_interpolation *itor, const int devid, cl_mem dev_out, const dt_iop_roi_t *const roi_out, cl_mem dev_in, const dt_iop_roi_t *const roi_in)
@ DT_INTERPOLATION_BILINEAR
int32_t dt_drawlayer_io_background_layer_job_run(dt_job_t *job)
Worker entrypoint for async "create background from input" sidecar jobs.
gboolean dt_drawlayer_io_layer_name_exists(const char *path, const char *candidate, const int ignore_index)
Test if a layer name already exists in sidecar TIFF.
gboolean dt_drawlayer_io_find_layer(const char *path, const char *target_name, const int target_order, dt_drawlayer_io_layer_info_t *info)
Find target layer metadata in sidecar TIFF.
gboolean dt_drawlayer_io_sidecar_path(const int32_t imgid, char *path, const size_t path_size)
Build absolute sidecar path from image id.
gboolean dt_drawlayer_io_rename_layer(const char *path, const char *current_name, const char *new_name, const char *work_profile, const int layer_width, const int layer_height, dt_drawlayer_io_layer_info_t *info)
Rename one existing layer page while preserving its directory payload.
gboolean dt_drawlayer_io_load_layer(const char *path, const char *target_name, const int target_order, const int layer_width, const int layer_height, dt_drawlayer_io_patch_t *patch)
Load one sidecar layer patch into float RGBA destination patch.
gboolean dt_drawlayer_io_delete_layer(const char *path, const char *target_name, const int layer_width, const int layer_height)
Delete one existing layer page from the sidecar TIFF.
TIFF sidecar I/O API for drawlayer layers.
static float _clamp01(const float v)
Clamp scalar to [0,1].
gboolean dt_drawlayer_brush_rasterize_dab_argb8(const dt_drawlayer_brush_dab_t *dab, uint8_t *argb, const int width, const int height, const int stride, const float center_x, const float center_y, const float opacity_multiplier)
Render one dab to 8-bit ARGB surface for GUI cursor preview.
Patch/cache helpers for drawlayer process and preview buffers.
Drawlayer configuration read/write helpers (private include unit).
static float _conf_smoothing(void)
Read and clamp configured smoothing parameter (%).
#define DRAWLAYER_CONF_MAP_TILT_SIZE
static void _ensure_gui_conf_defaults(void)
Ensure all drawlayer GUI config keys exist with sane defaults.
static float _conf_sprinkle_coarseness(void)
Read and clamp configured sprinkle octave mix (%).
static drawlayer_mapping_profile_t _conf_mapping_profile(const char *key)
Read and clamp one mapping-profile enum key.
static float _conf_hardness(void)
Derive hardness as complementary value of softness.
static float _conf_flow(void)
Read and clamp configured flow (%).
static float _conf_size(void)
Read and clamp configured brush size (px).
static void _conf_display_color(float rgb[3])
Read configured display RGB brush color.
#define DRAWLAYER_CONF_MAP_PRESSURE_SIZE
static float _conf_sprinkles(void)
Read and clamp configured sprinkles amount (%).
#define DRAWLAYER_CONF_ACCEL_PROFILE
static void _remember_display_color(dt_iop_module_t *self, const float display_rgb[3])
Push current display color to history and trigger swatch redraw.
static float _conf_opacity(void)
Read and clamp configured stroke opacity (%).
#define DRAWLAYER_CONF_MAP_PRESSURE_SOFTNESS
#define DRAWLAYER_CONF_PRESSURE_PROFILE
#define DRAWLAYER_CONF_MAP_TILT_FLOW
static float _conf_distance(void)
Read and clamp configured distance/sampling parameter (%).
#define DRAWLAYER_CONF_MAP_ACCEL_FLOW
static drawlayer_pick_source_t _conf_pick_source(void)
Read and clamp color picker source selector.
#define DRAWLAYER_CONF_MAP_ACCEL_SIZE
#define DRAWLAYER_CONF_MAP_PRESSURE_OPACITY
#define DRAWLAYER_CONF_SIZE
static void _sync_color_picker_from_conf(dt_iop_module_t *self)
Refresh picker widgets from persisted config color.
#define DRAWLAYER_CONF_MAP_TILT_SOFTNESS
#define DRAWLAYER_CONF_TILT_PROFILE
#define DRAWLAYER_CONF_MAP_ACCEL_OPACITY
static void _load_color_history(dt_iop_drawlayer_gui_data_t *g)
Load persisted color-history stack from config into widgets state.
static dt_iop_drawlayer_brush_shape_t _conf_brush_shape(void)
Read and clamp configured brush shape.
static void _sync_params_from_gui(dt_iop_module_t *self, const gboolean record_history)
Sync active GUI widget values back into persistent config keys.
#define DRAWLAYER_CONF_MAP_PRESSURE_FLOW
static float _conf_hdr_exposure(void)
Read and clamp HDR picker exposure compensation (EV).
#define DRAWLAYER_CONF_MAP_TILT_OPACITY
#define DRAWLAYER_CONF_MAP_ACCEL_SOFTNESS
static float _conf_sprinkle_size(void)
Read and clamp configured sprinkle feature size (px).
static dt_iop_drawlayer_brush_mode_t _conf_brush_mode(void)
Read and clamp configured brush blend mode.
static void _apply_display_brush_color(dt_iop_module_t *self, const float display_rgb[3], const gboolean remember)
Apply display-space brush color to conf, widgets and redraw.
Private drawlayer module types and lightweight shared helpers.
static float _mapping_profile_value(const drawlayer_mapping_profile_t profile, const float x)
@ DRAWLAYER_INPUT_MAP_ACCEL_SIZE
@ DRAWLAYER_INPUT_MAP_ACCEL_FLOW
@ DRAWLAYER_INPUT_MAP_PRESSURE_SOFTNESS
@ DRAWLAYER_INPUT_MAP_TILT_SOFTNESS
@ DRAWLAYER_INPUT_MAP_TILT_OPACITY
@ DRAWLAYER_INPUT_MAP_PRESSURE_OPACITY
@ DRAWLAYER_INPUT_MAP_TILT_FLOW
@ DRAWLAYER_INPUT_MAP_ACCEL_OPACITY
@ DRAWLAYER_INPUT_MAP_TILT_SIZE
@ DRAWLAYER_INPUT_MAP_PRESSURE_FLOW
@ DRAWLAYER_INPUT_MAP_ACCEL_SOFTNESS
@ DRAWLAYER_INPUT_MAP_PRESSURE_SIZE
drawlayer_mapping_profile_t
@ DRAWLAYER_PREVIEW_BG_WHITE
@ DRAWLAYER_PREVIEW_BG_IMAGE
@ DRAWLAYER_PREVIEW_BG_BLACK
@ DRAWLAYER_PREVIEW_BG_GREY
@ DRAWLAYER_PICK_SOURCE_OUTPUT
void dt_drawlayer_paint_runtime_state_reset(dt_drawlayer_damaged_rect_t *state)
Reset stroke-damage accumulator to empty/invalid.
Stroke-level path sampling and runtime-state API for drawlayer.
dt_drawlayer_paint_stroke_pos_t
Position of a raw input event inside a stroke lifecycle.
@ DT_DRAWLAYER_PAINT_STROKE_MIDDLE
@ DT_DRAWLAYER_PAINT_STROKE_FIRST
@ DT_DRAWLAYER_PAINT_STROKE_END
dt_job_t * dt_control_job_create(dt_job_execute_callback execute, const char *msg,...)
int dt_control_add_job(dt_control_t *control, dt_job_queue_t queue_id, _dt_job_t *job)
void dt_control_job_add_progress(dt_job_t *job, const char *message, gboolean cancellable)
void dt_control_job_set_params(_dt_job_t *job, void *params, dt_job_destroy_callback callback)
Private drawlayer layer cache, sidecar sync and widget cache state.
static void _layerio_log_errors(GString *errors)
static void _reset_stroke_session(dt_iop_drawlayer_gui_data_t *g)
static void _populate_layer_list(dt_iop_module_t *self)
static void _layerio_append_error(GString *errors, const char *message)
_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
#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.
#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.
void dt_ui_notebook_set_picker_owner(GtkNotebook *notebook, gpointer owner)
Register an opaque owner for a GtkNotebook's page switches, and report every "switch_page" to the hos...
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
void * dt_opencl_alloc_device_use_host_pointer(const int devid, const int width, const int height, const int bpp, void *host, const int flags)
gboolean dt_opencl_is_pinned_memory(cl_mem mem)
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
int dt_opencl_create_kernel(const int prog, const char *name)
int dt_opencl_enqueue_copy_image(const int devid, cl_mem src, cl_mem dst, size_t *orig_src, size_t *orig_dst, size_t *region)
int dt_opencl_unmap_mem_object(const int devid, cl_mem mem_object, void *mapped_ptr)
void dt_opencl_free_kernel(const int kernel)
void * dt_opencl_map_image(const int devid, cl_mem buffer, const int blocking, const int flags, size_t width, size_t height, int bpp)
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
gboolean dt_opencl_finish(const int devid)
void * dt_opencl_copy_host_to_device(const int devid, void *host, const int width, const int height, const int bpp)
int dt_opencl_write_host_to_device_raw(const int devid, const void *host, void *device, const size_t *origin, const size_t *region, const int rowpitch, const int blocking)
void dt_opencl_release_mem_object(cl_mem mem)
int dt_opencl_write_host_to_device(const int devid, void *host, void *device, const int width, const int height, const int bpp)
#define __OMP_PARALLEL_FOR__(...)
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
void * dt_dev_pixelpipe_cache_get_pinned_image(void *host_ptr, dt_pixel_cache_entry_t *entry_hint, int devid, int width, int height, int bpp, int flags, gboolean *out_reused)
Acquire a pinned OpenCL image for a host buffer tracked by the pixelpipe cache.
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_release_cl_buffer(void **cl_mem_buffer, dt_pixel_cache_entry_t *cache_entry, void *host_ptr, const gboolean cache_device)
Release or cache an OpenCL image associated with a host cache line.
void dt_dev_pixelpipe_cache_put_pinned_image(void *host_ptr, dt_pixel_cache_entry_t *entry_hint, void **mem)
Release or cache a pinned OpenCL image acquired with dt_dev_pixelpipe_cache_get_pinned_image().
void * dt_dev_pixelpipe_cache_get_cl_buffer(int devid, void *const host_ptr, const dt_iop_roi_t *roi, const size_t bpp, dt_iop_module_t *module, const char *message, dt_pixel_cache_entry_t *cache_entry, gboolean *out_reused, void *keep)
gboolean dt_dev_pixelpipe_cache_flush_host_pinned_image(void *host_ptr, dt_pixel_cache_entry_t *entry_hint, int devid)
Drop cached pinned OpenCL images associated with a given host buffer.
int dt_dev_pixelpipe_cache_rekey(const uint64_t old_hash, const uint64_t new_hash, dt_pixel_cache_entry_t *entry)
Change the hash/key of an existing cache line in place, without freeing, reallocating or invalidating...
dt_pixel_cache_entry_t * dt_dev_pixelpipe_cache_ref_entry_for_host_ptr(void *host_ptr)
Resolve and retain the cache entry owning a host pointer.
Pixelpipe cache for storing intermediate results in the pixelpipe.
gboolean dt_dev_pixelpipe_get_realtime(const dt_dev_pixelpipe_t *pipe)
void dt_drawlayer_runtime_manager_bind_piece(dt_drawlayer_runtime_manager_t *headless_manager, dt_drawlayer_process_state_t *headless_process, dt_drawlayer_runtime_manager_t *gui_manager, dt_drawlayer_process_state_t *gui_process, const gboolean display_pipe, dt_drawlayer_runtime_manager_t **runtime_manager, dt_drawlayer_process_state_t **runtime_process, gboolean *runtime_display_pipe)
void dt_drawlayer_runtime_manager_cleanup(dt_drawlayer_runtime_manager_t *state)
void dt_drawlayer_runtime_manager_init(dt_drawlayer_runtime_manager_t *state)
dt_drawlayer_runtime_result_t dt_drawlayer_runtime_manager_update(dt_drawlayer_runtime_manager_t *state, const dt_drawlayer_runtime_update_request_t *request, const dt_drawlayer_runtime_host_t *host)
void dt_drawlayer_process_state_init(dt_drawlayer_process_state_t *state)
void dt_drawlayer_ui_cursor_clear(dt_drawlayer_ui_state_t *state)
void dt_drawlayer_process_state_cleanup(dt_drawlayer_process_state_t *state)
void dt_drawlayer_runtime_manager_note_buffer_lock(dt_drawlayer_runtime_manager_t *state, const dt_drawlayer_runtime_buffer_t buffer, const dt_drawlayer_runtime_actor_t actor, const gboolean write_lock, const gboolean acquire)
void dt_drawlayer_process_state_invalidate(dt_drawlayer_process_state_t *state)
Private runtime state/helpers shared by drawlayer module entrypoints.
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_STROKE_BEGIN
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_STROKE_END
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_SAMPLE
@ DT_DRAWLAYER_SOURCE_BASE_PATCH
@ DT_DRAWLAYER_RUNTIME_ACTOR_PIPELINE_CPU
@ DT_DRAWLAYER_RUNTIME_ACTOR_PIPELINE_CL
@ DT_DRAWLAYER_RUNTIME_BUFFER_BASE_PATCH
dt_drawlayer_runtime_event_t
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_FOCUS_GAIN
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CPU_AFTER
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_SCROLL
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CL_BEFORE
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CL_AFTER
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_CHANGE_IMAGE
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_RAW_INPUT
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CPU_BEFORE
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_MOUSE_LEAVE
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_STROKE_ABORT
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_FOCUS_LOSS
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_SYNC_TEMP_BUFFERS
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
struct dt_control_signal_t * dt_control_signal_get_global(void)
@ DT_SIGNAL_DEVELOP_UI_PIPE_FINISHED
This signal is raised when pipe is finished and the gui is attached no param, no returned value.
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Apply one channel's tone curve to each of the three colour channels, or pass the channel through unto...
static const dt_aligned_pixel_simd_t value
float * dt_drawlayer_cache_ensure_scratch_buffer(float **buffer, size_t *capacity_pixels, const size_t needed_pixels, const char *name)
Ensure scratch RGBA float capacity in pixels.
void dt_drawlayer_cache_patch_wrunlock(const dt_drawlayer_cache_patch_t *patch)
Release write lock on shared patch cache entry.
void dt_drawlayer_cache_patch_wrlock(const dt_drawlayer_cache_patch_t *patch)
Acquire write lock on shared patch cache entry.
void dt_drawlayer_cache_patch_clear(dt_drawlayer_cache_patch_t *patch, const char *external_alloc_name)
Release patch storage and reset patch metadata.
gboolean dt_drawlayer_cache_patch_alloc_shared(dt_drawlayer_cache_patch_t *patch, const uint64_t hash, const size_t pixel_count, const int width, const int height, const char *name, int *created_out)
Allocate patch storage from shared pixel cache entry.
void dt_drawlayer_cache_free_temp_buffer(void **buffer, const char *name)
Free temporary aligned cache buffer.
void dt_drawlayer_cache_patch_rdlock(const dt_drawlayer_cache_patch_t *patch)
Acquire read lock on shared patch cache entry.
void dt_drawlayer_cache_patch_rdunlock(const dt_drawlayer_cache_patch_t *patch)
Release read lock on shared patch cache entry.
void dt_drawlayer_cache_clear_transparent_float(float *pixels, const size_t pixel_count)
Fill float RGBA buffer with transparent black.
Shared drawlayer runtime helpers used across module/runtime files.
#define DRAWLAYER_NAME_SIZE
dt_drawlayer_runtime_feedback_t
@ DT_DRAWLAYER_RUNTIME_FEEDBACK_NONE
@ DT_DRAWLAYER_RUNTIME_FEEDBACK_FOCUS_LOSS_WAIT
@ DT_DRAWLAYER_RUNTIME_FEEDBACK_SAVE_WAIT
#define DRAWLAYER_PROFILE_SIZE
const float uint32_t state[4]
unsigned __int64 uint64_t
gboolean is_cached_device
char work_profile[DRAWLAYER_PROFILE_SIZE]
char name[DRAWLAYER_NAME_SIZE]
const dt_iop_drawlayer_gui_data_t * g
size_t cl_background_rgba_pixels
float * flush_update_rgba
float * cl_background_rgba
size_t flush_update_rgba_pixels
Objective facts about the image a dev is working on.
struct dt_iop_module_t *void * data
struct dt_develop_t * dev
struct dt_iop_module_t * gui_module
dt_pthread_rwlock_t history_mutex
struct dt_dev_pixelpipe_t * preview_pipe
struct dt_masks_form_gui_t * form_gui
struct dt_dev_pixelpipe_t * pipe
Fully resolved input dab descriptor.
Generic float RGBA patch stored either in malloc memory or pixel cache.
dt_pixel_cache_entry_t * cache_entry
Integer axis-aligned rectangle in buffer coordinates.
Parameters owned by the async "create background from input" job.
char initiator_layer_name[64]
int initiator_layer_order
char sidecar_path[DT_PATH_MAX]
char requested_bg_name[64]
Result posted back to the UI after background-layer creation.
int initiator_layer_order
char initiator_layer_name[64]
int64_t sidecar_timestamp
Metadata returned when probing one layer directory in sidecar TIFF.
Float RGBA patch used by drawlayer I/O routines.
uint64_t last_composite_layer_hash
void * last_composite_dev_out
dt_drawlayer_cache_patch_t base_patch
char cache_layer_name[DRAWLAYER_NAME_SIZE]
gboolean last_composite_valid
dt_iop_roi_t last_composite_target_roi
dt_drawlayer_damaged_rect_t cache_dirty_rect
Where the raw-anchored layer canvas sits in this module's own frame.
dt_drawlayer_runtime_request_t runtime
dt_drawlayer_process_state_t * process
const dt_iop_drawlayer_params_t * runtime_params
const dt_iop_roi_t * roi_in
const dt_dev_pixelpipe_t * pipe
dt_drawlayer_process_state_t * process_state
const dt_iop_roi_t * roi_out
dt_dev_pixelpipe_iop_t * piece
dt_drawlayer_runtime_manager_t * manager
dt_drawlayer_runtime_buffer_t tracked_buffer
gboolean tracked_read_lock
dt_drawlayer_runtime_source_kind_t kind
dt_pixel_cache_entry_t * cache_entry
dt_drawlayer_runtime_actor_t tracked_actor
dt_drawlayer_runtime_event_t event
dt_drawlayer_runtime_release_t release
dt_drawlayer_process_state_t * runtime_process
dt_drawlayer_process_state_t process
dt_drawlayer_runtime_manager_t headless_manager
dt_iop_drawlayer_params_t params
dt_drawlayer_runtime_manager_t * runtime_manager
gboolean runtime_display_pipe
dt_drawlayer_process_state_t process
dt_drawlayer_session_state_t session
dt_drawlayer_runtime_manager_t manager
dt_iop_global_data_t * data
dt_dev_request_colorpick_flags_t request_color_pick
dt_iop_params_t * default_params
dt_aligned_pixel_t picked_output_color_min
struct dt_iop_module_gui_t * gui
struct dt_develop_t * dev
dt_aligned_pixel_t picked_output_color_max
dt_iop_global_data_t * global_data
dt_aligned_pixel_t picked_output_color
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,...
dt_iop_color_intent_t intent
Rendering intent, passed to cmsCreateTransform on the lcms2 fallback only. The matrix path ignores it...
dt_colorspaces_color_profile_type_t type
Profile identity, half of the memo key. DT_COLORSPACE_NONE means "unset" and makes every apply functi...
char filename[DT_IOP_COLOR_ICC_LEN]
ICC file name, the other half of the memo key; "" for every built-in. Compared with strcmp,...
Region of interest passed through the pixelpipe.
#define __DT_CLONE_TARGETS__
typedef double((*spd)(unsigned long int wavelength, double TempK))
Drawlayer realtime worker thread and FIFO event queue.
void dt_drawlayer_worker_stop(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Stop realtime and full-resolution worker threads.
void dt_drawlayer_worker_cleanup(dt_drawlayer_worker_t **worker)
Public worker cleanup entry point.
void dt_drawlayer_worker_reset_backend_path(dt_drawlayer_worker_t *worker)
Reset worker-owned backend damage accumulator.
static void _cancel_async_commit(dt_drawlayer_worker_t *rt)
Cancel deferred commit request state if any.
void dt_drawlayer_worker_init(dt_iop_module_t *self, dt_drawlayer_worker_t **worker, gboolean *painting, gboolean *finish_commit_pending, guint *stroke_sample_count, uint32_t *current_stroke_batch)
Public worker initialization entry point.
gboolean dt_drawlayer_worker_active(const dt_drawlayer_worker_t *worker)
Public status query: TRUE when worker has pending activity.
void dt_drawlayer_worker_publish_backend_stroke_damage(dt_iop_module_t *self)
Publish accumulated backend stroke damage into drawlayer process/runtime state.
void dt_drawlayer_worker_request_commit(dt_drawlayer_worker_t *worker)
Public commit request helper.
gboolean dt_drawlayer_worker_any_active(const dt_drawlayer_worker_t *worker)
Public status query: TRUE when any worker still has pending activity.
void dt_drawlayer_worker_reset_live_publish(dt_drawlayer_worker_t *worker)
Reset worker-owned transient live-publish state.
void dt_drawlayer_worker_seal_for_commit(dt_drawlayer_worker_t *worker)
Seal current stroke for synchronous commit.
void dt_drawlayer_worker_reset_stroke(dt_drawlayer_worker_t *worker)
Clear preserved stroke runtime/history after commit completed.
static gboolean _wait_worker_idle(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Wait until worker queue is drained and not busy.
Background stroke worker API for drawlayer realtime painting.