grain.c 21.5 KB
Newer Older
1 2
/*
    This file is part of darktable,
3
    copyright (c) 2010-2012 Henrik Andersson.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

    darktable is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    darktable is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with darktable.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
19
#include "config.h"
20 21
#endif
#include <assert.h>
22 23
#include <math.h>
#include <stdlib.h>
24
#include <string.h>
25

26
#include "bauhaus/bauhaus.h"
27
#include "control/control.h"
28 29
#include "develop/develop.h"
#include "develop/imageop.h"
30
#include "gui/accelerators.h"
31
#include "gui/gtk.h"
32
#include "iop/iop_api.h"
33 34 35
#include <gtk/gtk.h>
#include <inttypes.h>

36
#define GRAIN_LIGHTNESS_STRENGTH_SCALE 0.15
Henrik Andersson's avatar
Henrik Andersson committed
37
// (m_pi/2)/4 = half hue colorspan
38 39 40 41
#define GRAIN_HUE_COLORRANGE 0.392699082
#define GRAIN_HUE_STRENGTH_SCALE 0.25
#define GRAIN_SATURATION_STRENGTH_SCALE 0.25
#define GRAIN_RGB_STRENGTH_SCALE 0.25
42

43
#define GRAIN_SCALE_FACTOR 213.2
44

45 46
#define GRAIN_LUT_SIZE 128
#define GRAIN_LUT_DELTA_MAX 2.0
47
#define GRAIN_LUT_DELTA_MIN 0.0001
48 49
#define GRAIN_LUT_PAPER_GAMMA 1.0

50
#define CLIP(x) ((x < 0) ? 0.0 : (x > 1.0) ? 1.0 : x)
Andrea Volpato's avatar
Andrea Volpato committed
51
DT_MODULE_INTROSPECTION(2, dt_iop_grain_params_t)
52

53 54 55

typedef enum _dt_iop_grain_channel_t
{
56
  DT_GRAIN_CHANNEL_HUE = 0,
57 58 59
  DT_GRAIN_CHANNEL_SATURATION,
  DT_GRAIN_CHANNEL_LIGHTNESS,
  DT_GRAIN_CHANNEL_RGB
60
} _dt_iop_grain_channel_t;
61 62 63 64 65 66

typedef struct dt_iop_grain_params_t
{
  _dt_iop_grain_channel_t channel;
  float scale;
  float strength;
67
  float midtones_bias;
68
} dt_iop_grain_params_t;
69

70 71
typedef struct dt_iop_grain_gui_data_t
{
72
  GtkBox *vbox;
73
  GtkWidget *label1, *label2, *label3; // channel, scale, strength
74
  GtkWidget *scale1, *scale2, *scale3; // scale, strength, midtones_bias
75
} dt_iop_grain_gui_data_t;
76 77 78 79

typedef struct dt_iop_grain_data_t
{
  _dt_iop_grain_channel_t channel;
80
  float scale;
81
  float strength;
82 83
  float midtones_bias;
  float grain_lut[GRAIN_LUT_SIZE * GRAIN_LUT_SIZE];
84 85 86
} dt_iop_grain_data_t;


Andrea Volpato's avatar
Andrea Volpato committed
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params,
                  const int new_version)
{
  if(old_version == 1 && new_version == 2)
  {
    typedef struct dt_iop_grain_params_v1_t
    {
      _dt_iop_grain_channel_t channel;
      float scale;
      float strength;
    } dt_iop_grain_params_v1_t;

    const dt_iop_grain_params_v1_t *o = old_params;
    dt_iop_grain_params_t *n = new_params;

    n->channel = o->channel;
    n->scale = o->scale;
    n->strength = o->strength;
    n->midtones_bias = 0.0; // it produces the same results as the old version

    return 0;
  }
  return 1;
}


113 114 115 116 117 118 119 120 121 122 123 124 125
static int grad3[12][3] = { { 1, 1, 0 },
                            { -1, 1, 0 },
                            { 1, -1, 0 },
                            { -1, -1, 0 },
                            { 1, 0, 1 },
                            { -1, 0, 1 },
                            { 1, 0, -1 },
                            { -1, 0, -1 },
                            { 0, 1, 1 },
                            { 0, -1, 1 },
                            { 0, 1, -1 },
                            { 0, -1, -1 } };

126
static int permutation[]
127 128 129 130 131 132 133 134 135 136 137 138 139
    = { 151, 160, 137, 91,  90,  15,  131, 13,  201, 95,  96,  53,  194, 233, 7,   225, 140, 36,  103, 30,
        69,  142, 8,   99,  37,  240, 21,  10,  23,  190, 6,   148, 247, 120, 234, 75,  0,   26,  197, 62,
        94,  252, 219, 203, 117, 35,  11,  32,  57,  177, 33,  88,  237, 149, 56,  87,  174, 20,  125, 136,
        171, 168, 68,  175, 74,  165, 71,  134, 139, 48,  27,  166, 77,  146, 158, 231, 83,  111, 229, 122,
        60,  211, 133, 230, 220, 105, 92,  41,  55,  46,  245, 40,  244, 102, 143, 54,  65,  25,  63,  161,
        1,   216, 80,  73,  209, 76,  132, 187, 208, 89,  18,  169, 200, 196, 135, 130, 116, 188, 159, 86,
        164, 100, 109, 198, 173, 186, 3,   64,  52,  217, 226, 250, 124, 123, 5,   202, 38,  147, 118, 126,
        255, 82,  85,  212, 207, 206, 59,  227, 47,  16,  58,  17,  182, 189, 28,  42,  223, 183, 170, 213,
        119, 248, 152, 2,   44,  154, 163, 70,  221, 153, 101, 155, 167, 43,  172, 9,   129, 22,  39,  253,
        19,  98,  108, 110, 79,  113, 224, 232, 178, 185, 112, 104, 218, 246, 97,  228, 251, 34,  242, 193,
        238, 210, 144, 12,  191, 179, 162, 241, 81,  51,  145, 235, 249, 14,  239, 107, 49,  192, 214, 31,
        181, 199, 106, 157, 184, 84,  204, 176, 115, 121, 50,  45,  127, 4,   150, 254, 138, 236, 205, 93,
        222, 114, 67,  29,  24,  72,  243, 141, 128, 195, 78,  66,  215, 61,  156, 180 };
Henrik Andersson's avatar
Henrik Andersson committed
140 141

static int perm[512];
142 143
static void _simplex_noise_init()
{
144
  for(int i = 0; i < 512; i++) perm[i] = permutation[i & 255];
145
}
146
static double dot(int g[], double x, double y, double z)
147
{
148
  return g[0] * x + g[1] * y + g[2] * z;
149
}
Henrik Andersson's avatar
Henrik Andersson committed
150

151
#define FASTFLOOR(x) (x > 0 ? (int)(x) : (int)(x)-1)
Henrik Andersson's avatar
Henrik Andersson committed
152

153
static double _simplex_noise(double xin, double yin, double zin)
154
{
155
  double n0, n1, n2, n3; // Noise contributions from the four corners
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
                         // Skew the input space to determine which simplex cell we're in
  double F3 = 1.0 / 3.0;
  double s = (xin + yin + zin) * F3; // Very nice and simple skew factor for 3D
  int i = FASTFLOOR(xin + s);
  int j = FASTFLOOR(yin + s);
  int k = FASTFLOOR(zin + s);
  double G3 = 1.0 / 6.0; // Very nice and simple unskew factor, too
  double t = (i + j + k) * G3;
  double X0 = i - t; // Unskew the cell origin back to (x,y,z) space
  double Y0 = j - t;
  double Z0 = k - t;
  double x0 = xin - X0; // The x,y,z distances from the cell origin
  double y0 = yin - Y0;
  double z0 = zin - Z0;
  // For the 3D case, the simplex shape is a slightly irregular tetrahedron.
  // Determine which simplex we are in.
172 173
  int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords
  int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords
174
  if(x0 >= y0)
175
  {
176
    if(y0 >= z0)
177
    {
178 179 180 181 182 183
      i1 = 1; // X Y Z order
      j1 = 0;
      k1 = 0;
      i2 = 1;
      j2 = 1;
      k2 = 0;
184
    }
185
    else if(x0 >= z0)
186
    {
187 188 189 190 191 192
      i1 = 1; // X Z Y order
      j1 = 0;
      k1 = 0;
      i2 = 1;
      j2 = 0;
      k2 = 1;
193 194 195
    }
    else
    {
196 197 198 199 200 201
      i1 = 0; // Z X Y order
      j1 = 0;
      k1 = 1;
      i2 = 1;
      j2 = 0;
      k2 = 1;
202 203
    }
  }
204
  else // x0<y0
205
  {
206
    if(y0 < z0)
207
    {
208 209 210 211 212 213
      i1 = 0; // Z Y X order
      j1 = 0;
      k1 = 1;
      i2 = 0;
      j2 = 1;
      k2 = 1;
214
    }
215
    else if(x0 < z0)
216
    {
217 218 219 220 221 222
      i1 = 0; // Y Z X order
      j1 = 1;
      k1 = 0;
      i2 = 0;
      j2 = 1;
      k2 = 1;
223 224 225
    }
    else
    {
226 227 228 229 230 231
      i1 = 0; // Y X Z order
      j1 = 1;
      k1 = 0;
      i2 = 1;
      j2 = 1;
      k2 = 0;
232 233
    }
  }
234 235 236 237 238 239 240 241 242 243 244 245 246
  //  A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
  //  a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
  //  a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
  //  c = 1/6.
  double x1 = x0 - i1 + G3; // Offsets for second corner in (x,y,z) coords
  double y1 = y0 - j1 + G3;
  double z1 = z0 - k1 + G3;
  double x2 = x0 - i2 + 2.0 * G3; // Offsets for third corner in (x,y,z) coords
  double y2 = y0 - j2 + 2.0 * G3;
  double z2 = z0 - k2 + 2.0 * G3;
  double x3 = x0 - 1.0 + 3.0 * G3; // Offsets for last corner in (x,y,z) coords
  double y3 = y0 - 1.0 + 3.0 * G3;
  double z3 = z0 - 1.0 + 3.0 * G3;
Henrik Andersson's avatar
Henrik Andersson committed
247 248 249 250
  // Work out the hashed gradient indices of the four simplex corners
  int ii = i & 255;
  int jj = j & 255;
  int kk = k & 255;
251 252 253 254
  int gi0 = perm[ii + perm[jj + perm[kk]]] % 12;
  int gi1 = perm[ii + i1 + perm[jj + j1 + perm[kk + k1]]] % 12;
  int gi2 = perm[ii + i2 + perm[jj + j2 + perm[kk + k2]]] % 12;
  int gi3 = perm[ii + 1 + perm[jj + 1 + perm[kk + 1]]] % 12;
Henrik Andersson's avatar
Henrik Andersson committed
255
  // Calculate the contribution from the four corners
256 257 258
  double t0 = 0.6 - x0 * x0 - y0 * y0 - z0 * z0;
  if(t0 < 0)
    n0 = 0.0;
259 260
  else
  {
Henrik Andersson's avatar
Henrik Andersson committed
261 262 263
    t0 *= t0;
    n0 = t0 * t0 * dot(grad3[gi0], x0, y0, z0);
  }
264 265 266
  double t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1;
  if(t1 < 0)
    n1 = 0.0;
267 268
  else
  {
Henrik Andersson's avatar
Henrik Andersson committed
269 270 271
    t1 *= t1;
    n1 = t1 * t1 * dot(grad3[gi1], x1, y1, z1);
  }
272 273 274
  double t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2;
  if(t2 < 0)
    n2 = 0.0;
275 276
  else
  {
Henrik Andersson's avatar
Henrik Andersson committed
277 278 279
    t2 *= t2;
    n2 = t2 * t2 * dot(grad3[gi2], x2, y2, z2);
  }
280 281 282
  double t3 = 0.6 - x3 * x3 - y3 * y3 - z3 * z3;
  if(t3 < 0)
    n3 = 0.0;
283 284
  else
  {
Henrik Andersson's avatar
Henrik Andersson committed
285 286 287 288 289
    t3 *= t3;
    n3 = t3 * t3 * dot(grad3[gi3], x3, y3, z3);
  }
  // Add contributions from each corner to get the final noise value.
  // The result is scaled to stay just inside [-1,1]
290
  return 32.0 * (n0 + n1 + n2 + n3);
Henrik Andersson's avatar
Henrik Andersson committed
291 292 293 294 295
}



#define PRIME_LEVELS 4
296 297
// static uint64_t _low_primes[PRIME_LEVELS] ={ 12503,14029,15649, 11369 };
// uint64_t _mid_primes[PRIME_LEVELS] ={ 784697,875783, 536461,639259};
Henrik Andersson's avatar
Henrik Andersson committed
298

299
/*static double __value_noise(uint32_t level,uint32_t x,uint32_t y)
300
{
Henrik Andersson's avatar
Henrik Andersson committed
301
  //uint32_t lvl=level%PRIME_LEVELS;
302 303
  uint32_t n = x + y * 57;
  n = (n<<13) ^ n;
304
  return ( 1.0 - (( (n * (n * n * 15731 + 789221) +1376312589) & 0x7fffffff) / 1073741824.0));
305 306
}

307
static double __value_smooth_noise(uint32_t level,double x,double y)
308
{
309 310 311 312
  double corners = ( __value_noise(level,x-1, y-1)+__value_noise(level,x+1, y-1)+__value_noise(level,x-1,
y+1)+__value_noise(level,x+1, y+1) ) / 16;
  double sides   = ( __value_noise(level,x-1, y)  +__value_noise(level,x+1, y)  +__value_noise(level,x, y-1)
+__value_noise(level,x, y+1) ) /  8;
Henrik Andersson's avatar
Henrik Andersson committed
313
  double center  =  __value_noise(level,x, y) / 4;
314 315 316
  return corners + sides + center;
}

317
static double __preline_cosine_interpolate(double a,double b,double x)
318 319
{
  double ft = x * 3.1415927;
320 321
  double f = (1 - cos(ft)) * .5;
  return  a*(1-f) + b*f;
322 323
}

324
static double __value_interpolate(uint32_t level,double x,double y)
325 326 327 328
{
  double fx = x - (uint32_t)x;
  double fy = y - (uint32_t)y;

Henrik Andersson's avatar
Henrik Andersson committed
329 330 331 332
  double v1 = __value_smooth_noise(level,(uint32_t)x,     (uint32_t)y);
  double v2 = __value_smooth_noise(level,(uint32_t)x + 1, (uint32_t)y);
  double v3 = __value_smooth_noise(level,(uint32_t)x,     (uint32_t)y + 1);
  double v4 = __value_smooth_noise(level,(uint32_t)x + 1, (uint32_t)y + 1);
333 334 335 336 337 338

  double i1 = __preline_cosine_interpolate(v1 , v2 , fx);
  double i2 = __preline_cosine_interpolate(v3 , v4 , fx);

  return __preline_cosine_interpolate(i1 , i2 , fy);
}
339
static double _perlin_2d_noise(double x,double y,uint32_t octaves,double persistance,double z)
340
{
Henrik Andersson's avatar
Henrik Andersson committed
341
  double f=1,a=1,total=0;
342

Henrik Andersson's avatar
Henrik Andersson committed
343 344
  for(int o=0;o<octaves;o++) {
    total+= (__value_interpolate(o,x*f/z,y*f/z)*a);
345 346 347 348
    f=2*o;
    a=persistance*o;
  }
  return total;
349
}*/
350

