blinds.c 20.7 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1
2
3
/*
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
4
 * This is a plug-in for GIMP.
Elliot Lee's avatar
Elliot Lee committed
5
 *
6
 * Blinds plug-in. Distort an image as though it was stuck to
Elliot Lee's avatar
Elliot Lee committed
7
8
9
10
 * window blinds and the blinds where opened/closed.
 *
 * Copyright (C) 1997 Andy Thomas  alt@picnic.demon.co.uk
 *
11
 * This program is free software: you can redistribute it and/or modify
Elliot Lee's avatar
Elliot Lee committed
12
 * it under the terms of the GNU General Public License as published by
13
 * the Free Software Foundation; either version 3 of the License, or
Elliot Lee's avatar
Elliot Lee committed
14
15
16
17
18
19
20
21
 * (at your option) any later version.
 *
 * This program 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
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23
 *
Elliot Lee's avatar
Elliot Lee committed
24
25
 * A fair proprotion of this code was taken from the Whirl plug-in
 * which was copyrighted by Federico Mena Quintero (as below).
26
 *
Elliot Lee's avatar
Elliot Lee committed
27
 * Whirl plug-in --- distort an image into a whirlpool
28
 * Copyright (C) 1997 Federico Mena Quintero
Elliot Lee's avatar
Elliot Lee committed
29
30
31
 *
 */

32
#include "config.h"
Elliot Lee's avatar
Elliot Lee committed
33
34

#include <string.h>
35

36
37
38
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>

39
#include "libgimp/stdplugins-intl.h"
Elliot Lee's avatar
Elliot Lee committed
40
41
42

/***** Magic numbers *****/

43
44
#define PLUG_IN_PROC   "plug-in-blinds"
#define PLUG_IN_BINARY "blinds"
45
#define PLUG_IN_ROLE   "gimp-blinds"
Elliot Lee's avatar
Elliot Lee committed
46

47
#define SCALE_WIDTH    150
Elliot Lee's avatar
Elliot Lee committed
48

49
#define MAX_FANS       100
50

Elliot Lee's avatar
Elliot Lee committed
51
/* Variables set in dialog box */
52
53
typedef struct data
{
54
55
56
  gint                 angledsp;
  gint                 numsegs;
  GimpOrientationType  orientation;
57
  gboolean bg_trans;
Elliot Lee's avatar
Elliot Lee committed
58
59
60
61
62
63
} BlindVals;

/* Array to hold each size of fans. And no there are not each the
 * same size (rounding errors...)
 */

David Neary's avatar
David Neary committed
64
static gint fanwidths[MAX_FANS];
Elliot Lee's avatar
Elliot Lee committed
65
66

static void      query  (void);
67
static void      run    (const gchar      *name,
68
69
70
71
                         gint              nparams,
                         const GimpParam  *param,
                         gint             *nreturn_vals,
                         GimpParam       **return_vals);
Elliot Lee's avatar
Elliot Lee committed
72

73
static gboolean  blinds_dialog         (GimpDrawable  *drawable);
74

75
76
77
static void      dialog_update_preview (GimpDrawable  *drawable,
                                        GimpPreview   *preview);
static void      apply_blinds          (GimpDrawable  *drawable);
Elliot Lee's avatar
Elliot Lee committed
78

79
const GimpPlugInInfo PLUG_IN_INFO =
Elliot Lee's avatar
Elliot Lee committed
80
81
82
83
84
85
86
87
88
89
90
91
{
  NULL,    /* init_proc */
  NULL,    /* quit_proc */
  query,   /* query_proc */
  run,     /* run_proc */
};

/* Values when first invoked */
static BlindVals bvals =
{
  30,
  3,
92
  GIMP_ORIENTATION_HORIZONTAL,
93
  FALSE
Elliot Lee's avatar
Elliot Lee committed
94
95
96
97
98
};

MAIN ()

