~ubuntu-branches/ubuntu/saucy/darktable/saucy

« back to all changes in this revision

Viewing changes to src/iop/grain.c

  • Committer: Bazaar Package Importer
  • Author(s): David Bremner
  • Date: 2011-04-14 23:42:12 UTC
  • Revision ID: james.westby@ubuntu.com-20110414234212-kuffcz5wiu18v6ra
Tags: upstream-0.8
ImportĀ upstreamĀ versionĀ 0.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    This file is part of darktable,
 
3
    copyright (c) 2010 Henrik Andersson.
 
4
 
 
5
    darktable is free software: you can redistribute it and/or modify
 
6
    it under the terms of the GNU General Public License as published by
 
7
    the Free Software Foundation, either version 3 of the License, or
 
8
    (at your option) any later version.
 
9
 
 
10
    darktable is distributed in the hope that it will be useful,
 
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
    GNU General Public License for more details.
 
14
 
 
15
    You should have received a copy of the GNU General Public License
 
16
    along with darktable.  If not, see <http://www.gnu.org/licenses/>.
 
17
*/
 
18
#ifdef HAVE_CONFIG_H
 
19
#include "config.h"
 
20
#endif
 
21
#include <stdlib.h>
 
22
#include <math.h>
 
23
#include <assert.h>
 
24
#include <string.h>
 
25
#ifdef HAVE_GEGL
 
26
#include <gegl.h>
 
27
#endif
 
28
#include "develop/develop.h"
 
29
#include "develop/imageop.h"
 
30
#include "control/control.h"
 
31
#include "dtgtk/slider.h"
 
32
#include "dtgtk/resetlabel.h"
 
33
#include "gui/gtk.h"
 
34
#include <gtk/gtk.h>
 
35
#include <inttypes.h>
 
36
 
 
37
#define GRAIN_LIGHTNESS_STRENGTH_SCALE 0.15
 
38
// (m_pi/2)/4 = half hue colorspan
 
39
#define GRAIN_HUE_COLORRANGE 0.392699082
 
40
#define GRAIN_HUE_STRENGTH_SCALE 0.25
 
41
#define GRAIN_SATURATION_STRENGTH_SCALE 0.25
 
42
#define GRAIN_RGB_STRENGTH_SCALE 0.25
 
43
 
 
44
#define CLIP(x) ((x<0)?0.0:(x>1.0)?1.0:x)
 
45
DT_MODULE(1)
 
46
 
 
47
typedef enum _dt_iop_grain_channel_t
 
48
{
 
49
  DT_GRAIN_CHANNEL_HUE=0,
 
50
  DT_GRAIN_CHANNEL_SATURATION,
 
51
  DT_GRAIN_CHANNEL_LIGHTNESS,
 
52
  DT_GRAIN_CHANNEL_RGB
 
53
}
 
54
_dt_iop_grain_channel_t;
 
55
 
 
56
typedef struct dt_iop_grain_params_t
 
57
{
 
58
  _dt_iop_grain_channel_t channel;
 
59
  float scale;
 
60
  float strength;
 
61
}
 
62
dt_iop_grain_params_t;
 
63
 
 
64
typedef struct dt_iop_grain_gui_data_t
 
65
{
 
66
  GtkVBox   *vbox1,  *vbox2;
 
67
  GtkWidget  *label1,*label2,*label3;         // channel, scale, strength
 
68
  GtkDarktableSlider *scale1,*scale2;       // scale, strength
 
69
}
 
70
dt_iop_grain_gui_data_t;
 
71
 
 
72
typedef struct dt_iop_grain_data_t
 
73
{
 
74
  _dt_iop_grain_channel_t channel;
 
75
  float scale;
 
76
  float strength;
 
77
}
 
78
dt_iop_grain_data_t;
 
79
 
 
80
 
 
81
static int grad3[12][3] = {{1,1,0},{-1,1,0},{1,-1,0},{-1,-1,0},
 
82
  {1,0,1},{-1,0,1},{1,0,-1},{-1,0,-1},
 
83
  {0,1,1},{0,-1,1},{0,1,-1},{0,-1,-1}
 
84
};
 