351
static double _simplex_2d_noise(double x, double y, uint32_t octaves, double persistance, double z)
Henrik Andersson's avatar
Henrik Andersson committed
352
{
353 354 355 356 357
  double total = 0;

  // parametrization of octaves to match power spectrum of real grain scans
  static double f[] = {0.4910, 0.9441, 1.7280};
  static double a[] = {0.2340, 0.7850, 1.2150};
358

359
  for(uint32_t o = 0; o < octaves; o++)
360
  {
361
    total += (_simplex_noise(x * f[o] / z, y * f[o] / z, o) * a[o]);
Henrik Andersson's avatar
Henrik Andersson committed
362 363 364
  }
  return total;
}
365

Andrea Volpato's avatar
Andrea Volpato committed
366
static float paper_resp(float exposure, float mb, float gp)
367 368
{
  float density;
Andrea Volpato's avatar
Andrea Volpato committed
369 370
  float delta = GRAIN_LUT_DELTA_MAX * expf((mb / 100.0f) * logf(GRAIN_LUT_DELTA_MIN));
  density = (1.0f + 2.0f * delta) / (1.0f + expf( (4.0f * gp * (0.5f - exposure)) / (1.0f + 2.0f * delta) )) - delta;
371 372 373
  return density;
}

Andrea Volpato's avatar
Andrea Volpato committed
374
static float paper_resp_inverse(float density, float mb, float gp)
375 376
{
  float exposure;
Andrea Volpato's avatar
Andrea Volpato committed
377
  float delta = GRAIN_LUT_DELTA_MAX * expf((mb / 100.0f) * logf(GRAIN_LUT_DELTA_MIN));
Andrea Volpato's avatar
Andrea Volpato committed
378
  exposure = -logf((1.0f + 2.0f * delta) / (density + delta) - 1.0f) * (1.0f + 2.0f * delta) / (4.0f * gp) + 0.5f;
379 380 381
  return exposure;
}