static void
99
query (void)
Elliot Lee's avatar
Elliot Lee committed
100
{
101
  static const GimpParamDef args[] =
Elliot Lee's avatar
Elliot Lee committed
102
  {
103
    { GIMP_PDB_INT32,    "run-mode",       "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
104
105
    { GIMP_PDB_IMAGE,    "image",          "Input image (unused)" },
    { GIMP_PDB_DRAWABLE, "drawable",       "Input drawable" },
106
    { GIMP_PDB_INT32,    "angle-dsp",      "Angle of Displacement" },
107
    { GIMP_PDB_INT32,    "num-segments",   "Number of segments in blinds" },
108
109
    { GIMP_PDB_INT32,    "orientation",    "The orientation { ORIENTATION-HORIZONTAL (0), ORIENTATION-VERTICAL (1) }" },
    { GIMP_PDB_INT32,    "bg-transparent", "Background transparent { FALSE, TRUE }" }
Elliot Lee's avatar
Elliot Lee committed
110
  };
111

112
  gimp_install_procedure (PLUG_IN_PROC,
113
                          N_("Simulate an image painted on window blinds"),
114
115
116
117
                          "More here later",
                          "Andy Thomas",
                          "Andy Thomas",
                          "1997",
118
                          N_("_Blinds..."),
119
120
121
122
                          "RGB*, GRAY*",
                          GIMP_PLUGIN,
                          G_N_ELEMENTS (args), 0,
                          args, NULL);
123

124
  gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/Filters/Distorts");
Elliot Lee's avatar
Elliot Lee committed
125
126
127
}

static void
128
129
130
131
132
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
Elliot Lee's avatar
Elliot Lee committed
133
{
Sven Neumann's avatar
Sven Neumann committed
134
135
  static GimpParam values[1];
  GimpDrawable *drawable;
136
  GimpRunMode run_mode;
Sven Neumann's avatar
Sven Neumann committed
137
  GimpPDBStatusType status = GIMP_PDB_SUCCESS;
Elliot Lee's avatar
Elliot Lee committed
138
139
140

  run_mode = param[0].data.d_int32;

141
142
  INIT_I18N ();

Elliot Lee's avatar
Elliot Lee committed
143
144
145
  *nreturn_vals = 1;
  *return_vals = values;

Sven Neumann's avatar
Sven Neumann committed
146
  values[0].type = GIMP_PDB_STATUS;
Elliot Lee's avatar
Elliot Lee committed
147
148
  values[0].data.d_status = status;

149
  drawable = gimp_drawable_get (param[2].data.d_drawable);
Elliot Lee's avatar
Elliot Lee committed
150
151
152

  switch (run_mode)
    {
Sven Neumann's avatar
Sven Neumann committed
153
    case GIMP_RUN_INTERACTIVE:
154
      gimp_get_data (PLUG_IN_PROC, &bvals);
155
      if (! blinds_dialog (drawable))
156
157
158
159
        {
          gimp_drawable_detach (drawable);
          return;
        }
Elliot Lee's avatar
Elliot Lee committed
160
161
      break;

Sven Neumann's avatar
Sven Neumann committed
162
    case GIMP_RUN_NONINTERACTIVE:
Elliot Lee's avatar
Elliot Lee committed
163
      if (nparams != 7)
164
        status = GIMP_PDB_CALLING_ERROR;
Sven Neumann's avatar
Sven Neumann committed
165
      if (status == GIMP_PDB_SUCCESS)
166
        {
167
168
          bvals.angledsp    = param[3].data.d_int32;
          bvals.numsegs     = param[4].data.d_int32;
169
          bvals.orientation = param[5].data.d_int32;
170
          bvals.bg_trans    = param[6].data.d_int32;
171
        }
Elliot Lee's avatar
Elliot Lee committed
172
173
      break;

Sven Neumann's avatar
Sven Neumann committed
174
    case GIMP_RUN_WITH_LAST_VALS:
175
      gimp_get_data (PLUG_IN_PROC, &bvals);
Elliot Lee's avatar
Elliot Lee committed
176
177
178
179
180
181
      break;

    default:
      break;
    }

182
183
  if (gimp_drawable_is_rgb (drawable->drawable_id) ||
      gimp_drawable_is_gray (drawable->drawable_id))
Elliot Lee's avatar
Elliot Lee committed
184
    {
185
      gimp_progress_init (_("Adding blinds"));
Elliot Lee's avatar
Elliot Lee committed
186

187
      apply_blinds (drawable);
188

Sven Neumann's avatar
Sven Neumann committed
189
      if (run_mode != GIMP_RUN_NONINTERACTIVE)
190
        gimp_displays_flush ();
Elliot Lee's avatar
Elliot Lee committed
191

Sven Neumann's avatar
Sven Neumann committed
192
      if (run_mode == GIMP_RUN_INTERACTIVE)
193
        gimp_set_data (PLUG_IN_PROC, &bvals, sizeof (BlindVals));
Elliot Lee's avatar
Elliot Lee committed
194
195
196
    }
  else
    {
Sven Neumann's avatar
Sven Neumann committed
197
      status = GIMP_PDB_EXECUTION_ERROR;
Elliot Lee's avatar
Elliot Lee committed
198
199
200
201
202
203
204
205
    }

  values[0].data.d_status = status;

  gimp_drawable_detach (drawable);
}


206
static gboolean
207
blinds_dialog (GimpDrawable *drawable)
Elliot Lee's avatar
Elliot Lee committed
208
{
209
  GtkWidget *dialog;
210
  GtkWidget *main_vbox;
211
  GtkWidget *preview;
212
  GtkWidget *hbox;
Elliot Lee's avatar
Elliot Lee committed
213
214
215
216
  GtkWidget *frame;
  GtkWidget *table;
  GtkObject *size_data;
  GtkWidget *toggle;
217
218
  GtkWidget *horizontal;
  GtkWidget *vertical;
219
  gboolean   run;
220

221
  gimp_ui_init (PLUG_IN_BINARY, TRUE);
Elliot Lee's avatar
Elliot Lee committed
222

223
  dialog = gimp_dialog_new (_("Blinds"), PLUG_IN_ROLE,
224
                            NULL, 0,
225
                            gimp_standard_help_func, PLUG_IN_PROC,
226

227
228
                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                            GTK_STOCK_OK,     GTK_RESPONSE_OK,
229

230
                            NULL);
231

232
  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
233
234
235
                                           GTK_RESPONSE_OK,
                                           GTK_RESPONSE_CANCEL,
                                           -1);
236

237
  gimp_window_set_transient (GTK_WINDOW (dialog));
238

Michael Natterer's avatar
Michael Natterer committed
239
  main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
240
  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
241
242
  gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
                      main_vbox, TRUE, TRUE, 0);
