Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
atrous.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010 Bruce Guenter.
4 Copyright (C) 2010-2014, 2016 johannes hanika.
5 Copyright (C) 2011 Antony Dovgal.
6 Copyright (C) 2011 Brian Teague.
7 Copyright (C) 2011 Edouard Gomez.
8 Copyright (C) 2011-2012 Henrik Andersson.
9 Copyright (C) 2011 Jochen Schroeder.
10 Copyright (C) 2011 Jérémy Rosen.
11 Copyright (C) 2011 Olivier Tribout.
12 Copyright (C) 2011-2014 Pascal de Bruijn.
13 Copyright (C) 2011 Robert Bieber.
14 Copyright (C) 2011 Rostyslav Pidgornyi.
15 Copyright (C) 2011-2014, 2016, 2019 Tobias Ellinghaus.
16 Copyright (C) 2011-2014, 2016-2017, 2019-2020 Ulrich Pegelow.
17 Copyright (C) 2012 Richard Wonka.
18 Copyright (C) 2013-2016 Roman Lebedev.
19 Copyright (C) 2013 Simon Spannagel.
20 Copyright (C) 2014 parafin.
21 Copyright (C) 2014 Robert William Hutton.
22 Copyright (C) 2015 Pedro Côrte-Real.
23 Copyright (C) 2016 Asma.
24 Copyright (C) 2017-2018, 2021 Dan Torop.
25 Copyright (C) 2017-2018 Heiko Bauke.
26 Copyright (C) 2018-2020, 2022-2023, 2025-2026 Aurélien PIERRE.
27 Copyright (C) 2018 Edgardo Hoszowski.
28 Copyright (C) 2018 Maurizio Paglia.
29 Copyright (C) 2018, 2020-2022 Pascal Obry.
30 Copyright (C) 2018 rawfiner.
31 Copyright (C) 2019 Andreas Schneider.
32 Copyright (C) 2019-2022 Diederik Ter Rahe.
33 Copyright (C) 2019 emeikei.
34 Copyright (C) 2020 Aldric Renaudin.
35 Copyright (C) 2020-2021 Hubert Kowalski.
36 Copyright (C) 2020-2021 Ralf Brown.
37 Copyright (C) 2021 Chris Elston.
38 Copyright (C) 2021 Martin Straeten.
39 Copyright (C) 2021 Sakari Kapanen.
40 Copyright (C) 2022 Hanno Schwalm.
41 Copyright (C) 2022 Martin Bařinka.
42 Copyright (C) 2022 Philipp Lutz.
43 Copyright (C) 2022 Sebatian Glasl.
44
45 darktable is free software: you can redistribute it and/or modify
46 it under the terms of the GNU General Public License as published by
47 the Free Software Foundation, either version 3 of the License, or
48 (at your option) any later version.
49
50 darktable is distributed in the hope that it will be useful,
51 but WITHOUT ANY WARRANTY; without even the implied warranty of
52 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
53 GNU General Public License for more details.
54
55 You should have received a copy of the GNU General Public License
56 along with darktable. If not, see <http://www.gnu.org/licenses/>.
57*/
58
59#include "common/darktable.h"
60#include "bauhaus/bauhaus.h"
61#include "common/debug.h"
62#include "common/eaw.h"
63#include "common/imagebuf.h"
64#include "common/opencl.h"
65#include "control/conf.h"
66#include "control/control.h"
67#include "develop/imageop.h"
68#include "develop/imageop_gui.h"
70#include "develop/tiling.h"
71#include "dtgtk/drawingarea.h"
72
73#include "gui/draw.h"
74#include "gui/gtk.h"
75#include "gui/presets.h"
76#include "iop/iop_api.h"
77
78#include <math.h>
79#include <memory.h>
80#include <stdlib.h>
81//#define USE_NEW_CL //uncomment to use the new, more memory-efficient OpenCL code (not yet finished)
82
83#define INSET DT_PIXEL_APPLY_DPI(5)
84#define INFL .3f
85
86
88
89#define BANDS 6
90#define MAX_NUM_SCALES 8 // 2*2^(i+1) + 1 = 1025px support for i = 8
91#define RES 64
92
93#define dt_atrous_show_upper_label(cr, text, layout, ink) \
94 pango_layout_set_text(layout, text, -1); \
95 pango_layout_get_pixel_extents(layout, &ink, NULL); \
96 cairo_move_to(cr, .5 * (width - ink.width), (.08 * height) - ink.height); \
97 pango_cairo_show_layout(cr, layout);
98
99
100#define dt_atrous_show_lower_label(cr, text, layout, ink) \
101 pango_layout_set_text(layout, text, -1); \
102 pango_layout_get_pixel_extents(layout, &ink, NULL); \
103 cairo_move_to(cr, .5 * (width - ink.width), (.98 * height) - ink.height); \
104 pango_cairo_show_layout(cr, layout);
105
106
108{
109 atrous_L = 0, // luminance boost
110 atrous_c = 1, // chrominance boost
111 atrous_s = 2, // edge sharpness
112 atrous_Lt = 3, // luminance noise threshold
113 atrous_ct = 4, // chrominance noise threshold
114 atrous_none = 5
116
118{
119 int32_t octaves; // $DEFAULT: 3
121 float y[atrous_none][BANDS]; // $DEFAULT: 0.5
122 float mix; // $DEFAULT: 1.0 $MIN: -2.0 $MAX: 2.0
124
146
154
156{
157 // demosaic pattern
158 int32_t octaves;
161
162
163const char *name()
164{
165 return _("contrast equalizer");
166}
167
168const char *aliases()
169{
170 return _("sharpness|acutance|local contrast");
171}
172
173const char **description(struct dt_iop_module_t *self)
174{
175 return dt_iop_set_description(self, _("add or remove local contrast, sharpness, acutance"),
176 _("corrective and creative"),
177 _("linear, Lab, scene-referred"),
178 _("frequential, RGB"),
179 _("linear, Lab, scene-referred"));
180}
181
183{
184 return IOP_GROUP_SHARPNESS;
185}
186
191
193{
194 return IOP_CS_LAB;
195}
196
197int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version,
198 void *new_params, const int new_version)
199{
200 if(old_version == 1 && new_version == 2)
201 {
202 typedef struct dt_iop_atrous_params_v1_t
203 {
204 int32_t octaves; // $DEFAULT: 3
205 float x[atrous_none][BANDS];
206 float y[atrous_none][BANDS]; // $DEFAULT: 0.5
207 } dt_iop_atrous_params_v1_t;
208
209 dt_iop_atrous_params_v1_t *o = (dt_iop_atrous_params_v1_t *)old_params;
212
213 *n = *d; // start with a fresh copy of default parameters
214
215 memcpy(n, o, sizeof(dt_iop_atrous_params_v1_t));
216 n->mix = 1.0f;
217 return 0;
218 }
219
220 return 1;
221}
222
224static int get_samples(float *t, const dt_iop_atrous_data_t *const d, const dt_iop_roi_t *roi_in,
225 const dt_dev_pixelpipe_iop_t *const piece)
226{
227 const float scale = roi_in->scale;
228 const float supp0
229 = MIN(2 * (2 << (MAX_NUM_SCALES - 1)) + 1, MAX(piece->buf_in.height, piece->buf_in.width) * 0.2f);
230 const float i0 = dt_log2f((supp0 - 1.0f) * .5f);
231 int i = 0;
232 for(; i < MAX_NUM_SCALES; i++)
233 {
234 // actual filter support on scaled buffer
235 const float supp = 2 * (2 << i) + 1;
236 // approximates this filter size on unscaled input image:
237 const float supp_in = supp * (1.0f / scale);
238 const float i_in = dt_log2f((supp_in - 1) * .5f) - 1.0f;
239 t[i] = 1.0f - (i_in + .5f) / i0;
240 if(t[i] < 0.0f) break;
241 }
242 return i;
243}
244
246static int get_scales(float (*thrs)[4], float (*boost)[4], float *sharp, const dt_iop_atrous_data_t *const d,
247 const dt_iop_roi_t *roi_in, const dt_dev_pixelpipe_iop_t *const piece)
248{
249 // we want coeffs to span max 20% of the image
250 // finest is 5x5 filter
251 //
252 // 1:1 : w=20% buf_in.width w=5x5
253 // : ^ ... .... .... ^
254 // buf : 17x17 9x9 5x5 2*2^k+1
255 // .....
256 // . . . . .
257 // . . . . .
258 // cut off too fine ones, if image is not detailed enough (due to roi_in->scale)
259 const float scale = roi_in->scale;
260 // largest desired filter on input buffer (20% of input dim)
261 const float supp0
262 = MIN(2 * (2 << (MAX_NUM_SCALES - 1)) + 1,
263 MAX(piece->buf_in.height, piece->buf_in.width) * 0.2f);
264 const float i0 = dt_log2f((supp0 - 1.0f) * .5f);
265 int i = 0;
266 for(; i < MAX_NUM_SCALES; i++)
267 {
268 // actual filter support on scaled buffer
269 const float supp = 2 * (2 << i) + 1;
270 // approximates this filter size on unscaled input image:
271 const float supp_in = supp * (1.0f / scale);
272 const float i_in = dt_log2f((supp_in - 1) * .5f) - 1.0f;
273 // i_in = max_scale .. .. .. 0
274 const float t = 1.0f - (i_in + .5f) / i0;
275 boost[i][3] = boost[i][0] = 2.0f * dt_draw_curve_calc_value(d->curve[atrous_L], t);
276 boost[i][1] = boost[i][2] = 2.0f * dt_draw_curve_calc_value(d->curve[atrous_c], t);
277 for(int k = 0; k < 4; k++) boost[i][k] *= boost[i][k];
278 thrs[i][0] = thrs[i][3] = powf(2.0f, -7.0f * (1.0f - t)) * 10.0f
280 thrs[i][1] = thrs[i][2] = powf(2.0f, -7.0f * (1.0f - t)) * 20.0f
282 sharp[i] = 0.0025f * dt_draw_curve_calc_value(d->curve[atrous_s], t);
283 // printf("scale %d boost %f %f thrs %f %f sharpen %f\n", i, boost[i][0], boost[i][2], thrs[i][0],
284 // thrs[i][1], sharp[i]);
285 if(t < 0.0f) break;
286 }
287 // ensure that return value max_scale is such that
288 // 2 * 2 *(1 << max_scale) <= min(width, height)
289 const int max_scale_roi = (int)floorf(dt_log2f((float)MIN(roi_in->width, roi_in->height))) - 2;
290 return MIN(max_scale_roi, i);
291}
292
293/* just process the supplied image buffer, upstream default_process_tiling() does the rest */
295static int process_wavelets(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
296 const struct dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o,
297 const dt_iop_roi_t *const roi_in,
298 const dt_iop_roi_t *const roi_out, const eaw_decompose_t decompose,
299 const eaw_synthesize_t synthesize)
300{
304 float sharp[MAX_NUM_SCALES];
305 const int max_scale = get_scales(thrs, boost, sharp, d, roi_in, piece);
306 const int max_mult = 1u << (max_scale - 1);
307
308 const int width = roi_out->width;
309 const int height = roi_out->height;
310
311 if(self->dev->gui_attached && !dt_dev_pixelpipe_has_preview_output(self->dev, pipe, roi_out))
312 {
314 g->num_samples = get_samples(g->sample, d, roi_in, piece);
315 // tries to acquire gdk lock and this prone to deadlock:
316 // dt_control_queue_draw(GTK_WIDGET(g->area));
317 }
318
319 // corner case of extremely small image. this is not really likely to happen but would
320 // lead to out of bounds memory access
321 if(width < 2 * max_mult || height < 2 * max_mult)
322 {
324 return 0;
325 }
326
327 float *const restrict out = (float*)o;
328 float *restrict detail = NULL;
329 float *restrict tmp = NULL;
330 float *restrict tmp2 = NULL;
331
332 if (dt_iop_alloc_image_buffers(self, roi_in, roi_out, 4, &tmp, 4, &tmp2, 4, &detail, 0))
333 {
334 return 1;
335 }
336
337 float *buf1 = (float *)i;
338 float *buf2 = tmp;
339
340 // clear the output buffer, which will be accumulating all of the detail scales
341 memset(out, 0, sizeof(float) * 4 * width * height);
342
343 // now do the wavelet decomposition, immediately synthesizing the detail scale into the final output so
344 // that we don't need to store it past the current scale's iteration
345 for(int scale = 0; scale < max_scale; scale++)
346 {
347 decompose(buf2, buf1, detail, scale, sharp[scale], width, height);
348 synthesize(out, out, detail, thrs[scale], boost[scale], width, height);
349 if(scale == 0) buf1 = (float *)tmp2; // now switch to second scratch for buffer ping-pong between buf1 and buf2
350 float *buf3 = buf2;
351 buf2 = buf1;
352 buf1 = buf3;
353 }
354
355 // add in the final residue
356 __OMP_SIMD__(aligned(buf1, out : 64))
357 for (size_t k = 0; k < (size_t)4 * width * height; k++)
358 out[k] += buf1[k];
359
361 dt_iop_alpha_copy(i, o, width, height);
362
366 return 0;
367}
368
369int process(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
370 const struct dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o)
371{
372 const dt_iop_roi_t *const roi_in = &piece->roi_in;
373 const dt_iop_roi_t *const roi_out = &piece->roi_out;
374 return process_wavelets(self, pipe, piece, i, o, roi_in, roi_out, eaw_decompose, eaw_synthesize);
375}
376
377#ifdef HAVE_OPENCL
378
379#ifdef USE_NEW_CL
380/* this version is adapted to the new global tiling mechanism. it no longer does tiling by itself. */
381int 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)
382{
383 const dt_iop_roi_t *const roi_in = &piece->roi_in;
384 const dt_iop_roi_t *const roi_out = &piece->roi_out;
388 float sharp[MAX_NUM_SCALES];
389 const int max_scale = get_scales(thrs, boost, sharp, d, roi_in, piece);
390
391 if(self->dev->gui_attached && !dt_dev_pixelpipe_has_preview_output(self->dev, pipe, roi_out))
392 {
394 g->num_samples = get_samples(g->sample, d, roi_in, piece);
395 // dt_control_queue_redraw_widget(GTK_WIDGET(g->area));
396 // tries to acquire gdk lock and this prone to deadlock:
397 // dt_control_queue_draw(GTK_WIDGET(g->area));
398 }
399
401
402 const int devid = pipe->devid;
403 cl_int err = -999;
404 cl_mem dev_filter = NULL;
405 cl_mem dev_tmp = NULL;
406 cl_mem dev_tmp2 = NULL;
407 cl_mem dev_detail = NULL;
408
409 float m[] = { 0.0625f, 0.25f, 0.375f, 0.25f, 0.0625f }; // 1/16, 4/16, 6/16, 4/16, 1/16
410 float mm[5][5];
411 for(int j = 0; j < 5; j++)
412 for(int i = 0; i < 5; i++) mm[j][i] = m[i] * m[j];
413
414 dev_filter = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * 25, mm);
415 if(IS_NULL_PTR(dev_filter)) goto error;
416
417 /* allocate space for two temporary buffer to participate_in in the buffer ping-pong below. We need dev_out
418 to accumulate the result and dev_in needs to stay unchanged for blendops */
419 dev_tmp = dt_opencl_alloc_device(devid, roi_out->width, roi_out->height, sizeof(float) * 4);
420 if(IS_NULL_PTR(dev_tmp)) goto error;
421 dev_tmp2 = dt_opencl_alloc_device(devid, roi_out->width, roi_out->height, sizeof(float) * 4);
422 if(IS_NULL_PTR(dev_tmp2)) goto error;
423
424 /* allocate a buffer for storing the detail information. */
425 dev_detail = dt_opencl_alloc_device(devid, roi_out->width, roi_out->height, sizeof(float) * 4);
426 if(IS_NULL_PTR(dev_detail)) goto error;
427
428 const int width = roi_out->width;
429 const int height = roi_out->height;
430 size_t sizes[] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
431
432 // clear dev_out to zeros, as we will be incrementally accumulating results there
433 dt_opencl_set_kernel_arg(devid, gd->kernel_zero, 0, sizeof(cl_mem), (void *)&dev_out);
434 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_zero, sizes);
435 if(err != CL_SUCCESS) goto error;
436
437 // the buffers for the buffer ping-pong. We start with dev_in as the input half for the first
438 // scale, then switch to using dev_tmp and dev_tmp2 as the two scratch buffers
439 void* dev_buf1 = &dev_in;
440 void* dev_buf2 = &dev_tmp;
441
442 /* decompose image into detail scales and coarse (the latter is left in dev_tmp or dev_out) */
443 for(int s = 0; s < max_scale; s++)
444 {
445 const int scale = s;
446
447 // run the decomposition
448 dt_opencl_set_kernel_arg(devid, gd->kernel_decompose, 0, sizeof(cl_mem), (void *)&dev_buf2); //this scale's output
449 dt_opencl_set_kernel_arg(devid, gd->kernel_decompose, 1, sizeof(cl_mem), (void *)&dev_buf1); //this scale's input
450 dt_opencl_set_kernel_arg(devid, gd->kernel_decompose, 2, sizeof(cl_mem), (void *)&dev_detail);
451 dt_opencl_set_kernel_arg(devid, gd->kernel_decompose, 3, sizeof(int), (void *)&width);
452 dt_opencl_set_kernel_arg(devid, gd->kernel_decompose, 4, sizeof(int), (void *)&height);
453 dt_opencl_set_kernel_arg(devid, gd->kernel_decompose, 5, sizeof(unsigned int), (void *)&scale);
454 dt_opencl_set_kernel_arg(devid, gd->kernel_decompose, 6, sizeof(float), (void *)&sharp[s]);
455 dt_opencl_set_kernel_arg(devid, gd->kernel_decompose, 7, sizeof(cl_mem), (void *)&dev_filter);
456
457 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_decompose, sizes);
458 if(err != CL_SUCCESS) goto error;
459
460 // now immediately run the synthesis for the current scale, accumulating the details into dev_out
461 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 0, sizeof(cl_mem), (void *)&dev_out);
462 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 1, sizeof(cl_mem), (void *)&dev_out);
463 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 2, sizeof(cl_mem), (void *)&dev_detail);
464 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 3, sizeof(int), (void *)&width);
465 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 4, sizeof(int), (void *)&height);
466 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 5, sizeof(float), (void *)&thrs[scale][0]);
467 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 6, sizeof(float), (void *)&thrs[scale][1]);
468 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 7, sizeof(float), (void *)&thrs[scale][2]);
469 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 8, sizeof(float), (void *)&thrs[scale][3]);
470 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 9, sizeof(float), (void *)&boost[scale][0]);
471 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 10, sizeof(float), (void *)&boost[scale][1]);
472 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 11, sizeof(float), (void *)&boost[scale][2]);
473 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 12, sizeof(float), (void *)&boost[scale][3]);
474
475 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_synthesize, sizes);
476 if(err != CL_SUCCESS) goto error;
477
478 // swap scratch buffers
479 if (scale == 0) dev_buf1 = dev_tmp2;
480 void* tmp = dev_buf2;
481 dev_buf2 = dev_buf1;
482 dev_buf1 = tmp;
483 }
484
485 // add the residue (the coarse scale from the final decomposition) to the accumulated details
486 dt_opencl_set_kernel_arg(devid, gd->kernel_addbuffers, 0, sizeof(cl_mem), (void*)&dev_out);
487 dt_opencl_set_kernel_arg(devid, gd->kernel_addbuffers, 1, sizeof(cl_mem), (void*)&dev_buf1);
488
489 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_addbuffers, sizes);
490 if(err != CL_SUCCESS) goto error;
491
496 return TRUE;
497
498error:
503 dt_print(DT_DEBUG_OPENCL, "[opencl_atrous] couldn't enqueue kernel! %d\n", err);
504 return FALSE;
505}
506
507#else // ======== old, memory-hungry implementation ========================================================
508
509/* this version is adapted to the new global tiling mechanism. it no longer does tiling by itself. */
510int 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)
511{
512 const dt_iop_roi_t *const roi_in = &piece->roi_in;
513 const dt_iop_roi_t *const roi_out = &piece->roi_out;
517 float sharp[MAX_NUM_SCALES];
518 const int max_scale = get_scales(thrs, boost, sharp, d, roi_in, piece);
519
520 if(self->dev->gui_attached && !dt_dev_pixelpipe_has_preview_output(self->dev, pipe, roi_out))
521 {
523 g->num_samples = get_samples(g->sample, d, roi_in, piece);
524 // dt_control_queue_redraw_widget(GTK_WIDGET(g->area));
525 // tries to acquire gdk lock and this prone to deadlock:
526 // dt_control_queue_draw(GTK_WIDGET(g->area));
527 }
528
530
531 const int devid = pipe->devid;
532 cl_int err = -999;
533 cl_mem dev_filter = NULL;
534 cl_mem dev_tmp = NULL;
535 cl_mem *dev_detail = calloc(max_scale, sizeof(cl_mem));
536
537 float m[] = { 0.0625f, 0.25f, 0.375f, 0.25f, 0.0625f }; // 1/16, 4/16, 6/16, 4/16, 1/16
538 float mm[5][5];
539 for(int j = 0; j < 5; j++)
540 for(int i = 0; i < 5; i++)
541 mm[j][i] = m[i] * m[j];
542
543 dev_filter = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * 25, mm);
544 if(IS_NULL_PTR(dev_filter)) goto error;
545
546 /* allocate space for a temporary buffer. we don't want to use dev_in in the buffer ping-pong below, as we
547 need to keep it for blendops */
548 dev_tmp = dt_opencl_alloc_device(devid, roi_out->width, roi_out->height, sizeof(float) * 4);
549 if(IS_NULL_PTR(dev_tmp)) goto error;
550
551 /* allocate space to store detail information. Requires a number of additional buffers, each with full image
552 * size */
553 for(int k = 0; k < max_scale; k++)
554 {
555 dev_detail[k] = dt_opencl_alloc_device(devid, roi_out->width, roi_out->height, sizeof(float) * 4);
556 if(dev_detail[k] == NULL) goto error;
557 }
558
559 const int width = roi_out->width;
560 const int height = roi_out->height;
561 size_t sizes[] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
562 size_t origin[] = { 0, 0, 0 };
563 size_t region[] = { width, height, 1 };
564
565 // copy original input from dev_in -> dev_out as starting point
566 err = dt_opencl_enqueue_copy_image(devid, dev_in, dev_out, origin, origin, region);
567 if(err != CL_SUCCESS) goto error;
568
569 /* decompose image into detail scales and coarse (the latter is left in dev_tmp or dev_out) */
570 for(int s = 0; s < max_scale; s++)
571 {
572 const int scale = s;
573
574 if(s & 1)
575 {
576 dt_opencl_set_kernel_arg(devid, gd->kernel_decompose, 0, sizeof(cl_mem), (void *)&dev_tmp);
577 dt_opencl_set_kernel_arg(devid, gd->kernel_decompose, 1, sizeof(cl_mem), (void *)&dev_out);
578 }
579 else
580 {
581 dt_opencl_set_kernel_arg(devid, gd->kernel_decompose, 0, sizeof(cl_mem), (void *)&dev_out);
582 dt_opencl_set_kernel_arg(devid, gd->kernel_decompose, 1, sizeof(cl_mem), (void *)&dev_tmp);
583 }
584 dt_opencl_set_kernel_arg(devid, gd->kernel_decompose, 2, sizeof(cl_mem), (void *)&dev_detail[s]);
585 dt_opencl_set_kernel_arg(devid, gd->kernel_decompose, 3, sizeof(int), (void *)&width);
586 dt_opencl_set_kernel_arg(devid, gd->kernel_decompose, 4, sizeof(int), (void *)&height);
587 dt_opencl_set_kernel_arg(devid, gd->kernel_decompose, 5, sizeof(unsigned int), (void *)&scale);
588 dt_opencl_set_kernel_arg(devid, gd->kernel_decompose, 6, sizeof(float), (void *)&sharp[s]);
589 dt_opencl_set_kernel_arg(devid, gd->kernel_decompose, 7, sizeof(cl_mem), (void *)&dev_filter);
590
591 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_decompose, sizes);
592 if(err != CL_SUCCESS) goto error;
593 }
594
595 /* now synthesize again */
596 for(int scale = max_scale - 1; scale >= 0; scale--)
597 {
598 if(scale & 1)
599 {
600 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 0, sizeof(cl_mem), (void *)&dev_tmp);
601 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 1, sizeof(cl_mem), (void *)&dev_out);
602 }
603 else
604 {
605 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 0, sizeof(cl_mem), (void *)&dev_out);
606 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 1, sizeof(cl_mem), (void *)&dev_tmp);
607 }
608
609 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 2, sizeof(cl_mem), (void *)&dev_detail[scale]);
610 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 3, sizeof(int), (void *)&width);
611 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 4, sizeof(int), (void *)&height);
612 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 5, sizeof(float), (void *)&thrs[scale][0]);
613 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 6, sizeof(float), (void *)&thrs[scale][1]);
614 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 7, sizeof(float), (void *)&thrs[scale][2]);
615 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 8, sizeof(float), (void *)&thrs[scale][3]);
616 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 9, sizeof(float), (void *)&boost[scale][0]);
617 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 10, sizeof(float), (void *)&boost[scale][1]);
618 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 11, sizeof(float), (void *)&boost[scale][2]);
619 dt_opencl_set_kernel_arg(devid, gd->kernel_synthesize, 12, sizeof(float), (void *)&boost[scale][3]);
620
621 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_synthesize, sizes);
622 if(err != CL_SUCCESS) goto error;
623 }
624
627 for(int k = 0; k < max_scale; k++)
628 dt_opencl_release_mem_object(dev_detail[k]);
629 dt_free(dev_detail);
630 return TRUE;
631
632error:
635 for(int k = 0; k < max_scale; k++)
636 dt_opencl_release_mem_object(dev_detail[k]);
637 dt_free(dev_detail);
638 dt_print(DT_DEBUG_OPENCL, "[opencl_atrous] couldn't enqueue kernel! %d\n", err);
639 return FALSE;
640}
641#endif // USE_NEW_CL
642
643#endif // HAVE_OPENCL
644
645void tiling_callback(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
646{
647 const dt_iop_roi_t *const roi_in = &piece->roi_in;
651 float sharp[MAX_NUM_SCALES];
652 const int max_scale = get_scales(thrs, boost, sharp, d, roi_in, piece);
653 const int max_filter_radius = 2 * (1 << max_scale); // 2 * 2^max_scale
654
655 tiling->factor = 5.0f; // in + out + 2*tmp + details
656 tiling->factor_cl = 3.0f + max_scale; // in + out + tmp + scale buffers
657 tiling->maxbuf = 1.0f;
658 tiling->maxbuf_cl = 1.0f;
659 tiling->overhead = 0;
660 tiling->overlap = max_filter_radius;
661 tiling->xalign = 1;
662 tiling->yalign = 1;
663 return;
664}
665
667{
668 dt_iop_default_init(module);
669
670 dt_iop_atrous_params_t *d = module->default_params;
671
672 for(int k = 0; k < BANDS; k++)
673 {
674 d->y[atrous_Lt][k] = d->y[atrous_ct][k] = 0.0f;
675 for(int c = atrous_L; c <= atrous_ct; c++)
676 d->x[c][k] = k / (BANDS - 1.0f);
677 }
678}
679
681{
682 const int program = 1; // from programs.conf
685 module->data = gd;
686 gd->kernel_decompose = dt_opencl_create_kernel(program, "eaw_decompose");
687 gd->kernel_synthesize = dt_opencl_create_kernel(program, "eaw_synthesize");
688#ifdef USE_NEW_CL
689 gd->kernel_zero = dt_opencl_create_kernel(program, "eaw_zero");
690 gd->kernel_addbuffers = dt_opencl_create_kernel(program, "eaw_addbuffers");
691#endif
692}
693
705
706static inline void _apply_mix(dt_iop_module_t *self,
707 const int ch, const int k,
708 const float mix,
709 const float px, const float py, float *x, float *y)
710{
712 *x = fminf(1.0f, fmaxf(0.0f, px + (mix - 1.0f) * (px - dp->x[ch][k])));
713 *y = fminf(1.0f, fmaxf(0.0f, py + (mix - 1.0f) * (py - dp->y[ch][k])));
714}
715
718{
721
722#if 0
723 printf("---------- atrous preset begin\n");
724 printf("p.octaves = %d; p.mix = %.2f\n", p->octaves, p->mix);
725 for(int ch=0; ch<atrous_none; ch++) for(int k=0; k<BANDS; k++)
726 {
727 printf("p.x[%d][%d] = %f;\n", ch, k, p->x[ch][k]);
728 printf("p.y[%d][%d] = %f;\n", ch, k, p->y[ch][k]);
729 }
730 printf("---------- atrous preset end\n");
731#endif
732 d->octaves = p->octaves;
733 for(int ch = 0; ch < atrous_none; ch++)
734 for(int k = 0; k < BANDS; k++)
735 {
736 float x, y;
737 _apply_mix(self, ch, k, p->mix, p->x[ch][k], p->y[ch][k], &x, &y);
738 dt_draw_curve_set_point(d->curve[ch], k, x, y);
739 }
740 int l = 0;
741 for(int k = (int)MIN(pipe->iwidth, pipe->iheight); k; k >>= 1) l++;
742 d->octaves = MIN(BANDS, l);
743
744 piece->cache_output_on_ram = TRUE;
745}
746
748{
751 piece->data = (void *)d;
752 piece->data_size = sizeof(dt_iop_atrous_data_t);
753 for(int ch = 0; ch < atrous_none; ch++)
754 {
755 d->curve[ch] = dt_draw_curve_new(0.0, 1.0, CATMULL_ROM);
756 for(int k = 0; k < BANDS; k++)
757 (void)dt_draw_curve_add_point(d->curve[ch], default_params->x[ch][k], default_params->y[ch][k]);
758 }
759 int l = 0;
760 for(int k = (int)MIN(pipe->iwidth, pipe->iheight); k; k >>= 1) l++;
761 d->octaves = MIN(BANDS, l);
762}
763
765{
767 for(int ch = 0; ch < atrous_none; ch++)
768 dt_draw_curve_destroy(d->curve[ch]);
769 dt_free_align(piece->data);
770 piece->data = NULL;
771}
772
773#define GAUSS(x, sigma) expf( -(1.0f - x) * (1.0f - x) / (sigma * sigma)) / (2.0 * sigma * powf(M_PI, 0.5f))
774
776{
779 p.octaves = 7;
780 p.mix = 1.0f;
781
782 for(int k = 0; k < BANDS; k++)
783 {
784 p.x[atrous_L][k] = k / (BANDS - 1.0);
785 p.x[atrous_c][k] = k / (BANDS - 1.0);
786 p.x[atrous_s][k] = k / (BANDS - 1.0);
787 p.y[atrous_L][k] = fmaxf(.5f, .75f - .5f * k / (BANDS - 1.0));
788 p.y[atrous_c][k] = fmaxf(.5f, .55f - .5f * k / (BANDS - 1.0));
789 p.y[atrous_s][k] = fminf(.5f, .2f + .35f * k / (BANDS - 1.0));
790 p.x[atrous_Lt][k] = k / (BANDS - 1.0);
791 p.x[atrous_ct][k] = k / (BANDS - 1.0);
792 p.y[atrous_Lt][k] = 0.0f;
793 p.y[atrous_ct][k] = 0.0f;
794 }
795 dt_gui_presets_add_generic(C_("eq_preset", "coarse"), self->op,
796 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_RGB_DISPLAY);
797 for(int k = 0; k < BANDS; k++)
798 {
799 p.x[atrous_L][k] = k / (BANDS - 1.0);
800 p.x[atrous_c][k] = k / (BANDS - 1.0);
801 p.x[atrous_s][k] = k / (BANDS - 1.0);
802 p.y[atrous_L][k] = .5f + .25f * k / (float)BANDS;
803 p.y[atrous_c][k] = .5f;
804 p.y[atrous_s][k] = .5f;
805 p.x[atrous_Lt][k] = k / (BANDS - 1.0);
806 p.x[atrous_ct][k] = k / (BANDS - 1.0);
807 p.y[atrous_Lt][k] = .2f * k / (float)BANDS;
808 p.y[atrous_ct][k] = .3f * k / (float)BANDS;
809 }
810 dt_gui_presets_add_generic(_("denoise & sharpen"), self->op,
811 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_RGB_DISPLAY);
812 for(int k = 0; k < BANDS; k++)
813 {
814 p.x[atrous_L][k] = k / (BANDS - 1.0);
815 p.x[atrous_c][k] = k / (BANDS - 1.0);
816 p.x[atrous_s][k] = k / (BANDS - 1.0);
817 p.y[atrous_L][k] = .5f + .25f * k / (float)BANDS;
818 p.y[atrous_c][k] = .5f;
819 p.y[atrous_s][k] = .5f;
820 p.x[atrous_Lt][k] = k / (BANDS - 1.0);
821 p.x[atrous_ct][k] = k / (BANDS - 1.0);
822 p.y[atrous_Lt][k] = 0.0f;
823 p.y[atrous_ct][k] = 0.0f;
824 }
825 dt_gui_presets_add_generic(C_("atrous", "sharpen"), self->op,
826 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_RGB_DISPLAY);
827 for(int k = 0; k < BANDS; k++)
828 {
829 p.x[atrous_L][k] = k / (BANDS - 1.0);
830 p.x[atrous_c][k] = k / (BANDS - 1.0);
831 p.x[atrous_s][k] = k / (BANDS - 1.0);
832 p.y[atrous_L][k] = .5f;
833 p.y[atrous_c][k] = .5f;
834 p.y[atrous_s][k] = .0f;
835 p.x[atrous_Lt][k] = k / (BANDS - 1.0);
836 p.x[atrous_ct][k] = k / (BANDS - 1.0);
837 p.y[atrous_Lt][k] = .0f;
838 p.y[atrous_ct][k] = fmaxf(0.0f, (.60f * k / (float)BANDS) - 0.30f);
839 }
840 dt_gui_presets_add_generic(_("denoise chroma"), self->op,
841 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_RGB_DISPLAY);
842 for(int k = 0; k < BANDS; k++)
843 {
844 p.x[atrous_L][k] = k / (BANDS - 1.0);
845 p.x[atrous_c][k] = k / (BANDS - 1.0);
846 p.x[atrous_s][k] = k / (BANDS - 1.0);
847 p.y[atrous_L][k] = .5f; //-.2f*k/(float)BANDS;
848 p.y[atrous_c][k] = .5f; // fmaxf(0.0f, .5f-.3f*k/(float)BANDS);
849 p.y[atrous_s][k] = .5f;
850 p.x[atrous_Lt][k] = k / (BANDS - 1.0);
851 p.x[atrous_ct][k] = k / (BANDS - 1.0);
852 p.y[atrous_Lt][k] = .2f * k / (float)BANDS;
853 p.y[atrous_ct][k] = .3f * k / (float)BANDS;
854 }
855 dt_gui_presets_add_generic(_("denoise"), self->op,
856 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_RGB_DISPLAY);
857 for(int k = 0; k < BANDS; k++)
858 {
859 p.x[atrous_L][k] = k / (BANDS - 1.0);
860 p.x[atrous_c][k] = k / (BANDS - 1.0);
861 p.x[atrous_s][k] = k / (BANDS - 1.0);
862 p.y[atrous_L][k] = fminf(.5f, .3f + .35f * k / (BANDS - 1.0));
863 p.y[atrous_c][k] = .5f;
864 p.y[atrous_s][k] = .0f;
865 p.x[atrous_Lt][k] = k / (BANDS - 1.0);
866 p.x[atrous_ct][k] = k / (BANDS - 1.0);
867 p.y[atrous_Lt][k] = 0.0f;
868 p.y[atrous_ct][k] = 0.0f;
869 }
870 p.y[atrous_L][0] = .5f;
871 dt_gui_presets_add_generic(_("bloom"), self->op,
872 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_RGB_DISPLAY);
873 for(int k = 0; k < BANDS; k++)
874 {
875 p.x[atrous_L][k] = k / (BANDS - 1.0);
876 p.x[atrous_c][k] = k / (BANDS - 1.0);
877 p.x[atrous_s][k] = k / (BANDS - 1.0);
878 p.y[atrous_L][k] = 0.6f;
879 p.y[atrous_c][k] = .55f;
880 p.y[atrous_s][k] = .0f;
881 p.x[atrous_Lt][k] = k / (BANDS - 1.0);
882 p.x[atrous_ct][k] = k / (BANDS - 1.0);
883 p.y[atrous_Lt][k] = 0.0f;
884 p.y[atrous_ct][k] = 0.0f;
885 }
886 dt_gui_presets_add_generic(_("clarity"), self->op,
887 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_RGB_DISPLAY);
888
889 float sigma = 3.f / (float)(BANDS - 1);
890
891 for(int k = 0; k < BANDS; k++)
892 {
893 const float x = k / (float)(BANDS - 1);
894 const float fine = GAUSS(x, 0.5 * sigma);
895 const float medium = GAUSS(x, sigma);
896 const float coarse = GAUSS(x, 2 * sigma);
897 const float coeff = 0.5f + (coarse + medium + fine) / 16.0f;
898 const float noise = (coarse + medium + fine) / 128.f;
899
900 p.x[atrous_L][k] = p.x[atrous_c][k] = p.x[atrous_s][k] = x;
901 p.y[atrous_L][k] = p.y[atrous_s][k] = coeff;
902 p.y[atrous_c][k] = 0.5f;
903 p.x[atrous_Lt][k] = p.x[atrous_ct][k] = x;
904 p.y[atrous_Lt][k] = p.y[atrous_ct][k] = noise;
905 }
906 dt_gui_presets_add_generic(_("deblur: large blur, strength 3"), self->op,
907 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_RGB_DISPLAY);
908
909 for(int k = 0; k < BANDS; k++)
910 {
911 const float x = k / (float)(BANDS - 1);
912 const float fine = GAUSS(x, 0.5 * sigma);
913 const float medium = GAUSS(x, sigma);
914 const float coeff = 0.5f + (medium + fine) / 16.0f;
915 const float noise = (medium + fine) / 128.f;
916
917 p.x[atrous_L][k] = p.x[atrous_c][k] = p.x[atrous_s][k] = x;
918 p.y[atrous_L][k] = p.y[atrous_s][k] = coeff;
919 p.y[atrous_c][k] = 0.5f;
920 p.x[atrous_Lt][k] = p.x[atrous_ct][k] = x;
921 p.y[atrous_Lt][k] = p.y[atrous_ct][k] = noise;
922 }
923 dt_gui_presets_add_generic(_("deblur: medium blur, strength 3"), self->op,
924 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_RGB_DISPLAY);
925
926 for(int k = 0; k < BANDS; k++)
927 {
928 const float x = k / (float)(BANDS - 1);
929 const float fine = GAUSS(x, 0.5 * sigma);
930 const float coeff = 0.5f + fine / 16.f;
931 const float noise = fine / 128.f;
932
933 p.x[atrous_L][k] = p.x[atrous_c][k] = p.x[atrous_s][k] = x;
934 p.y[atrous_L][k] = p.y[atrous_s][k] = coeff;
935 p.y[atrous_c][k] = 0.5f;
936 p.x[atrous_Lt][k] = p.x[atrous_ct][k] = x;
937 p.y[atrous_Lt][k] = p.y[atrous_ct][k] = noise;
938 }
939 dt_gui_presets_add_generic(_("deblur: fine blur, strength 3"), self->op,
940 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_RGB_DISPLAY);
941
942 for(int k = 0; k < BANDS; k++)
943 {
944 const float x = k / (float)(BANDS - 1);
945 const float fine = GAUSS(x, 0.5 * sigma);
946 const float medium = GAUSS(x, sigma);
947 const float coarse = GAUSS(x, 2 * sigma);
948 const float coeff = 0.5f + (coarse + medium + fine) / 24.0f;
949 const float noise = (coarse + medium + fine) / 192.f;
950
951 p.x[atrous_L][k] = p.x[atrous_c][k] = p.x[atrous_s][k] = x;
952 p.y[atrous_L][k] = p.y[atrous_s][k] = coeff;
953 p.y[atrous_c][k] = 0.5f;
954 p.x[atrous_Lt][k] = p.x[atrous_ct][k] = x;
955 p.y[atrous_Lt][k] = p.y[atrous_ct][k] = noise;
956 }
957 dt_gui_presets_add_generic(_("deblur: large blur, strength 2"), self->op,
958 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_RGB_DISPLAY);
959
960 for(int k = 0; k < BANDS; k++)
961 {
962 const float x = k / (float)(BANDS - 1);
963 const float fine = GAUSS(x, 0.5 * sigma);
964 const float medium = GAUSS(x, sigma);
965 const float coeff = 0.5f + (medium + fine) / 24.0f;
966 const float noise = (medium + fine) / 192.f;
967
968 p.x[atrous_L][k] = p.x[atrous_c][k] = p.x[atrous_s][k] = x;
969 p.y[atrous_L][k] = p.y[atrous_s][k] = coeff;
970 p.y[atrous_c][k] = 0.5f;
971 p.x[atrous_Lt][k] = p.x[atrous_ct][k] = x;
972 p.y[atrous_Lt][k] = p.y[atrous_ct][k] = noise;
973 }
974 dt_gui_presets_add_generic(_("deblur: medium blur, strength 2"), self->op,
975 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_RGB_DISPLAY);
976
977 for(int k = 0; k < BANDS; k++)
978 {
979 const float x = k / (float)(BANDS - 1);
980 const float fine = GAUSS(x, 0.5 * sigma);
981 const float coeff = 0.5f + fine / 24.0f;
982 const float noise = fine / 192.f;
983
984 p.x[atrous_L][k] = p.x[atrous_c][k] = p.x[atrous_s][k] = x;
985 p.y[atrous_L][k] = p.y[atrous_s][k] = coeff;
986 p.y[atrous_c][k] = 0.5f;
987 p.x[atrous_Lt][k] = p.x[atrous_ct][k] = x;
988 p.y[atrous_Lt][k] = p.y[atrous_ct][k] = noise;
989 }
990 dt_gui_presets_add_generic(_("deblur: fine blur, strength 2"), self->op,
991 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_RGB_DISPLAY);
992
993 for(int k = 0; k < BANDS; k++)
994 {
995 const float x = k / (float)(BANDS - 1);
996 const float fine = GAUSS(x, 0.5 * sigma);
997 const float medium = GAUSS(x, sigma);
998 const float coarse = GAUSS(x, 2 * sigma);
999 const float coeff = 0.5f + (coarse + medium + fine) / 32.0f;
1000 const float noise = (coarse + medium + fine) / 128.f;
1001
1002 p.x[atrous_L][k] = p.x[atrous_c][k] = p.x[atrous_s][k] = x;
1003 p.y[atrous_L][k] = p.y[atrous_s][k] = coeff;
1004 p.y[atrous_c][k] = 0.5f;
1005 p.x[atrous_Lt][k] = p.x[atrous_ct][k] = x;
1006 p.y[atrous_Lt][k] = p.y[atrous_ct][k] = noise;
1007 }
1008 dt_gui_presets_add_generic(_("deblur: large blur, strength 1"), self->op,
1009 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_RGB_DISPLAY);
1010
1011 for(int k = 0; k < BANDS; k++)
1012 {
1013 const float x = k / (float)(BANDS - 1);
1014 const float fine = GAUSS(x, 0.5 * sigma);
1015 const float medium = GAUSS(x, sigma);
1016 const float coeff = 0.5f + (medium + fine) / 32.0f;
1017 const float noise = (medium + fine) / 128.f;
1018
1019 p.x[atrous_L][k] = p.x[atrous_c][k] = p.x[atrous_s][k] = x;
1020 p.y[atrous_L][k] = p.y[atrous_s][k] = coeff;
1021 p.y[atrous_c][k] = 0.5f;
1022 p.x[atrous_Lt][k] = p.x[atrous_ct][k] = x;
1023 p.y[atrous_Lt][k] = p.y[atrous_ct][k] = noise;
1024 }
1025 dt_gui_presets_add_generic(_("deblur: medium blur, strength 1"), self->op,
1026 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_RGB_DISPLAY);
1027
1028 for(int k = 0; k < BANDS; k++)
1029 {
1030 const float x = k / (float)(BANDS - 1);
1031 const float fine = GAUSS(x, 0.5 * sigma);
1032 const float coeff = 0.5f + fine / 32.f;
1033 const float noise = fine / 128.f;
1034
1035 p.x[atrous_L][k] = p.x[atrous_c][k] = p.x[atrous_s][k] = x;
1036 p.y[atrous_L][k] = p.y[atrous_s][k] = coeff;
1037 p.y[atrous_c][k] = 0.5f;
1038 p.x[atrous_Lt][k] = p.x[atrous_ct][k] = x;
1039 p.y[atrous_Lt][k] = p.y[atrous_ct][k] = noise;
1040 }
1041 dt_gui_presets_add_generic(_("deblur: fine blur, strength 1"), self->op,
1042 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_RGB_DISPLAY);
1043
1045}
1046
1047static void reset_mix(dt_iop_module_t *self)
1048{
1051 c->drag_params = *p;
1052 ++darktable.gui->reset;
1053 dt_bauhaus_slider_set(c->mix, p->mix);
1054 --darktable.gui->reset;
1055}
1056
1057void gui_update(struct dt_iop_module_t *self)
1058{
1059 reset_mix(self);
1061 gtk_widget_queue_draw(self->widget);
1062}
1063
1064
1065// gui stuff:
1066
1067static gboolean area_enter_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
1068{
1069 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
1071 if(!c->dragging) c->mouse_y = fabs(c->mouse_y);
1072 c->in_curve = TRUE;
1073 gtk_widget_queue_draw(widget);
1074 return TRUE;
1075}
1076
1077static gboolean area_leave_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
1078{
1079 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
1081 if(!c->dragging) c->mouse_y = -fabs(c->mouse_y);
1082 c->in_curve = FALSE;
1083 gtk_widget_queue_draw(widget);
1084 return TRUE;
1085}
1086
1087// fills in new parameters based on mouse position (in 0,1)
1088static void get_params(dt_iop_atrous_params_t *p, const int ch, const double mouse_x, const double mouse_y,
1089 const float rad)
1090{
1091 for(int k = 0; k < BANDS; k++)
1092 {
1093 const float f = expf(-(mouse_x - p->x[ch][k]) * (mouse_x - p->x[ch][k]) / (rad * rad));
1094 p->y[ch][k] = MAX(0.0f, MIN(1.0f, (1 - f) * p->y[ch][k] + f * mouse_y));
1095 }
1096}
1097
1098static gboolean area_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
1099{
1100 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
1103
1104 const float mix = c->in_curve ? 1.0f : p.mix;
1105
1106 for(int k = 0; k < BANDS; k++)
1107 {
1108 const int ch2 = (int)c->channel2;
1109 float x, y;
1110 _apply_mix(self, ch2, k, mix, p.x[ch2][k], p.y[ch2][k], &x, &y);
1111 dt_draw_curve_set_point(c->minmax_curve, k, x, y);
1112 }
1113
1114 const int inset = INSET;
1115 GtkAllocation allocation;
1116 gtk_widget_get_allocation(widget, &allocation);
1117 int width = allocation.width, height = allocation.height;
1118 cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
1119 cairo_t *cr = cairo_create(cst);
1120 // clear bg, match color of the notebook tabs:
1121 GdkRGBA bright_bg_color, graph_bg;
1122 GtkStyleContext *context = gtk_widget_get_style_context(self->expander);
1123 gboolean color_found = gtk_style_context_lookup_color (context, "graph_overlay", &bright_bg_color);
1124 if(!color_found)
1125 {
1126 bright_bg_color.red = 1.0;
1127 bright_bg_color.green = 0.0;
1128 bright_bg_color.blue = 0.0;
1129 bright_bg_color.alpha = 1.0;
1130 }
1131
1132 color_found = gtk_style_context_lookup_color (context, "graph_bg", &graph_bg);
1133 if(!color_found)
1134 {
1135 graph_bg.red = 1.0;
1136 graph_bg.green = 0.0;
1137 graph_bg.blue = 0.0;
1138 graph_bg.alpha = 1.0;
1139 }
1140
1141 gdk_cairo_set_source_rgba(cr, &bright_bg_color);
1142 cairo_paint(cr);
1143
1144 cairo_translate(cr, inset, inset);
1145 width -= 2 * inset;
1146 height -= 2 * inset;
1147
1148 cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.0));
1149 gdk_cairo_set_source_rgba(cr, &graph_bg);
1150 cairo_rectangle(cr, 0, 0, width, height);
1151 cairo_stroke(cr);
1152
1153 gdk_cairo_set_source_rgba(cr, &bright_bg_color);
1154 cairo_rectangle(cr, 0, 0, width, height);
1155 cairo_fill(cr);
1156
1157 if(c->mouse_y > 0 || c->dragging)
1158 {
1159 const int ch2 = (int)c->channel2;
1160
1161 // draw min/max curves:
1162 get_params(&p, ch2, c->mouse_x, 1., c->mouse_radius);
1163 for(int k = 0; k < BANDS; k++)
1164 dt_draw_curve_set_point(c->minmax_curve, k, p.x[ch2][k], p.y[ch2][k]);
1165 dt_draw_curve_calc_values(c->minmax_curve, 0.0, 1.0, RES, c->draw_min_xs, c->draw_min_ys);
1166
1167 p = *(dt_iop_atrous_params_t *)self->params;
1168 get_params(&p, ch2, c->mouse_x, .0, c->mouse_radius);
1169 for(int k = 0; k < BANDS; k++)
1170 dt_draw_curve_set_point(c->minmax_curve, k, p.x[ch2][k], p.y[ch2][k]);
1171 dt_draw_curve_calc_values(c->minmax_curve, 0.0, 1.0, RES, c->draw_max_xs, c->draw_max_ys);
1172 }
1173
1174 // draw grid
1175 cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(.4));
1176 gdk_cairo_set_source_rgba(cr, &graph_bg);
1177 dt_draw_grid(cr, 8, 0, 0, width, height);
1178
1179 cairo_save(cr);
1180
1181 // draw selected cursor
1182 cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.));
1183 cairo_translate(cr, 0, height);
1184
1185// draw frequency histogram in bg.
1186#if 1
1187 if(c->num_samples > 0)
1188 {
1189 cairo_save(cr);
1190 for(int k = 1; k < c->num_samples; k += 2)
1191 {
1192 cairo_set_source_rgba(cr, graph_bg.red, graph_bg.green, graph_bg.blue, .3);
1193 cairo_move_to(cr, width * c->sample[k - 1], 0.0f);
1194 cairo_line_to(cr, width * c->sample[k - 1], -height);
1195 cairo_line_to(cr, width * c->sample[k], -height);
1196 cairo_line_to(cr, width * c->sample[k], 0.0f);
1197 cairo_fill(cr);
1198 }
1199 if(c->num_samples & 1)
1200 {
1201 cairo_move_to(cr, width * c->sample[c->num_samples - 1], 0.0f);
1202 cairo_line_to(cr, width * c->sample[c->num_samples - 1], -height);
1203 cairo_line_to(cr, 0.0f, -height);
1204 cairo_line_to(cr, 0.0f, 0.0f);
1205 cairo_fill(cr);
1206 }
1207 cairo_restore(cr);
1208 }
1209 if(c->band_max > 0)
1210 {
1211 cairo_save(cr);
1212 cairo_scale(cr, width / (BANDS - 1.0), -(height - DT_PIXEL_APPLY_DPI(5)) / c->band_max);
1213 cairo_set_source_rgba(cr, graph_bg.red, graph_bg.green, graph_bg.blue, .3);
1214 cairo_move_to(cr, 0, 0);
1215 for(int k = 0; k < BANDS; k++) cairo_line_to(cr, k, c->band_hist[k]);
1216 cairo_line_to(cr, BANDS - 1.0, 0.);
1217 cairo_close_path(cr);
1218 cairo_fill(cr);
1219 cairo_restore(cr);
1220 }
1221#endif
1222
1223 // cairo_set_operator(cr, CAIRO_OPERATOR_ADD);
1224 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1225 cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.));
1226 for(int i = 0; i <= atrous_s; i++)
1227 {
1228 // draw curves, selected last.
1229 int ch = ((int)c->channel + i + 1) % (atrous_s + 1);
1230 int ch2 = -1;
1231 const float bgmul = i < atrous_s ? 0.5f : 1.0f;
1232 switch(ch)
1233 {
1234 case atrous_L:
1235 cairo_set_source_rgba(cr, .6, .6, .6, .3 * bgmul);
1236 ch2 = atrous_Lt;
1237 break;
1238 case atrous_c:
1239 cairo_set_source_rgba(cr, .4, .2, .0, .4 * bgmul);
1240 ch2 = atrous_ct;
1241 break;
1242 default: // case atrous_s:
1243 cairo_set_source_rgba(cr, .1, .2, .3, .4 * bgmul);
1244 break;
1245 }
1246 p = *(dt_iop_atrous_params_t *)self->params;
1247
1248 // reverse order if bottom is active (to end up with correct values in minmax_curve):
1249 if(c->channel2 == ch2)
1250 {
1251 ch2 = ch;
1252 ch = c->channel2;
1253 }
1254
1255 if(ch2 >= 0)
1256 {
1257 for(int k = 0; k < BANDS; k++)
1258 {
1259 float x, y;
1260 _apply_mix(self, ch2, k, mix, p.x[ch2][k], p.y[ch2][k], &x, &y);
1261 dt_draw_curve_set_point(c->minmax_curve, k, x, y);
1262 }
1263 dt_draw_curve_calc_values(c->minmax_curve, 0.0, 1.0, RES, c->draw_xs, c->draw_ys);
1264 cairo_move_to(cr, width, -height * p.y[ch2][BANDS - 1]);
1265 for(int k = RES - 2; k >= 0; k--)
1266 cairo_line_to(cr, k * width / (float)(RES - 1), -height * c->draw_ys[k]);
1267 }
1268 else
1269 cairo_move_to(cr, 0, 0);
1270 for(int k = 0; k < BANDS; k++)
1271 {
1272 float x, y;
1273 _apply_mix(self, ch, k, mix, p.x[ch][k], p.y[ch][k], &x, &y);
1274 dt_draw_curve_set_point(c->minmax_curve, k, x, y);
1275 }
1276 dt_draw_curve_calc_values(c->minmax_curve, 0.0, 1.0, RES, c->draw_xs, c->draw_ys);
1277 for(int k = 0; k < RES; k++)
1278 cairo_line_to(cr, k * width / (float)(RES - 1), -height * c->draw_ys[k]);
1279 if(ch2 < 0)
1280 cairo_line_to(cr, width, 0);
1281 cairo_close_path(cr);
1282 cairo_stroke_preserve(cr);
1283 cairo_fill(cr);
1284 }
1285
1286 if(c->mouse_y > 0 || c->dragging)
1287 {
1288 const int ch = (int)c->channel;
1289 const int ch2 = (int)c->channel2;
1290
1291 // draw dots on knots
1292 cairo_save(cr);
1293 if(ch != ch2)
1294 cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
1295 else
1296 cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
1297 cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.));
1298 for(int k = 0; k < BANDS; k++)
1299 {
1300 float x, y;
1301 _apply_mix(self, ch, k, mix, p.x[ch2][k], p.y[ch2][k], &x, &y);
1302 cairo_arc(cr, width * x, -height * y, DT_PIXEL_APPLY_DPI(3.0), 0.0, 2.0 * M_PI);
1303 if(c->x_move == k)
1304 cairo_fill(cr);
1305 else
1306 cairo_stroke(cr);
1307 }
1308 cairo_restore(cr);
1309 }
1310
1311 if(c->mouse_y > 0 || c->dragging)
1312 {
1313 // draw min/max, if selected
1314 // cairo_set_source_rgba(cr, .6, .6, .6, .5);
1315 cairo_move_to(cr, 0, -height * c->draw_min_ys[0]);
1316 for(int k = 1; k < RES; k++)
1317 cairo_line_to(cr, k * width / (float)(RES - 1), -height * c->draw_min_ys[k]);
1318 for(int k = RES - 1; k >= 0; k--)
1319 cairo_line_to(cr, k * width / (float)(RES - 1), -height * c->draw_max_ys[k]);
1320 cairo_close_path(cr);
1321 cairo_fill(cr);
1322 // draw mouse focus circle
1323 cairo_set_source_rgba(cr, .9, .9, .9, .5);
1324 const float pos = RES * c->mouse_x;
1325 int k = (int)pos;
1326 const float f = k - pos;
1327 if(k >= RES - 1) k = RES - 2;
1328 const float ht = -height * (f * c->draw_ys[k] + (1 - f) * c->draw_ys[k + 1]);
1329 cairo_arc(cr, c->mouse_x * width, ht, c->mouse_radius * width, 0, 2. * M_PI);
1330 cairo_stroke(cr);
1331 }
1332
1333 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1334
1335 // draw x positions
1336 cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.));
1337 cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
1338 const float arrw = DT_PIXEL_APPLY_DPI(7.0f);
1339 for(int k = 1; k < BANDS - 1; k++)
1340 {
1341 cairo_move_to(cr, width * p.x[(int)c->channel][k], inset - DT_PIXEL_APPLY_DPI(1));
1342 cairo_rel_line_to(cr, -arrw * .5f, 0);
1343 cairo_rel_line_to(cr, arrw * .5f, -arrw);
1344 cairo_rel_line_to(cr, arrw * .5f, arrw);
1345 cairo_close_path(cr);
1346 if(c->x_move == k)
1347 cairo_fill(cr);
1348 else
1349 cairo_stroke(cr);
1350 }
1351
1352 cairo_restore(cr);
1353
1354 if(c->mouse_y > 0 || c->dragging)
1355 {
1356 // draw labels:
1357 PangoLayout *layout;
1358 PangoRectangle ink;
1359 PangoFontDescription *desc = pango_font_description_copy_static(darktable.bauhaus->pango_font_desc);
1360 pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
1361 pango_font_description_set_absolute_size(desc, (.06 * height) * PANGO_SCALE);
1362 layout = pango_cairo_create_layout(cr);
1363 pango_layout_set_font_description(layout, desc);
1364 gdk_cairo_set_source_rgba(cr, &graph_bg);
1365 cairo_set_font_size(cr, .06 * height);
1366 pango_layout_set_text(layout, _("coarse"), -1);
1367 pango_layout_get_pixel_extents(layout, &ink, NULL);
1368 cairo_move_to(cr, .02 * width - ink.y, .14 * height + ink.width);
1369 cairo_save(cr);
1370 cairo_rotate(cr, -M_PI * .5f);
1371 pango_cairo_show_layout(cr, layout);
1372 cairo_restore(cr);
1373 pango_layout_set_text(layout, _("fine"), -1);
1374 pango_layout_get_pixel_extents(layout, &ink, NULL);
1375 cairo_move_to(cr, .98 * width - ink.height, .14 * height + ink.width);
1376 cairo_save(cr);
1377 cairo_rotate(cr, -M_PI * .5f);
1378 pango_cairo_show_layout(cr, layout);
1379 cairo_restore(cr);
1380
1381 switch(c->channel2)
1382 {
1383 case atrous_L:
1384 case atrous_c:
1385 dt_atrous_show_upper_label(cr, _("contrasty"), layout, ink);
1386 dt_atrous_show_lower_label(cr, _("smooth"), layout, ink);
1387 break;
1388 case atrous_Lt:
1389 case atrous_ct:
1390 dt_atrous_show_upper_label(cr, _("smooth"), layout, ink);
1391 dt_atrous_show_lower_label(cr, _("noisy"), layout, ink);
1392 break;
1393 default: // case atrous_s:
1394 dt_atrous_show_upper_label(cr, _("bold"), layout, ink);
1395 dt_atrous_show_lower_label(cr, _("dull"), layout, ink);
1396 break;
1397 }
1398 pango_font_description_free(desc);
1399 g_object_unref(layout);
1400 }
1401
1402
1403 cairo_destroy(cr);
1404 cairo_set_source_surface(crf, cst, 0, 0);
1405 cairo_paint(crf);
1406 cairo_surface_destroy(cst);
1407 return TRUE;
1408}
1409
1410static gboolean area_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
1411{
1412 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
1415 const int inset = INSET;
1416 GtkAllocation allocation;
1417 gtk_widget_get_allocation(widget, &allocation);
1418 const int height = allocation.height - 2 * inset;
1419 const int width = allocation.width - 2 * inset;
1420 if(!c->dragging) c->mouse_x = CLAMP(event->x - inset, 0, width) / (float)width;
1421 c->mouse_y = 1.0 - CLAMP(event->y - inset, 0, height) / (float)height;
1422
1423 int ch2 = c->channel;
1424 if(c->channel == atrous_L) ch2 = atrous_Lt;
1425 if(c->channel == atrous_c) ch2 = atrous_ct;
1426
1427 if(c->dragging)
1428 {
1429 // drag y-positions
1430 *p = c->drag_params;
1431 if(c->x_move >= 0)
1432 {
1433 const float mx = CLAMP(event->x - inset, 0, width) / (float)width;
1434 if(c->x_move > 0 && c->x_move < BANDS - 1)
1435 {
1436 const float minx = p->x[c->channel][c->x_move - 1] + 0.001f;
1437 const float maxx = p->x[c->channel][c->x_move + 1] - 0.001f;
1438 p->x[ch2][c->x_move] = p->x[c->channel][c->x_move] = fminf(maxx, fmaxf(minx, mx));
1439 }
1440 }
1441 else
1442 {
1443 get_params(p, c->channel2, c->mouse_x, c->mouse_y + c->mouse_pick, c->mouse_radius);
1444 }
1445 gtk_widget_queue_draw(widget);
1447 }
1448 else if(event->y > height)
1449 {
1450 // move x-positions
1451 c->x_move = 0;
1452 float dist = fabs(p->x[c->channel][0] - c->mouse_x);
1453 for(int k = 1; k < BANDS; k++)
1454 {
1455 const float d2 = fabs(p->x[c->channel][k] - c->mouse_x);
1456 if(d2 < dist)
1457 {
1458 c->x_move = k;
1459 dist = d2;
1460 }
1461 }
1462 gtk_widget_queue_draw(widget);
1463 }
1464 else
1465 {
1466 // choose between bottom and top curve:
1467 const int ch = c->channel;
1468 float dist = 1000000.0f;
1469 for(int k = 0; k < BANDS; k++)
1470 {
1471 float d2 = fabs(p->x[c->channel][k] - c->mouse_x);
1472 if(d2 < dist)
1473 {
1474 if(fabs(c->mouse_y - p->y[ch][k]) < fabs(c->mouse_y - p->y[ch2][k]))
1475 c->channel2 = ch;
1476 else
1477 c->channel2 = ch2;
1478 dist = d2;
1479 }
1480 }
1481 // don't move x-positions:
1482 c->x_move = -1;
1483 gtk_widget_queue_draw(widget);
1484 }
1485 return TRUE;
1486}
1487
1488static gboolean area_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
1489{
1490 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
1491 if(event->button == 1 && event->type == GDK_2BUTTON_PRESS)
1492 {
1493 // reset current curve
1497 reset_mix(self);
1498 for(int k = 0; k < BANDS; k++)
1499 {
1500 p->x[c->channel2][k] = d->x[c->channel2][k];
1501 p->y[c->channel2][k] = d->y[c->channel2][k];
1502 }
1503 gtk_widget_queue_draw(self->widget);
1505 }
1506 else if(event->button == 1)
1507 {
1508 // set active point
1510 reset_mix(self);
1511 const int inset = INSET;
1512 GtkAllocation allocation;
1513 gtk_widget_get_allocation(widget, &allocation);
1514 const int height = allocation.height - 2 * inset;
1515 const int width = allocation.width - 2 * inset;
1516 c->mouse_pick
1517 = dt_draw_curve_calc_value(c->minmax_curve, CLAMP(event->x - inset, 0, width) / (float)width);
1518 c->mouse_pick -= 1.0 - CLAMP(event->y - inset, 0, height) / (float)height;
1519 c->dragging = 1;
1520 return TRUE;
1521 }
1522 return FALSE;
1523}
1524
1525static gboolean area_button_release(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
1526{
1527 if(event->button == 1)
1528 {
1529 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
1531 c->dragging = 0;
1532 reset_mix(self);
1533 return TRUE;
1534 }
1535 return FALSE;
1536}
1537
1538static gboolean area_scrolled(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
1539{
1540 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
1542
1543 int delta_y;
1544 if(dt_gui_get_scroll_unit_deltas(event, NULL, &delta_y))
1545 {
1546 c->mouse_radius = CLAMP(c->mouse_radius * (1.0 + 0.1 * delta_y), 0.25 / BANDS, 1.0);
1547 gtk_widget_queue_draw(widget);
1548 }
1549 return TRUE;
1550}
1551
1552static void tab_switch(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data)
1553{
1554 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
1556 if(darktable.gui->reset) return;
1557 c->channel = c->channel2 = (atrous_channel_t)page_num;
1558 gtk_widget_queue_draw(self->widget);
1559}
1560
1561static void mix_callback(GtkWidget *slider, gpointer user_data)
1562{
1563 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
1564 if(darktable.gui->reset) return;
1566 p->mix = dt_bauhaus_slider_get(slider);
1567 gtk_widget_queue_draw(self->widget);
1569}
1570
1571void gui_init(struct dt_iop_module_t *self)
1572{
1575
1576 c->num_samples = 0;
1577 c->band_max = 0;
1578 c->channel = c->channel2 = dt_conf_get_int("plugins/darkroom/atrous/gui_channel");
1579 int ch = (int)c->channel;
1580 c->minmax_curve = dt_draw_curve_new(0.0, 1.0, CATMULL_ROM);
1581 for(int k = 0; k < BANDS; k++)
1582 (void)dt_draw_curve_add_point(c->minmax_curve, p->x[ch][k], p->y[ch][k]);
1583 c->mouse_x = c->mouse_y = c->mouse_pick = -1.0;
1584 c->dragging = 0;
1585 self->timeout_handle = 0;
1586 c->x_move = -1;
1587 c->mouse_radius = 1.0 / BANDS;
1588 c->in_curve = FALSE;
1589
1590 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1591
1592 c->channel_tabs = dt_ui_notebook_new();
1593 dt_ui_notebook_page(c->channel_tabs, N_("luma"), _("change lightness at each feature size"));
1594 dt_ui_notebook_page(c->channel_tabs, N_("chroma"), _("change color saturation at each feature size"));
1595 dt_ui_notebook_page(c->channel_tabs, N_("edges"), _("change edge halos at each feature size\nonly changes results of luma and chroma tabs"));
1596 gtk_widget_show(gtk_notebook_get_nth_page(c->channel_tabs, c->channel));
1597 gtk_notebook_set_current_page(c->channel_tabs, c->channel);
1598 g_signal_connect(G_OBJECT(c->channel_tabs), "switch_page", G_CALLBACK(tab_switch), self);
1599 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(c->channel_tabs), FALSE, FALSE, 0);
1600
1601 // graph
1602 c->area = GTK_DRAWING_AREA(gtk_drawing_area_new());
1603 gtk_widget_set_hexpand(GTK_WIDGET(c->area), TRUE);
1604 gtk_box_pack_start(GTK_BOX(self->widget),
1605 dt_ui_resizable_drawing_area(GTK_WIDGET(c->area),
1606 "plugins/darkroom/atrous/graphheight", 280, 100),
1607 FALSE, FALSE, 0);
1608
1609 gtk_widget_add_events(GTK_WIDGET(c->area),
1610 GDK_POINTER_MOTION_MASK
1611 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1612 | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK
1614 g_object_set_data(G_OBJECT(c->area), "iop-instance", self);
1615 g_signal_connect(G_OBJECT(c->area), "draw", G_CALLBACK(area_draw), self);
1616 g_signal_connect(G_OBJECT(c->area), "button-press-event", G_CALLBACK(area_button_press), self);
1617 g_signal_connect(G_OBJECT(c->area), "button-release-event", G_CALLBACK(area_button_release), self);
1618 g_signal_connect(G_OBJECT(c->area), "motion-notify-event", G_CALLBACK(area_motion_notify), self);
1619 g_signal_connect(G_OBJECT(c->area), "leave-notify-event", G_CALLBACK(area_leave_notify), self);
1620 g_signal_connect(G_OBJECT(c->area), "enter-notify-event", G_CALLBACK(area_enter_notify), self);
1621 g_signal_connect(G_OBJECT(c->area), "scroll-event", G_CALLBACK(area_scrolled), self);
1622
1623 // mix slider
1624 c->mix = dt_bauhaus_slider_from_params(self, N_("mix"));
1625 gtk_widget_set_tooltip_text(c->mix, _("make effect stronger or weaker"));
1626 g_signal_connect(G_OBJECT(c->mix), "value-changed", G_CALLBACK(mix_callback), self);
1627}
1628
1630{
1632 dt_conf_set_int("plugins/darkroom/atrous/gui_channel", c->channel);
1633 dt_draw_curve_destroy(c->minmax_curve);
1635
1637}
1638
1639// clang-format off
1640// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1641// vim: shiftwidth=2 expandtab tabstop=2 cindent
1642// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1643// clang-format on
static double dist(double x1, double y1, double x2, double y2)
Definition ashift_lsd.c:250
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void init(dt_iop_module_t *module)
Definition atrous.c:666
static gboolean area_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
Definition atrous.c:1488
#define GAUSS(x, sigma)
Definition atrous.c:773
const char ** description(struct dt_iop_module_t *self)
Definition atrous.c:173
static __DT_CLONE_TARGETS__ int get_scales(float(*thrs)[4], float(*boost)[4], float *sharp, const dt_iop_atrous_data_t *const d, const dt_iop_roi_t *roi_in, const dt_dev_pixelpipe_iop_t *const piece)
Definition atrous.c:246
int default_group()
Definition atrous.c:182
static gboolean area_leave_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
Definition atrous.c:1077
#define BANDS
Definition atrous.c:89
static void reset_mix(dt_iop_module_t *self)
Definition atrous.c:1047
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *params, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition atrous.c:716
atrous_channel_t
Definition atrous.c:108
@ atrous_s
Definition atrous.c:111
@ atrous_ct
Definition atrous.c:113
@ atrous_L
Definition atrous.c:109
@ atrous_none
Definition atrous.c:114
@ atrous_c
Definition atrous.c:110
@ atrous_Lt
Definition atrous.c:112
const char * aliases()
Definition atrous.c:168
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition atrous.c:747
#define RES
Definition atrous.c:91
const char * name()
Definition atrous.c:163
void gui_update(struct dt_iop_module_t *self)
Definition atrous.c:1057
void gui_init(struct dt_iop_module_t *self)
Definition atrous.c:1571
static void mix_callback(GtkWidget *slider, gpointer user_data)
Definition atrous.c:1561
static void _apply_mix(dt_iop_module_t *self, const int ch, const int k, const float mix, const float px, const float py, float *x, float *y)
Definition atrous.c:706
#define dt_atrous_show_lower_label(cr, text, layout, ink)
Definition atrous.c:100
static __DT_CLONE_TARGETS__ int process_wavelets(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const eaw_decompose_t decompose, const eaw_synthesize_t synthesize)
Definition atrous.c:295
void tiling_callback(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
Definition atrous.c:645
void cleanup_global(dt_iop_module_so_t *module)
Definition atrous.c:694
static void get_params(dt_iop_atrous_params_t *p, const int ch, const double mouse_x, const double mouse_y, const float rad)
Definition atrous.c:1088
static gboolean area_enter_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
Definition atrous.c:1067
static gboolean area_button_release(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
Definition atrous.c:1525
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition atrous.c:192
static gboolean area_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
Definition atrous.c:1410
int flags()
Definition atrous.c:187
static gboolean area_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
Definition atrous.c:1098
void gui_cleanup(struct dt_iop_module_t *self)
Definition atrous.c:1629
void init_presets(dt_iop_module_so_t *self)
Definition atrous.c:775
static __DT_CLONE_TARGETS__ int get_samples(float *t, const dt_iop_atrous_data_t *const d, const dt_iop_roi_t *roi_in, const dt_dev_pixelpipe_iop_t *const piece)
Definition atrous.c:224
#define INSET
Definition atrous.c:83
#define MAX_NUM_SCALES
Definition atrous.c:90
static gboolean area_scrolled(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
Definition atrous.c:1538
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition atrous.c:764
int process(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o)
Definition atrous.c:369
void init_global(dt_iop_module_so_t *module)
Definition atrous.c:680
#define dt_atrous_show_upper_label(cr, text, layout, ink)
Definition atrous.c:93
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)
Definition atrous.c:510
static void tab_switch(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data)
Definition atrous.c:1552
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
Definition atrous.c:197
#define m
Definition basecurve.c:278
float dt_bauhaus_slider_get(GtkWidget *widget)
Definition bauhaus.c:3483
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3506
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
@ DEVELOP_BLEND_CS_RGB_DISPLAY
Definition blend.h:59
const double thrs
Definition chart/main.c:54
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
@ IOP_CS_LAB
const dt_aligned_pixel_t f
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
#define CATMULL_ROM
Definition curve_tools.h:34
darktable_t darktable
Definition darktable.c:181
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
#define dt_free_align(ptr)
Definition darktable.h:481
static void * dt_calloc_align(size_t size)
Definition darktable.h:488
#define __OMP_SIMD__(...)
Definition darktable.h:262
@ DT_DEBUG_OPENCL
Definition darktable.h:722
#define dt_free(ptr)
Definition darktable.h:456
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
Definition darktable.h:151
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:453
#define __DT_CLONE_TARGETS__
Definition darktable.h:367
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
#define dt_database_start_transaction(db)
Definition database.h:77
#define dt_database_release_transaction(db)
Definition database.h:78
#define dt_dev_add_history_item(dev, module, enable, redraw)
void dt_iop_params_t
Definition dev_history.h:41
gboolean dt_dev_pixelpipe_has_preview_output(const dt_develop_t *dev, const dt_dev_pixelpipe_t *pipe, const dt_iop_roi_t *roi)
Definition develop.c:367
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
Definition develop.h:118
static void dt_draw_curve_calc_values(dt_draw_curve_t *c, const float min, const float max, const int res, float *x, float *y)
Definition draw.h:309
static void dt_draw_grid(cairo_t *cr, const int num, const int left, const int top, const int right, const int bottom)
Definition draw.h:143
static float dt_draw_curve_calc_value(dt_draw_curve_t *c, const float x)
Definition draw.h:345
static void dt_draw_curve_destroy(dt_draw_curve_t *c)
Definition draw.h:282
static void dt_draw_curve_set_point(dt_draw_curve_t *c, const int num, const float x, const float y)
Definition draw.h:288
static int dt_draw_curve_add_point(dt_draw_curve_t *c, const float x, const float y)
Definition draw.h:364
static dt_draw_curve_t * dt_draw_curve_new(const float min, const float max, unsigned int type)
Definition draw.h:266
void eaw_decompose(float *const restrict out, const float *const restrict in, float *const restrict detail, const int scale, const float sharpen, const int32_t width, const int32_t height)
Definition eaw.c:80
void eaw_synthesize(float *const out, const float *const in, const float *const restrict detail, const float *const restrict threshold, const float *const restrict boost, const int32_t width, const int32_t height)
Definition eaw.c:158
gboolean dt_gui_get_scroll_unit_deltas(const GdkEventScroll *event, int *delta_x, int *delta_y)
Definition gtk.c:219
GtkWidget * dt_ui_resizable_drawing_area(GtkWidget *area, char *config_str, int default_height, int min_height)
Make a self-drawing widget (typically a GtkDrawingArea graph or scope) vertically resizable.
Definition gtk.c:2836
GtkWidget * dt_ui_notebook_page(GtkNotebook *notebook, const char *text, const char *tooltip)
Definition gtk.c:2259
GtkNotebook * dt_ui_notebook_new()
Definition gtk.c:2254
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
Definition gtk.h:316
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
#define DT_PIXEL_APPLY_DPI(value)
Definition gtk.h:90
void dt_gui_presets_add_generic(const char *name, dt_dev_operation_t op, const int32_t version, const void *params, const int32_t params_size, const int32_t enabled, const dt_develop_blend_colorspace_t blend_cst)
void dt_gui_throttle_cancel(gpointer source)
void dt_gui_throttle_queue(gpointer source, dt_gui_throttle_callback_t callback, gpointer user_data)
int dt_iop_alloc_image_buffers(struct dt_iop_module_t *const module, const struct dt_iop_roi_t *const roi_in, const struct dt_iop_roi_t *const roi_out,...)
Definition imagebuf.c:31
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)
Definition imagebuf.h:87
void dt_iop_throttled_history_update(gpointer data)
Definition imageop.c:3135
void dt_iop_default_init(dt_iop_module_t *module)
Definition imageop.c:316
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)
Definition imageop.c:3141
#define IOP_GUI_FREE
Definition imageop.h:602
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:167
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:169
@ IOP_GROUP_SHARPNESS
Definition imageop.h:141
#define IOP_GUI_ALLOC(module)
Definition imageop.h:599
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
Definition imageop_gui.c:77
static const float x
const float *const const float coeff[3]
const int t
static float mix(const float a, const float b, const float t)
Definition liquify.c:705
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
#define M_PI
Definition math.h:45
float dt_aligned_pixel_t[4]
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2136
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
Definition opencl.c:2471
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2030
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
Definition opencl.c:2332
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)
Definition opencl.c:2261
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2073
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
Definition opencl.c:2127
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2383
#define ROUNDUPDHT(a, b)
Definition opencl.h:82
#define ROUNDUPDWD(a, b)
Definition opencl.h:81
struct _GtkWidget GtkWidget
Definition splash.h:29
const float sigma
const float noise
struct dt_gui_gtk_t * gui
Definition darktable.h:775
const struct dt_database_t * db
Definition darktable.h:779
struct dt_bauhaus_t * bauhaus
Definition darktable.h:778
struct dt_develop_t * develop
Definition darktable.h:770
PangoFontDescription * pango_font_desc
Definition bauhaus.h:274
struct dt_iop_module_t *void * data
int32_t gui_attached
Definition develop.h:162
gint scroll_mask
Definition gtk.h:224
int32_t reset
Definition gtk.h:172
dt_draw_curve_t * curve[atrous_none]
Definition atrous.c:159
GtkDrawingArea * area
Definition atrous.c:128
atrous_channel_t channel2
Definition atrous.c:136
dt_iop_atrous_params_t drag_params
Definition atrous.c:132
GtkNotebook * channel_tabs
Definition atrous.c:129
atrous_channel_t channel
Definition atrous.c:136
dt_draw_curve_t * minmax_curve
Definition atrous.c:135
float y[atrous_none][6]
Definition atrous.c:121
float x[atrous_none][6]
Definition atrous.c:120
GModule *dt_dev_operation_t op
Definition imageop.h:230
dt_iop_global_data_t * data
Definition imageop.h:233
dt_iop_params_t * default_params
Definition imageop.h:307
GtkWidget * widget
Definition imageop.h:337
struct dt_develop_t * dev
Definition imageop.h:296
dt_iop_gui_data_t * gui_data
Definition imageop.h:311
dt_iop_global_data_t * global_data
Definition imageop.h:314
GtkWidget * expander
Definition imageop.h:345
guint timeout_handle
Definition imageop.h:371
dt_iop_params_t * params
Definition imageop.h:307
Region of interest passed through the pixelpipe.
Definition imageop.h:72
double scale
Definition imageop.h:74
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29