85
 
 
86
static int p[] = {151,160,137,91,90,15,
 
87
                  131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
 
88
                  190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
 
89
                  88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
 
90
                  77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
 
91
                  102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
 
92
                  135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
 
93
                  5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
 
94
                  223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
 
95
                  129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
 
96
                  251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
 
97
                  49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
 
98
                  138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
 
99
                 };
 
100
 
 
101
static int perm[512];
 
102
static void _simplex_noise_init()
 
103
{
 
104
  for(int i=0; i<512; i++) perm[i] = p[i & 255];
 
105
}
 
106
static double dot(int g[], double x, double y, double z)
 
107
{
 
108
  return g[0]*x + g[1]*y + g[2]*z;
 
109
}
 
110
 
 
111
#define FASTFLOOR(x) ( x>0 ? (int)(x) : (int)(x)-1 )
 
112
 
 
113
static double _simplex_noise(double xin, double yin, double zin)
 
114
{
 
115
  double n0, n1, n2, n3; // Noise contributions from the four corners
 
116
// Skew the input space to determine which simplex cell we're in
 
117
  double F3 = 1.0/3.0;
 
118
  double s = (xin+yin+zin)*F3; // Very nice and simple skew factor for 3D
 
119
  int i = FASTFLOOR(xin+s);
 
120
  int j = FASTFLOOR(yin+s);
 
121
  int k = FASTFLOOR(zin+s);
 
122
  double G3 = 1.0/6.0; // Very nice and simple unskew factor, too
 
123
  double t = (i+j+k)*G3;
 
124
  double X0 = i-t; // Unskew the cell origin back to (x,y,z) space
 
125
  double Y0 = j-t;
 
126
  double Z0 = k-t;
 
127
  double x0 = xin-X0; // The x,y,z distances from the cell origin
 
128
  double y0 = yin-Y0;
 
129
  double z0 = zin-Z0;
 
130
// For the 3D case, the simplex shape is a slightly irregular tetrahedron.
 
131
// Determine which simplex we are in.
 
132
  int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords
 
133
  int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords
 
134
  if(x0>=y0)
 
135
  {
 
136
    if(y0>=z0)
 
137
    {
 
138
      i1=1;  // X Y Z order
 
139
      j1=0;
 
140
      k1=0;
 
141
      i2=1;
 
142
      j2=1;
 
143
      k2=0;
 
144
    }
 
145
    else if(x0>=z0)
 
146
    {
 
147
      i1=1;  // X Z Y order
 
148
      j1=0;
 
149
      k1=0;
 
150
      i2=1;
 
151
      j2=0;
 
152
      k2=1;
 
153
    }
 
154
    else
 
155
    {
 
156
      i1=0;  // Z X Y order
 
157
      j1=0;
 
158
      k1=1;
 
159
      i2=1;
 
160
      j2=0;
 
161
      k2=1;
 
162
    }
 
163
  }
 
164
  else   // x0<y0
 
165
  {
 
166
    if(y0<z0)
 
167
    {
 
168
      i1=0;  // Z Y X order
 
169
      j1=0;
 
170
      k1=1;
 
171
      i2=0;
 
172
      j2=1;
 
173
      k2=1;
 
174
    }
 
175
    else if(x0<z0)
 
176
    {
 
177
      i1=0;  // Y Z X order
 
178
      j1=1;
 
179
      k1=0;
 
180
      i2=0;
 
181
      j2=1;
 
182
      k2=1;
 
183
    }
 
184
    else
 
185
    {
 
186
      i1=0;  // Y X Z order
 
187
      j1=1;
 
188
      k1=0;
 
189
      i2=1;
 
190
      j2=1;
 
191
      k2=0;
 
192
    }
 
193
  }
 
194
//  A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
 
195
//  a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
 
196
//  a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
 
197
//  c = 1/6.
 
198
  double   x1 = x0 - i1 + G3; // Offsets for second corner in (x,y,z) coords
 
199
  double   y1 = y0 - j1 + G3;
 
200
  double   z1 = z0 - k1 + G3;
 
201
  double   x2 = x0 - i2 + 2.0*G3; // Offsets for third corner in (x,y,z) coords
 
202
  double   y2 = y0 - j2 + 2.0*G3;
 
203
  double   z2 = z0 - k2 + 2.0*G3;
 
204
  double   x3 = x0 - 1.0 + 3.0*G3; // Offsets for last corner in (x,y,z) coords
 
205
  double   y3 = y0 - 1.0 + 3.0*G3;
 
206
  double   z3 = z0 - 1.0 + 3.0*G3;
 
207
  // Work out the hashed gradient indices of the four simplex corners
 
208
  int ii = i & 255;
 
209
  int jj = j & 255;
 
210
  int kk = k & 255;
 
211
  int gi0 = perm[ii+perm[jj+perm[kk]]] % 12;
 
212
  int gi1 = perm[ii+i1+perm[jj+j1+perm[kk+k1]]] % 12;
 
213
  int gi2 = perm[ii+i2+perm[jj+j2+perm[kk+k2]]] % 12;
 
214
  int gi3 = perm[ii+1+perm[jj+1+perm[kk+1]]] % 12;
 
215
  // Calculate the contribution from the four corners
 
216
  double t0 = 0.6 - x0*x0 - y0*y0 - z0*z0;
 
217
  if(t0<0) n0 = 0.0;
 
218
  else
 
219
  {
 
220
    t0 *= t0;
 
221
    n0 = t0 * t0 * dot(grad3[gi0], x0, y0, z0);
 
222
  }
 
223
  double t1 = 0.6 - x1*x1 - y1*y1 - z1*z1;
 
224
  if(t1<0) n1 = 0.0;
 
225
  else
 
226
  {
 
227
    t1 *= t1;
 
228
    n1 = t1 * t1 * dot(grad3[gi1], x1, y1, z1);
 
229
  }
 
230
  double t2 = 0.6 - x2*x2 - y2*y2 - z2*z2;
 
231
  if(t2<0) n2 = 0.0;
 
232
  else
 
233
  {
 
234
    t2 *= t2;
 
235
    n2 = t2 * t2 * dot(grad3[gi2], x2, y2, z2);
 
236
  }
 
237
  double t3 = 0.6 - x3*x3 - y3*y3 - z3*z3;
 
238
  if(t3<0) n3 = 0.0;
 
239
  else
 
240
  {
 
241
    t3 *= t3;
 
242
    n3 = t3 * t3 * dot(grad3[gi3], x3, y3, z3);
 
243
  }
 
244
  // Add contributions from each corner to get the final noise value.
 
245
  // The result is scaled to stay just inside [-1,1]
 
246
  return 32.0*(n0 + n1 + n2 + n3);
 
247
}
 