243
  gtk_widget_show (main_vbox);
Elliot Lee's avatar
Elliot Lee committed
244

245
  preview = gimp_aspect_preview_new (drawable, NULL);
246
  gtk_box_pack_start (GTK_BOX (main_vbox), preview, TRUE, TRUE, 0);
247
  gtk_widget_show (preview);
248

249
250
251
252
  g_signal_connect_swapped (preview, "invalidated",
                            G_CALLBACK (dialog_update_preview),
                            drawable);

Michael Natterer's avatar
Michael Natterer committed
253
  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
254
255
256
  gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show (hbox);

257
  frame =
258
    gimp_int_radio_group_new (TRUE, _("Orientation"),
259
                              G_CALLBACK (gimp_radio_button_update),
260
                              &bvals.orientation, bvals.orientation,
261

262
263
264
265
266
                              _("_Horizontal"), GIMP_ORIENTATION_HORIZONTAL,
                              &horizontal,

                              _("_Vertical"),   GIMP_ORIENTATION_VERTICAL,
                              &vertical,
Elliot Lee's avatar
Elliot Lee committed
267

268
                              NULL);
269
  gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
270
  gtk_widget_show (frame);
271

272
273
274
275
276
277
278
  g_signal_connect_swapped (horizontal, "toggled",
                            G_CALLBACK (gimp_preview_invalidate),
                            preview);
  g_signal_connect_swapped (vertical, "toggled",
                            G_CALLBACK (gimp_preview_invalidate),
                            preview);

279
  frame = gimp_frame_new (_("Background"));
280
  gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
281
  gtk_widget_show (frame);
282

283
  toggle = gtk_check_button_new_with_mnemonic (_("_Transparent"));
284
  gtk_container_add (GTK_CONTAINER (frame), toggle);
285
286
  gtk_widget_show (toggle);

287
  g_signal_connect (toggle, "toggled",
288
                    G_CALLBACK (gimp_toggle_button_update),
289
                    &bvals.bg_trans);