Andrea Volpato's avatar
Andrea Volpato committed
382
static void evaluate_grain_lut(float *grain_lut, const float mb)
383 384 385 386 387
{
  for(int i = 0; i < GRAIN_LUT_SIZE; i++)
  {
    for(int j = 0; j < GRAIN_LUT_SIZE; j++)
    {
Andrea Volpato's avatar
Andrea Volpato committed
388 389
      float gu = (float)i / (GRAIN_LUT_SIZE - 1) - 0.5;
      float l = (float)j / (GRAIN_LUT_SIZE - 1);
Andrea Volpato's avatar
Andrea Volpato committed
390
      grain_lut[j * GRAIN_LUT_SIZE + i] = 100.0f * (paper_resp(gu + paper_resp_inverse(l, mb, GRAIN_LUT_PAPER_GAMMA), mb, GRAIN_LUT_PAPER_GAMMA) - l);
391 392 393 394
    }
  }
}

Andrea Volpato's avatar
Andrea Volpato committed
395
static float dt_lut_lookup_2d_1c(const float *grain_lut, const float x, const float y)
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
{
  const float _x = CLAMPS((x + 0.5) * (GRAIN_LUT_SIZE - 1), 0, GRAIN_LUT_SIZE - 1);
  const float _y = CLAMPS(y * (GRAIN_LUT_SIZE - 1), 0, GRAIN_LUT_SIZE - 1);

  const int _x0 = _x < GRAIN_LUT_SIZE - 2 ? _x : GRAIN_LUT_SIZE - 2;
  const int _y0 = _y < GRAIN_LUT_SIZE - 2 ? _y : GRAIN_LUT_SIZE - 2;

  const int _x1 = _x0 + 1;
  const int _y1 = _y0 + 1;

  const float x_diff = _x - _x0;
  const float y_diff = _y - _y0;

  const float l00 = grain_lut[_y0 * GRAIN_LUT_SIZE + _x0];
  const float l01 = grain_lut[_y0 * GRAIN_LUT_SIZE + _x1];
  const float l10 = grain_lut[_y1 * GRAIN_LUT_SIZE + _x0];
  const float l11 = grain_lut[_y1 * GRAIN_LUT_SIZE + _x1];

  const float xy0 = (1.0 - y_diff) * l00 + l10 * y_diff;
  const float xy1 = (1.0 - y_diff) * l01 + l11 * y_diff;
  return xy0 * (1.0f - x_diff) + xy1 * x_diff;
}
418 419 420 421 422 423