248
 
 
249
 
 
250
 
 
251
 
 
252
 
 
253
#define PRIME_LEVELS 4
 
254
//static uint64_t _low_primes[PRIME_LEVELS] ={ 12503,14029,15649, 11369 };
 
255
//uint64_t _mid_primes[PRIME_LEVELS] ={ 784697,875783, 536461,639259};
 
256
 
 
257
/*static double __value_noise(uint32_t level,uint32_t x,uint32_t y)
 
258
{
 
259
  //uint32_t lvl=level%PRIME_LEVELS;
 
260
  uint32_t n = x + y * 57;
 
261
  n = (n<<13) ^ n;
 
262
  return ( 1.0 - (( (n * (n * n * 15731 + 789221) +1376312589) & 0x7fffffff) / 1073741824.0));
 
263
}
 
264
 
 
265
static double __value_smooth_noise(uint32_t level,double x,double y)
 
266
{
 
267
  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;
 
268
  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;
 
269
  double center  =  __value_noise(level,x, y) / 4;
 
270
  return corners + sides + center;
 
271
}
 
272
 
 
273
static double __preline_cosine_interpolate(double a,double b,double x)
 
274
{
 
275
  double ft = x * 3.1415927;
 
276
  double f = (1 - cos(ft)) * .5;
 
277
  return  a*(1-f) + b*f;
 
278
}
 
279
 
 
280
static double __value_interpolate(uint32_t level,double x,double y)
 
281
{
 
282
  double fx = x - (uint32_t)x;
 
283
  double fy = y - (uint32_t)y;
 
284
 
 
285
  double v1 = __value_smooth_noise(level,(uint32_t)x,     (uint32_t)y);
 
286
  double v2 = __value_smooth_noise(level,(uint32_t)x + 1, (uint32_t)y);
 
287
  double v3 = __value_smooth_noise(level,(uint32_t)x,     (uint32_t)y + 1);
 
288
  double v4 = __value_smooth_noise(level,(uint32_t)x + 1, (uint32_t)y + 1);
 
289
 
 
290
  double i1 = __preline_cosine_interpolate(v1 , v2 , fx);
 
291
  double i2 = __preline_cosine_interpolate(v3 , v4 , fx);
 
292
 
 
293
  return __preline_cosine_interpolate(i1 , i2 , fy);
 
294
}
 
295
static double _perlin_2d_noise(double x,double y,uint32_t octaves,double persistance,double z)
 
296
{
 
297
  double f=1,a=1,total=0;
 
298
 
 
299
  for(int o=0;o<octaves;o++) {
 
300
    total+= (__value_interpolate(o,x*f/z,y*f/z)*a);
 
301
    f=2*o;
 
302
    a=persistance*o;
 
303
  }
 
304
  return total;
 
305
}*/
 