290
291
292
  g_signal_connect_swapped (toggle, "toggled",
                            G_CALLBACK (gimp_preview_invalidate),
                            preview);
293

294
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), bvals.bg_trans);
Elliot Lee's avatar
Elliot Lee committed
295

296
  if (!gimp_drawable_has_alpha (drawable->drawable_id))
Elliot Lee's avatar
Elliot Lee committed
297
    {
298
      gtk_widget_set_sensitive (toggle, FALSE);
299
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), FALSE);
Elliot Lee's avatar
Elliot Lee committed
300
301
    }

302
  table = gtk_table_new (2, 3, FALSE);
303
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
304
  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
305
  gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
306
  gtk_widget_show (table);
Elliot Lee's avatar
Elliot Lee committed
307

308
  size_data = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
309
310
311
312
                                    _("_Displacement:"), SCALE_WIDTH, 0,
                                    bvals.angledsp, 1, 90, 1, 15, 0,
                                    TRUE, 0, 0,
                                    NULL, NULL);
313
  g_signal_connect (size_data, "value-changed",
314
                    G_CALLBACK (gimp_int_adjustment_update),
315
                    &bvals.angledsp);
316
  g_signal_connect_swapped (size_data, "value-changed",
317
318
                            G_CALLBACK (gimp_preview_invalidate),
                            preview);
319
320

  size_data = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
321
                                    _("_Number of segments:"), SCALE_WIDTH, 0,
322
323
324
                                    bvals.numsegs, 1, MAX_FANS, 1, 2, 0,
                                    TRUE, 0, 0,
                                    NULL, NULL);
325
  g_signal_connect (size_data, "value-changed",
326
                    G_CALLBACK (gimp_int_adjustment_update),
327
                    &bvals.numsegs);
328
  g_signal_connect_swapped (size_data, "value-changed",
329
330
                            G_CALLBACK (gimp_preview_invalidate),
                            preview);
Elliot Lee's avatar
Elliot Lee committed
331

332
  gtk_widget_show (dialog);
Elliot Lee's avatar
Elliot Lee committed
333

334
  run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
Elliot Lee's avatar
Elliot Lee committed
335

336
  gtk_widget_destroy (dialog);
Elliot Lee's avatar
Elliot Lee committed
337

338
  return run;
Elliot Lee's avatar
Elliot Lee committed
339
340
}

341
static void
342
blindsapply (guchar *srow,
343
344
345
346
             guchar *drow,
             gint    width,
             gint    bpp,
             guchar *bg)