const char *name()
{
  return _("grain");
}

424 425
int flags()
{
426
  return IOP_FLAGS_INCLUDE_IN_STYLES | IOP_FLAGS_SUPPORTS_BLENDING;
427 428
}

429
int groups()
430
{
431
  return IOP_GROUP_EFFECT;
432 433
}

434
#if 0 // BAUHAUS doesn't support keyaccels yet...
435
void init_key_accels(dt_iop_module_so_t *self)
436
{
437 438
  dt_accel_register_slider_iop(self, FALSE, NC_("accel", "coarseness"));
  dt_accel_register_slider_iop(self, FALSE, NC_("accel", "strength"));
439
}
440

441 442 443
void connect_key_accels(dt_iop_module_t *self)
{
  dt_iop_grain_gui_data_t *g = (dt_iop_grain_gui_data_t*)self->gui_data;
444

445 446 447
  dt_accel_connect_slider_iop(self, "coarseness", GTK_WIDGET(g->scale1));
  dt_accel_connect_slider_iop(self, "strength", GTK_WIDGET(g->scale2));
}
448

449 450
#endif

451 452 453 454 455 456 457 458 459
// see: http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
// this is the modified bernstein
static unsigned int _hash_string(char *s)
{
  unsigned int h = 0;
  while(*s) h = 33 * h ^ *s++;
  return h;
}