306
 
 
307
static double _simplex_2d_noise(double x,double y,uint32_t octaves,double persistance,double z)
 
308
{
 
309
  double f=1,a=1,total=0;
 
310
 
 
311
  for(int o=0; o<octaves; o++)
 
312
  {
 
313
    total+= (_simplex_noise(x*f/z,y*f/z,o)*a);
 
314
    f=2*o;
 
315
    a=persistance*o;
 
316
  }
 
317
  return total;
 
318
}
 
319
 
 
320
 
 
321
const char *name()
 
322
{
 
323
  return _("grain");
 
324
}
 
325
 
 
326
int flags()
 
327
{
 
328
  return IOP_FLAGS_INCLUDE_IN_STYLES;
 
329
}
 
330
 
 
331
int
 
332
groups ()
 
333
{
 
334
  return IOP_GROUP_EFFECT;
 
335
}
 
336
 
 
337
 
 
338
 
 
339
 
 
340
void process (struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, void *ivoid, void *ovoid, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out)
 
341
{
 
342
  dt_iop_grain_data_t *data = (dt_iop_grain_data_t *)piece->data;
 
343
  const int ch = piece->colors;
 
344
  // Apply grain to image
 
345
  const double strength=(data->strength/100.0);
 
346
  const double octaves=3;
 
347
  // double zoom=1.0+(8*(data->scale/100.0));
 
348
  const double wd = fminf(piece->buf_in.width, piece->buf_in.height);
 
349
  const double zoom=(1.0+8*data->scale/100)/800.0;
 
350
  const int filter = fabsf(roi_out->scale - 1.0) > 0.01;
 
351
  // filter width depends on world space (i.e. reverse wd norm and roi->scale, as well as buffer input to pixelpipe iscale)
 
352
  const double filtermul = piece->iscale/(roi_out->scale*wd);
 
353
#ifdef _OPENMP
 
354
#pragma omp parallel for default(none) shared(roi_out, roi_in, ovoid, ivoid, data)
 
355
#endif
 
356
  for(int j=0; j<roi_out->height; j++)
 
357
  {
 
358
    float *in  = ((float *)ivoid) + roi_out->width * j * ch;
 
359
    float *out = ((float *)ovoid) + roi_out->width * j * ch;
 
360
    for(int i=0; i<roi_out->width; i++)
 
361
    {
 
362
      // calculate x, y in a resolution independent way:
 
363
      // wx,wy: worldspace in full image pixel coords:
 
364
      double wx = (roi_out->x + i)/roi_out->scale;
 
365
      double wy = (roi_out->y + j)/roi_out->scale;
 
366
      // x, y: normalized to shorter side of image, so with pixel aspect = 1.
 
367
      // printf("scale %f\n", wd);
 
368
      double x = wx / wd;
 
369
      double y = wy / wd;
 
370
      //  double noise=_perlin_2d_noise(x, y, octaves,0.25, zoom)*1.5;
 
371
      double noise = 0.0;
 
372
      if(filter)
 
373
      {
 
374
        // if zoomed out a lot, use rank-1 lattice downsampling
 
375
        const float fib1 = 34.0, fib2 = 21.0;
 
376
        for(int l=0; l<fib2; l++)
 
377
        {
 
378
          float px = l/fib2, py = l*(fib1/fib2);
 
379
          py -= (int)py;
 
380
          float dx = px*filtermul, dy = py*filtermul;
 
381
          noise += (1.0/fib2) * _simplex_2d_noise(x+dx, y+dy, octaves, 1.0, zoom);
 
382
        }
 
383
      }
 
384
      else
 
385
      {
 
386
        noise = _simplex_2d_noise(x, y, octaves, 1.0, zoom);
 
387
      }
 
388
 
 
389
      out[0] = in[0]+((100.0*(noise*(strength)))*GRAIN_LIGHTNESS_STRENGTH_SCALE);
 
390
      out[1] = in[1];
 
391
      out[2] = in[2];
 
392
 
 
393
      out += ch;
 
394
      in += ch;
 
395
    }
 
396
  }
 
397
}
 