Elliot Lee's avatar
Elliot Lee committed
347
{
348
349
350
351
352
  guchar  *src;
  guchar  *dst;
  gint     i,j,k;
  gdouble  ang;
  gint     available;
Elliot Lee's avatar
Elliot Lee committed
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369

  /* Make the row 'shrink' around points along its length */
  /* The bvals.numsegs determins how many segments to slip it in to */
  /* The angle is the conceptual 'rotation' of each of these segments */

  /* Note the row is considered to be made up of a two dim array actual
   * pixel locations and the RGB colour at these locations.
   */

  /* In the process copy the src row to the destination row */

  /* Fill in with background color ? */
  for (i = 0 ; i < width ; i++)
    {
      dst = &drow[i*bpp];

      for (j = 0 ; j < bpp; j++)
370
371
372
        {
          dst[j] = bg[j];
        }
Elliot Lee's avatar
Elliot Lee committed
373
374
375
376
377
    }

  /* Apply it */

  available = width;
David Neary's avatar
David Neary committed
378
  for (i = 0; i < bvals.numsegs; i++)
379
380
381
382
383
    {
      /* Width of segs are variable */
      fanwidths[i] = available / (bvals.numsegs - i);
      available -= fanwidths[i];
    }
Elliot Lee's avatar
Elliot Lee committed
384
385
386

  /* do center points  first - just for fun...*/
  available = 0;
387
  for (k = 1; k <= bvals.numsegs; k++)
Elliot Lee's avatar
Elliot Lee committed
388
389
390
    {
      int point;

391
      point = available + fanwidths[k - 1] / 2;
Elliot Lee's avatar
Elliot Lee committed
392

393
      available += fanwidths[k - 1];
Elliot Lee's avatar
Elliot Lee committed
394

395
396
      src = &srow[point * bpp];
      dst = &drow[point * bpp];
397

Elliot Lee's avatar
Elliot Lee committed
398
399
      /* Copy pixels across */
      for (j = 0 ; j < bpp; j++)
400
401
402
        {
          dst[j] = src[j];
        }
Elliot Lee's avatar
Elliot Lee committed
403
404
405
    }

  /* Disp for each point */
406
407
  ang = (bvals.angledsp * 2 * G_PI) / 360; /* Angle in rads */
  ang = (1 - fabs (cos (ang)));
Elliot Lee's avatar
Elliot Lee committed
408
409

  available = 0;
410
  for (k = 0 ; k < bvals.numsegs; k++)
Elliot Lee's avatar
Elliot Lee committed
411
412
413
414
415
    {
      int dx; /* Amount to move by */
      int fw;

      for (i = 0 ; i < (fanwidths[k]/2) ; i++)
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
        {
          /* Copy pixels across of left half of fan */
          fw = fanwidths[k] / 2;
          dx = (int) (ang * ((double) (fw - (double)(i % fw))));

          src = &srow[(available + i) * bpp];
          dst = &drow[(available + i + dx) * bpp];

          for (j = 0; j < bpp; j++)
            {
              dst[j] = src[j];
            }

          /* Right side */
          j = i + 1;
          src = &srow[(available + fanwidths[k] - j
                       - (fanwidths[k] % 2)) * bpp];
          dst = &drow[(available + fanwidths[k] - j
                       - (fanwidths[k] % 2) - dx) * bpp];

          for (j = 0; j < bpp; j++)
            {
              dst[j] = src[j];
            }
        }
Elliot Lee's avatar
Elliot Lee committed
441
442
443
444
445
446

      available += fanwidths[k];
    }
}

static void
447
448
dialog_update_preview (GimpDrawable *drawable,
                       GimpPreview  *preview)
Elliot Lee's avatar
Elliot Lee committed
449
{
450
  gint     y;
451
  guchar  *p, *buffer, *cache;
452
453
  GimpRGB  background;
  guchar   bg[4];
454
455
  gint     width, height, bpp;

456
457
458
459
  gimp_preview_get_size (preview, &width, &height);
  bpp = gimp_drawable_bpp (drawable->drawable_id);
  cache = gimp_drawable_get_thumbnail_data (drawable->drawable_id,
                                            &width, &height, &bpp);
460
  p = cache;
Elliot Lee's avatar
Elliot Lee committed
461

462
  gimp_context_get_background (&background);
463
464
465
466

  if (bvals.bg_trans)
    gimp_rgb_set_alpha (&background, 0.0);

467
  gimp_drawable_get_color_uchar (drawable->drawable_id, &background, bg);
Elliot Lee's avatar
Elliot Lee committed
468

469
  buffer = g_new (guchar, width * height * bpp);
David Neary's avatar
David Neary committed
470

471
  if (bvals.orientation == GIMP_ORIENTATION_VERTICAL)
Elliot Lee's avatar
Elliot Lee committed
472
    {
473
      for (y = 0; y < height; y++)
474
        {
David Odin's avatar
David Odin committed
475
          blindsapply (p,
476
477
478
479
                       buffer + y * width * bpp,
                       width,
                       bpp, bg);
          p += width * bpp;
480
        }
Elliot Lee's avatar
Elliot Lee committed
481
482
483
484
485
    }
  else
    {
      /* Horizontal blinds */
      /* Apply the blinds algo to a single column -
486
       * this act as a transfomation matrix for the
Elliot Lee's avatar
Elliot Lee committed
487
488
       * rows. Make row 0 invalid so we can find it again!
       */
489
      gint i;
490
491
      guchar *sr = g_new (guchar, height * 4);
      guchar *dr = g_new0 (guchar, height * 4);
David Neary's avatar
David Neary committed
492
      guchar dummybg[4] = {0, 0, 0, 0};
Elliot Lee's avatar
Elliot Lee committed
493
494

      /* Fill in with background color ? */
495
      for (i = 0 ; i < width ; i++)
496
497
        {
          gint j;
498
          gint bd = bpp;
499
500
501
502
503
504
505
506
          guchar *dst;
          dst = &buffer[i * bd];

          for (j = 0 ; j < bd; j++)
            {
              dst[j] = bg[j];
            }
        }
Elliot Lee's avatar
Elliot Lee committed
507

508
      for ( y = 0 ; y < height; y++)
509
510
511
        {
          sr[y] = y+1;
        }
Elliot Lee's avatar
Elliot Lee committed
512
513
514

      /* Bit of a fiddle since blindsapply really works on an image
       * row not a set of bytes. - preview can't be > 255
515
       * or must make dr sr int rows.
Elliot Lee's avatar
Elliot Lee committed
516
       */
517
      blindsapply (sr, dr, height, 1, dummybg);
Elliot Lee's avatar
Elliot Lee committed
518

519
      for (y = 0; y < height; y++)
520
521
522
523
524
525
526
527
528
        {
          if (dr[y] == 0)
            {
              /* Draw background line */
              p = buffer;
            }
          else
            {
              /* Draw line from src */
529
530
              p = cache +
                (width * bpp * (dr[y] - 1));
531
            }
532
          memcpy (buffer + y * width * bpp,
David Odin's avatar
David Odin committed
533
                  p,
534
                  width * bpp);
535
        }
536
537
      g_free (sr);
      g_free (dr);
Elliot Lee's avatar
Elliot Lee committed
538
    }
539

540
  gimp_preview_draw_buffer (preview, buffer, width * bpp);
David Neary's avatar
David Neary committed
541

David Odin's avatar
David Odin committed
542
  g_free (buffer);
543
  g_free (cache);
Elliot Lee's avatar
Elliot Lee committed
544
545
546
547
548
549
550
551
552
553
}