460 461
void process(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
             void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
462 463
{
  dt_iop_grain_data_t *data = (dt_iop_grain_data_t *)piece->data;
464

465
  unsigned int hash = _hash_string(piece->pipe->image.filename) % (int)fmax(roi_out->width * 0.3, 1.0);
466

467
  const int ch = piece->colors;
468
  // Apply grain to image
469 470
  const double strength = (data->strength / 100.0);
  const double octaves = 3;
471
  // double zoom=1.0+(8*(data->scale/100.0));
472
  const double wd = fminf(piece->buf_in.width, piece->buf_in.height);
473
  const double zoom = (1.0 + 8 * data->scale / 100) / 800.0;
474
  const int filter = fabsf(roi_out->scale - 1.0f) > 0.01;
475 476 477
  // filter width depends on world space (i.e. reverse wd norm and roi->scale, as well as buffer input to
  // pixelpipe iscale)
  const double filtermul = piece->iscale / (roi_out->scale * wd);
478
#ifdef _OPENMP
479
#pragma omp parallel for default(none) shared(data, hash)
480
#endif
481
  for(int j = 0; j < roi_out->height; j++)
482
  {
483
    float *in = ((float *)ivoid) + (size_t)roi_out->width * j * ch;
484
    float *out = ((float *)ovoid) + (size_t)roi_out->width * j * ch;
485
    for(int i = 0; i < roi_out->width; i++)
486
    {
487
      // calculate x, y in a resolution independent way:
488
      // wx,wy: worldspace in full image pixel coords:
489 490
      double wx = (roi_out->x + i) / roi_out->scale;
      double wy = (roi_out->y + j) / roi_out->scale;
491 492
      // x, y: normalized to shorter side of image, so with pixel aspect = 1.
      // printf("scale %f\n", wd);
493 494
      double x = wx / wd;
      double y = wy / wd;
495
      //  double noise=_perlin_2d_noise(x, y, octaves,0.25, zoom)*1.5;
496
      double noise = 0.0;
497
      if(filter)
498 499
      {
        // if zoomed out a lot, use rank-1 lattice downsampling
500
        const float fib1 = 34.0, fib2 = 21.0;
501
        for(int l = 0; l < fib2; l++)
502
        {
503
          float px = l / fib2, py = l * (fib1 / fib2);
504
          py -= (int)py;
505 506
          float dx = px * filtermul, dy = py * filtermul;
          noise += (1.0 / fib2) * _simplex_2d_noise(x + dx + hash, y + dy, octaves, 1.0, zoom);
507 508 509 510
        }
      }
      else
      {
511
        noise = _simplex_2d_noise(x + hash, y, octaves, 1.0, zoom);
512
      }
513

Andrea Volpato's avatar
Andrea Volpato committed
514
      out[0] = in[0] + dt_lut_lookup_2d_1c(data->grain_lut, (noise * strength) * GRAIN_LIGHTNESS_STRENGTH_SCALE, in[0] / 100.0f);
515 516
      out[1] = in[1];
      out[2] = in[2];
517
      out[3] = in[3];
518 519 520

      out += ch;
      in += ch;
521
    }
522 523 524
  }
}

525
static void scale_callback(GtkWidget *slider, gpointer user_data)
526 527 528 529
{
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
  if(self->dt->gui->reset) return;
  dt_iop_grain_params_t *p = (dt_iop_grain_params_t *)self->params;
530
  p->scale = dt_bauhaus_slider_get(slider) / GRAIN_SCALE_FACTOR;
531
  dt_dev_add_history_item(darktable.develop, self, TRUE);
532
}
533

534
static void strength_callback(GtkWidget *slider, gpointer user_data)
535 536 537 538
{
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
  if(self->dt->gui->reset) return;
  dt_iop_grain_params_t *p = (dt_iop_grain_params_t *)self->params;
539
  p->strength = dt_bauhaus_slider_get(slider);
540
  dt_dev_add_history_item(darktable.develop, self, TRUE);
541 542
}

543 544 545 546 547
static void midtones_bias_callback(GtkWidget *slider, gpointer user_data)
{
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
  if(self->dt->gui->reset) return;
  dt_iop_grain_params_t *p = (dt_iop_grain_params_t *)self->params;
Andrea Volpato's avatar
Andrea Volpato committed
548
  p->midtones_bias = dt_bauhaus_slider_get(slider);
549 550
  dt_dev_add_history_item(darktable.develop, self, TRUE);
}
551

552 553
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe,
                   dt_dev_pixelpipe_iop_t *piece)