398
 
 
399
static void
 
400
scale_callback (GtkDarktableSlider *slider, gpointer user_data)
 
401
{
 
402
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
 
403
  if(self->dt->gui->reset) return;
 
404
  dt_iop_grain_params_t *p = (dt_iop_grain_params_t *)self->params;
 
405
  p->scale = dtgtk_slider_get_value(slider)/53.3;
 
406
  dt_dev_add_history_item(darktable.develop, self, TRUE);
 
407
}
 
408
 
 
409
static void
 
410
strength_callback (GtkDarktableSlider *slider, gpointer user_data)
 
411
{
 
412
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
 
413
  if(self->dt->gui->reset) return;
 
414
  dt_iop_grain_params_t *p = (dt_iop_grain_params_t *)self->params;
 
415
  p->strength= dtgtk_slider_get_value(slider);
 
416
  dt_dev_add_history_item(darktable.develop, self, TRUE);
 
417
}
 
418
 
 
419
 
 
420
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)
 
421
{
 
422
  dt_iop_grain_params_t *p = (dt_iop_grain_params_t *)p1;
 
423
#ifdef HAVE_GEGL
 
424
  fprintf(stderr, "[grain] TODO: implement gegl version!\n");
 
425
  // pull in new params to gegl
 
426
#else
 
427
  dt_iop_grain_data_t *d = (dt_iop_grain_data_t *)piece->data;
 
428
  d->channel = p->channel;
 
429
  d->scale = p->scale;
 
430
  d->strength = p->strength;
 
431
#endif
 
432
}
 
