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
}