554 555 556
{
  dt_iop_grain_params_t *p = (dt_iop_grain_params_t *)p1;
  dt_iop_grain_data_t *d = (dt_iop_grain_data_t *)piece->data;
557

558
  d->channel = p->channel;
559
  d->scale = p->scale;
560
  d->strength = p->strength;
Andrea Volpato's avatar
Andrea Volpato committed
561
  d->midtones_bias = p->midtones_bias;
562 563
  
  evaluate_grain_lut(d->grain_lut, d->midtones_bias);
564 565
}

566
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
567
{
568
  piece->data = calloc(1, sizeof(dt_iop_grain_data_t));
569 570 571
  self->commit_params(self, self->default_params, pipe, piece);
}

572
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
573 574
{
  free(piece->data);
575
  piece->data = NULL;
576 577 578 579 580 581 582
}

void gui_update(struct dt_iop_module_t *self)
{
  dt_iop_module_t *module = (dt_iop_module_t *)self;
  dt_iop_grain_gui_data_t *g = (dt_iop_grain_gui_data_t *)self->gui_data;
  dt_iop_grain_params_t *p = (dt_iop_grain_params_t *)module->params;
583

584
  dt_bauhaus_slider_set(g->scale1, p->scale * GRAIN_SCALE_FACTOR);
585
  dt_bauhaus_slider_set(g->scale2, p->strength);
Andrea Volpato's avatar
Andrea Volpato committed
586
  dt_bauhaus_slider_set(g->scale3, p->midtones_bias);
587 588 589 590
}