433
 
 
434
void init_pipe (struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
 
435
{
 
436
#ifdef HAVE_GEGL
 
437
  // create part of the gegl pipeline
 
438
  piece->data = NULL;
 
439
#else
 
440
  piece->data = malloc(sizeof(dt_iop_grain_data_t));
 
441
  memset(piece->data,0,sizeof(dt_iop_grain_data_t));
 
442
  self->commit_params(self, self->default_params, pipe, piece);
 
443
#endif
 
444
}
 
445
 
 
446
void cleanup_pipe (struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
 
447
{
 
448
#ifdef HAVE_GEGL
 
449
  // clean up everything again.
 
450
  (void)gegl_node_remove_child(pipe->gegl, piece->input);
 
451
  // no free necessary, no data is alloc'ed
 
452
#else
 
453
  free(piece->data);
 
454
#endif
 
455
}
 
456
 
 
457
void gui_update(struct dt_iop_module_t *self)
 
458
{
 
459
  dt_iop_module_t *module = (dt_iop_module_t *)self;
 
460
  dt_iop_grain_gui_data_t *g = (dt_iop_grain_gui_data_t *)self->gui_data;
 
461
  dt_iop_grain_params_t *p = (dt_iop_grain_params_t *)module->params;
 
462
 
 
463
  dtgtk_slider_set_value(g->scale1, p->scale*53.3);
 
464
  dtgtk_slider_set_value(g->scale2, p->strength);
 
465
}
 
466
 
 
467
void init(dt_iop_module_t *module)
 
468
{
 
469
  _simplex_noise_init();
 
470
  module->params = malloc(sizeof(dt_iop_grain_params_t));
 
471
  module->default_params = malloc(sizeof(dt_iop_grain_params_t));
 
472
  module->default_enabled = 0;
 
473
  module->priority = 855;
 
474
  module->params_size = sizeof(dt_iop_grain_params_t);
 
475
  module->gui_data = NULL;
 
476
  dt_iop_grain_params_t tmp = (dt_iop_grain_params_t)
 
477
  {
 
478
    DT_GRAIN_CHANNEL_LIGHTNESS, 400.0/53.3, 25.0
 
479
  };
 
480
  memcpy(module->params, &tmp, sizeof(dt_iop_grain_params_t));
 
481
  memcpy(module->default_params, &tmp, sizeof(dt_iop_grain_params_t));
 
482
}
 
483
 
 
484
void cleanup(dt_iop_module_t *module)
 
485
{
 
486
  free(module->gui_data);
 
487
  module->gui_data = NULL;
 
488
  free(module->params);
 
489
  module->params = NULL;
 
490
}
 
491
 
 
492
void gui_init(struct dt_iop_module_t *self)
 
493
{
 
494
  self->gui_data = malloc(sizeof(dt_iop_grain_gui_data_t));
 
495
  dt_iop_grain_gui_data_t *g = (dt_iop_grain_gui_data_t *)self->gui_data;
 
496
  dt_iop_grain_params_t *p = (dt_iop_grain_params_t *)self->params;
 
497
 
 
498
  self->widget = GTK_WIDGET(gtk_hbox_new(FALSE, 0));
 
499
  g->vbox1 = GTK_VBOX(gtk_vbox_new(FALSE, DT_GUI_IOP_MODULE_CONTROL_SPACING));
 
500
  g->vbox2 = GTK_VBOX(gtk_vbox_new(FALSE, DT_GUI_IOP_MODULE_CONTROL_SPACING));
 
501
  gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->vbox1), FALSE, FALSE, 5);
 
502
  gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->vbox2), TRUE, TRUE, 5);
 
503
 
 
504
  g->label2 = dtgtk_reset_label_new(_("coarseness"), self, &p->scale, sizeof(float));
 
505
  g->label3 = dtgtk_reset_label_new(_("strength"), self, &p->strength, sizeof(float));
 
506
 
 
507
  gtk_box_pack_start(GTK_BOX(g->vbox1), GTK_WIDGET(g->label2), TRUE, TRUE, 0);
 
508
  gtk_box_pack_start(GTK_BOX(g->vbox1), GTK_WIDGET(g->label3), TRUE, TRUE, 0);
 
509
 
 
510
  g->scale1 = DTGTK_SLIDER(dtgtk_slider_new_with_range(DARKTABLE_SLIDER_BAR, 100.0, 3200.0, 20.0, p->scale*53.3, 0));
 
511
  dtgtk_slider_set_snap(g->scale1, 20);
 
512
  g->scale2 = DTGTK_SLIDER(dtgtk_slider_new_with_range(DARKTABLE_SLIDER_BAR, 0.0, 100.0, 1.0, p->strength, 2));
 
513
  dtgtk_slider_set_format_type(g->scale2,DARKTABLE_SLIDER_FORMAT_PERCENT);
 
514
  gtk_box_pack_start(GTK_BOX(g->vbox2), GTK_WIDGET(g->scale1), TRUE, TRUE, 0);
 
515
  gtk_box_pack_start(GTK_BOX(g->vbox2), GTK_WIDGET(g->scale2), TRUE, TRUE, 0);
 
516
  gtk_object_set(GTK_OBJECT(g->scale1), "tooltip-text", _("the grain size (~iso of the film)"), (char *)NULL);
 
517
  gtk_object_set(GTK_OBJECT(g->scale2), "tooltip-text", _("the strength of applied grain"), (char *)NULL);
 
518
 
 
519
  g_signal_connect (G_OBJECT (g->scale1), "value-changed",
 
520
                    G_CALLBACK (scale_callback), self);
 
521
  g_signal_connect (G_OBJECT (g->scale2), "value-changed",
 
522
                    G_CALLBACK (strength_callback), self);
 
523
 
 
524
}
 
525
 
 
526
void gui_cleanup(struct dt_iop_module_t *self)
 
527
{
 
528
  free(self->gui_data);
 
529
  self->gui_data = NULL;
 
530
}
 
531