/* STEP tells us how many rows/columns to gulp down in one go... */
/* Note all the "4" literals around here are to do with the depths
 * of the images. Makes it easier to deal with for my small brain.
 */

#define STEP 40

static void
554
apply_blinds (GimpDrawable *drawable)
Elliot Lee's avatar
Elliot Lee committed
555
{
556
557
558
559
560
561
562
563
564
  GimpPixelRgn  des_rgn;
  GimpPixelRgn  src_rgn;
  guchar       *src_rows, *des_rows;
  gint          x, y;
  GimpRGB       background;
  guchar        bg[4];
  gint          sel_x1, sel_y1, sel_x2, sel_y2;
  gint          sel_width, sel_height;

565
  gimp_context_get_background (&background);
566
567
568

  if (bvals.bg_trans)
    gimp_rgb_set_alpha (&background, 0.0);
Elliot Lee's avatar
Elliot Lee committed
569

570
  gimp_drawable_get_color_uchar (drawable->drawable_id, &background, bg);
Elliot Lee's avatar
Elliot Lee committed
571

572
573
574
575
  if (! gimp_drawable_mask_intersect (drawable->drawable_id,
                                      &sel_x1, &sel_y1,
                                      &sel_width, &sel_height))
    return;
David Neary's avatar
David Neary committed
576

577
578
  sel_x2 = sel_x1 + sel_width;
  sel_y2 = sel_y1 + sel_height;
David Neary's avatar
David Neary committed
579

580
  gimp_pixel_rgn_init (&src_rgn, drawable,
581
                       sel_x1, sel_y1, sel_width, sel_height, FALSE, FALSE);
582
  gimp_pixel_rgn_init (&des_rgn, drawable,
583
                       sel_x1, sel_y1, sel_width, sel_height, TRUE, TRUE);
Elliot Lee's avatar
Elliot Lee committed
584

585
586
  src_rows = g_new (guchar, MAX (sel_width, sel_height) * 4 * STEP);
  des_rows = g_new (guchar, MAX (sel_width, sel_height) * 4 * STEP);
Elliot Lee's avatar
Elliot Lee committed
587

588
  if (bvals.orientation == GIMP_ORIENTATION_VERTICAL)
Elliot Lee's avatar
Elliot Lee committed
589
    {
590
      for (y = 0; y < sel_height; y += STEP)
591
        {
592
593
          gint rr;
          gint step;
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621

          if((y + STEP) > sel_height)
            step = sel_height - y;
          else
            step = STEP;

          gimp_pixel_rgn_get_rect (&src_rgn,
                                   src_rows,
                                   sel_x1,
                                   sel_y1 + y,
                                   sel_width,
                                   step);

          /* OK I could make this better */
          for (rr = 0; rr < STEP; rr++)
            blindsapply (src_rows + (sel_width * rr * src_rgn.bpp),
                         des_rows + (sel_width * rr * src_rgn.bpp),
                         sel_width, src_rgn.bpp, bg);

          gimp_pixel_rgn_set_rect (&des_rgn,
                                   des_rows,
                                   sel_x1,
                                   sel_y1 + y,
                                   sel_width,
                                   step);

          gimp_progress_update ((double) y / (double) sel_height);
        }
Elliot Lee's avatar
Elliot Lee committed
622
623
624
625
626
    }
  else
    {
      /* Horizontal blinds */
      /* Apply the blinds algo to a single column -
627
       * this act as a transfomation matrix for the
Elliot Lee's avatar
Elliot Lee committed
628
629
       * rows. Make row 0 invalid so we can find it again!
       */
630
      gint    i;
631
632
      gint   *sr  = g_new (gint, sel_height * 4);
      gint   *dr  = g_new (gint, sel_height * 4);
633
      guchar *dst = g_new (guchar, STEP * 4);
634
      guchar  dummybg[4];
Elliot Lee's avatar
Elliot Lee committed
635

636
637
638
      memset (dummybg, 0, 4);
      memset (dr, 0, sel_height * 4); /* all dr rows are background rows */
      for (y = 0; y < sel_height; y++)
639
640
641
        {
          sr[y] = y+1;
        }
Elliot Lee's avatar
Elliot Lee committed
642
643
644

      /* Hmmm. does this work portably? */
      /* This "swaps the intergers around that are held in in the
645
       * sr & dr arrays.
Elliot Lee's avatar
Elliot Lee committed
646
       */
647
      blindsapply ((guchar *) sr, (guchar *) dr,
648
                   sel_height, sizeof (gint), dummybg);
Elliot Lee's avatar
Elliot Lee committed
649
650
651

      /* Fill in with background color ? */
      for (i = 0 ; i < STEP ; i++)
652
        {
653
          int     j;
654
655
          guchar *bgdst;
          bgdst = &dst[i * src_rgn.bpp];
656

657
658
659
660
661
          for (j = 0 ; j < src_rgn.bpp; j++)
            {
              bgdst[j] = bg[j];
            }
        }
Elliot Lee's avatar
Elliot Lee committed
662

663
      for (x = 0; x < sel_width; x += STEP)
664
        {
665
666
          int     rr;
          int     step;
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
          guchar *p;

          if((x + STEP) > sel_width)
            step = sel_width - x;
          else
            step = STEP;

          gimp_pixel_rgn_get_rect (&src_rgn,
                                   src_rows,
                                   sel_x1 + x,
                                   sel_y1,
                                   step,
                                   sel_height);

          /* OK I could make this better */
          for (rr = 0; rr < sel_height; rr++)
            {
              if(dr[rr] == 0)
                {
                  /* Draw background line */
                  p = dst;
                }
              else
                {
                  /* Draw line from src */
                  p = src_rows + (step * src_rgn.bpp * (dr[rr] - 1));
                }
              memcpy (des_rows + (rr * step * src_rgn.bpp), p,
                      step * src_rgn.bpp);
            }

          gimp_pixel_rgn_set_rect (&des_rgn,
                                   des_rows,
                                   sel_x1 + x,
                                   sel_y1,
                                   step,
                                   sel_height);

          gimp_progress_update ((double) x / (double) sel_width);
        }
Elliot Lee's avatar
Elliot Lee committed
707

708
709
710
      g_free (dst);
      g_free (sr);
      g_free (dr);
Elliot Lee's avatar
Elliot Lee committed
711
712
    }

713
714
  g_free (src_rows);
  g_free (des_rows);
Elliot Lee's avatar
Elliot Lee committed
715

716
  gimp_progress_update (1.0);
717
718
719
  gimp_drawable_flush (drawable);
  gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
  gimp_drawable_update (drawable->drawable_id,
720
                        sel_x1, sel_y1, sel_width, sel_height);
Elliot Lee's avatar
Elliot Lee committed
721
}