void init(dt_iop_module_t *module)
{
Henrik Andersson's avatar
Henrik Andersson committed
591
  _simplex_noise_init();
592 593
  module->params = calloc(1, sizeof(dt_iop_grain_params_t));
  module->default_params = calloc(1, sizeof(dt_iop_grain_params_t));
594
  module->default_enabled = 0;
Heiko Bauke's avatar
Heiko Bauke committed
595
  module->priority = 779; // module order created by iop_dependencies.py, do not edit!
596 597
  module->params_size = sizeof(dt_iop_grain_params_t);
  module->gui_data = NULL;
598
  dt_iop_grain_params_t tmp
Andrea Volpato's avatar
Andrea Volpato committed
599
      = (dt_iop_grain_params_t){ DT_GRAIN_CHANNEL_LIGHTNESS, 1600.0 / GRAIN_SCALE_FACTOR, 25.0, 100.0 };
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
  memcpy(module->params, &tmp, sizeof(dt_iop_grain_params_t));
  memcpy(module->default_params, &tmp, sizeof(dt_iop_grain_params_t));
}

void cleanup(dt_iop_module_t *module)
{
  free(module->params);
  module->params = NULL;
}

void gui_init(struct dt_iop_module_t *self)
{
  self->gui_data = malloc(sizeof(dt_iop_grain_gui_data_t));
  dt_iop_grain_gui_data_t *g = (dt_iop_grain_gui_data_t *)self->gui_data;
  dt_iop_grain_params_t *p = (dt_iop_grain_params_t *)self->params;

616
  self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_BAUHAUS_SPACE);
617

618
  /* courseness */
619
  g->scale1 = dt_bauhaus_slider_new_with_range(self, 20.0, 6400.0, 20.0, p->scale * GRAIN_SCALE_FACTOR, 0);
620
  dt_bauhaus_widget_set_label(g->scale1, NULL, _("coarseness"));
621
  dt_bauhaus_slider_set_format(g->scale1, "%.0fISO");
622
  gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->scale1), TRUE, TRUE, 0);
623
  gtk_widget_set_tooltip_text(g->scale1, _("the grain size (~ISO of the film)"));
624
  g_signal_connect(G_OBJECT(g->scale1), "value-changed", G_CALLBACK(scale_callback), self);
625 626 627

  /* strength */
  g->scale2 = dt_bauhaus_slider_new_with_range(self, 0.0, 100.0, 1.0, p->strength, 2);
628
  dt_bauhaus_widget_set_label(g->scale2, NULL, _("strength"));
629
  dt_bauhaus_slider_set_format(g->scale2, "%.0f%%");
630
  gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->scale2), TRUE, TRUE, 0);
631
  gtk_widget_set_tooltip_text(g->scale2, _("the strength of applied grain"));
632
  g_signal_connect(G_OBJECT(g->scale2), "value-changed", G_CALLBACK(strength_callback), self);
633 634

  /* midtones bias */
Andrea Volpato's avatar
Andrea Volpato committed
635
  g->scale3 = dt_bauhaus_slider_new_with_range(self, 0.0, 100.0, 1.0, p->midtones_bias, 2);
636 637 638
  dt_bauhaus_widget_set_label(g->scale3, NULL, _("midtones bias"));
  dt_bauhaus_slider_set_format(g->scale3, "%.0f%%");
  gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->scale3), TRUE, TRUE, 0);
Andrea Volpato's avatar
Andrea Volpato committed
639
  gtk_widget_set_tooltip_text(g->scale3, _("amount of midtones bias from the photographic paper response modeling. the greater the bias, the more pronounced the fall off of the grain in shadows and highlights"));
640
  g_signal_connect(G_OBJECT(g->scale3), "value-changed", G_CALLBACK(midtones_bias_callback), self);
641 642 643 644 645 646 647 648
}

void gui_cleanup(struct dt_iop_module_t *self)
{
  free(self->gui_data);
  self->gui_data = NULL;
}

Richard Wonka's avatar
Richard Wonka committed
649
// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
650
// vim: shiftwidth=2 expandtab tabstop=2 cindent
Tobias Ellinghaus's avatar
Tobias Ellinghaus committed
651
// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;