~ubuntu-branches/ubuntu/hoary/gimp/hoary

« back to all changes in this revision

Viewing changes to plug-ins/common/papertile.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2005-04-04 14:51:23 UTC
  • Revision ID: james.westby@ubuntu.com-20050404145123-9py049eeelfymur8
Tags: upstream-2.2.2
ImportĀ upstreamĀ versionĀ 2.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*============================================================================*
 
2
 
 
3
  Paper Tile 1.0  -- A GIMP PLUG-IN
 
4
 
 
5
  Copyright (C) 1997-1999 Hirotsuna Mizuno <s1041150@u-aizu.ac.jp>
 
6
 
 
7
  This program  is  free software;  you can redistribute it  and/or  modify it
 
8
  under the terms of the GNU Public License as published  by the Free Software
 
9
  Foundation;  either version 2 of the License,  or (at your option) any later
 
10
  version.
 
11
 
 
12
  This program is distributed in the hope that it will be useful,  but WITHOUT
 
13
  ANY WARRANTY;  without  even  the  implied  warranty  of MERCHANTABILITY  or
 
14
  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU General Public License  for
 
15
  more details.
 
16
 
 
17
  You should have received a copy of the GNU General Public License along with
 
18
  this program; if not, write to the Free Software Foundation, Inc.,
 
19
  59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
20
 
 
21
 *===========================================================================*/
 
22
 
 
23
#include "config.h"
 
24
 
 
25
#include <stdlib.h>
 
26
 
 
27
#include <gtk/gtk.h>
 
28
 
 
29
#include <libgimp/gimp.h>
 
30
#include <libgimp/gimpui.h>
 
31
 
 
32
#include "libgimp/stdplugins-intl.h"
 
33
 
 
34
/*===========================================================================*/
 
35
/* DEFINES                                                                   */
 
36
/*===========================================================================*/
 
37
 
 
38
#define PLUGIN_PROCEDURE_NAME "plug_in_papertile"
 
39
#define HELP_ID               "plug-in-papertile"
 
40
 
 
41
/*===========================================================================*/
 
42
/* TYPES                                                                     */
 
43
/*===========================================================================*/
 
44
 
 
45
typedef enum
 
46
{
 
47
  BACKGROUND_TYPE_TRANSPARENT,
 
48
  BACKGROUND_TYPE_INVERTED,
 
49
  BACKGROUND_TYPE_IMAGE,
 
50
  BACKGROUND_TYPE_FOREGROUND,
 
51
  BACKGROUND_TYPE_BACKGROUND,
 
52
  BACKGROUND_TYPE_COLOR
 
53
} BackgroundType;
 
54
 
 
55
typedef enum
 
56
{
 
57
  FRACTIONAL_TYPE_BACKGROUND,           /* AS BACKGROUND */
 
58
  FRACTIONAL_TYPE_IGNORE,               /* NOT OPERATED  */
 
59
  FRACTIONAL_TYPE_FORCE                 /* FORCE DIVISION */
 
60
} FractionalType;
 
61
 
 
62
typedef struct _PluginParams PluginParams;
 
63
struct _PluginParams
 
64
{
 
65
  gint32          tile_size;
 
66
  gint32          division_x;
 
67
  gint32          division_y;
 
68
  gdouble         move_max_rate;
 
69
  FractionalType  fractional_type;
 
70
  gboolean        centering;
 
71
  gboolean        wrap_around;
 
72
  BackgroundType  background_type;
 
73
  GimpRGB         background_color;
 
74
};
 
75
 
 
76
/*===========================================================================*/
 
77
/* VARIABLES                                                                 */
 
78
/*===========================================================================*/
 
79
 
 
80
static struct
 
81
{
 
82
  PluginParams  params;
 
83
 
 
84
  gint32        image;
 
85
  GimpDrawable *drawable;
 
86
  gboolean      drawable_has_alpha;
 
87
 
 
88
  struct
 
89
  {
 
90
    gint        x0;
 
91
    gint        y0;
 
92
    gint        x1;
 
93
    gint        y1;
 
94
    gint        width;
 
95
    gint        height;
 
96
  } selection;
 
97
 
 
98
  GimpRunMode  run_mode;
 
99
  gboolean         run;
 
100
} p =
 
101
{
 
102
  {
 
103
    1,                          /* tile_size             */
 
104
    16,                         /* division_x            */
 
105
    16,                         /* division_y            */
 
106
    25.0,                       /* move_max_rate         */
 
107
    FRACTIONAL_TYPE_BACKGROUND, /* fractional_type       */
 
108
    TRUE,                       /* centering             */
 
109
    FALSE,                      /* wrap_around           */
 
110
    BACKGROUND_TYPE_INVERTED,   /* background_type       */
 
111
    { 0.0, 0.0, 1.0, 1.0 }      /* background_color      */
 
112
  },
 
113
 
 
114
  0,                            /* image                 */
 
115
  NULL,                         /* drawable              */
 
116
  FALSE,                        /* drawable_has_alpha    */
 
117
 
 
118
  { 0, 0, 0, 0, 0, 0 },         /* selection             */
 
119
 
 
120
  GIMP_RUN_INTERACTIVE,         /* run_mode              */
 
121
  FALSE                         /* run                   */
 
122
};
 
123
 
 
124
/*---------------------------------------------------------------------------*/
 
125
 
 
126
static void
 
127
params_save_to_gimp (void)
 
128
{
 
129
  gimp_set_data (PLUGIN_PROCEDURE_NAME, &p.params, sizeof p.params);
 
130
}
 
131
 
 
132
static void
 
133
params_load_from_gimp (void)
 
134
{
 
135
  gimp_get_data (PLUGIN_PROCEDURE_NAME, &p.params);
 
136
 
 
137
  if (0 < p.params.division_x)
 
138
    {
 
139
      p.params.tile_size  = p.drawable->width / p.params.division_x;
 
140
      if (0 < p.params.tile_size)
 
141
        {
 
142
          p.params.division_y = p.drawable->height / p.params.tile_size;
 
143
        }
 
144
    }
 
145
  if (p.params.tile_size <= 0 ||
 
146
      p.params.division_x <= 0 ||
 
147
      p.params.division_y <= 0)
 
148
    {
 
149
      p.params.tile_size  = MIN (p.drawable->width, p.drawable->height);
 
150
      p.params.division_x = p.drawable->width / p.params.tile_size;
 
151
      p.params.division_y = p.drawable->height / p.params.tile_size;
 
152
    }
 
153
  if (!p.drawable_has_alpha)
 
154
    {
 
155
      if (p.params.background_type == BACKGROUND_TYPE_TRANSPARENT)
 
156
        {
 
157
          p.params.background_type = BACKGROUND_TYPE_INVERTED;
 
158
        }
 
159
      gimp_rgb_set_alpha (&p.params.background_color, 1.0);
 
160
    }
 
161
}
 
162
 
 
163
/*===========================================================================*/
 
164
/* GUI                                                                       */
 
165
/*===========================================================================*/
 
166
 
 
167
static struct
 
168
{
 
169
  GtkObject *tile_size_adj;
 
170
  GtkObject *division_x_adj;
 
171
  GtkObject *division_y_adj;
 
172
} w;
 
173
 
 
174
static void
 
175
tile_size_adj_changed (GtkAdjustment *adj)
 
176
{
 
177
  if (p.params.tile_size != (gint)adj->value)
 
178
    {
 
179
      p.params.tile_size  = adj->value;
 
180
      p.params.division_x = p.drawable->width  / p.params.tile_size;
 
181
      p.params.division_y = p.drawable->height / p.params.tile_size;
 
182
      gtk_adjustment_set_value (GTK_ADJUSTMENT (w.division_x_adj),
 
183
                                p.params.division_x);
 
184
      gtk_adjustment_set_value (GTK_ADJUSTMENT (w.division_y_adj),
 
185
                                p.params.division_y);
 
186
  }
 
187
}
 
188
 
 
189
static void
 
190
division_x_adj_changed (GtkAdjustment *adj)
 
191
{
 
192
  if (p.params.division_x != (gint)adj->value)
 
193
    {
 
194
      p.params.division_x = adj->value;
 
195
      p.params.tile_size  = p.drawable->width  / p.params.division_x;
 
196
      p.params.division_y =
 
197
        p.drawable->height * p.params.division_x / p.drawable->width;
 
198
      gtk_adjustment_set_value (GTK_ADJUSTMENT (w.tile_size_adj),
 
199
                                p.params.tile_size);
 
200
      gtk_adjustment_set_value (GTK_ADJUSTMENT (w.division_y_adj),
 
201
                                p.params.division_y);
 
202
  }
 
203
}
 
204
 
 
205
static void
 
206
division_y_adj_changed (GtkAdjustment *adj)
 
207
{
 
208
  if (p.params.division_y != (gint)adj->value)
 
209
    {
 
210
      p.params.division_y = adj->value;
 
211
      p.params.tile_size  = p.drawable->height / p.params.division_y;
 
212
      p.params.division_x =
 
213
        p.drawable->width * p.params.division_y / p.drawable->height;
 
214
      gtk_adjustment_set_value (GTK_ADJUSTMENT (w.tile_size_adj),
 
215
                                p.params.tile_size);
 
216
      gtk_adjustment_set_value (GTK_ADJUSTMENT (w.division_x_adj),
 
217
                                p.params.division_x);
 
218
  }
 
219
}
 
220
 
 
221
static void
 
222
open_dialog (void)
 
223
{
 
224
  GtkWidget *dialog;
 
225
  GtkWidget *main_hbox;
 
226
  GtkWidget *button;
 
227
  GtkObject *adjustment;
 
228
  GtkWidget *vbox;
 
229
  GtkWidget *table;
 
230
  GtkWidget *frame;
 
231
  GtkWidget *color_button;
 
232
 
 
233
  gimp_ui_init ("papertile", TRUE);
 
234
 
 
235
  dialog = gimp_dialog_new (_("Paper Tile"), "papertile",
 
236
                            NULL, 0,
 
237
                            gimp_standard_help_func, HELP_ID,
 
238
 
 
239
                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 
240
                            GTK_STOCK_OK,     GTK_RESPONSE_OK,
 
241
 
 
242
                            NULL);
 
243
 
 
244
  main_hbox = gtk_hbox_new (FALSE, 12);
 
245
  gtk_container_set_border_width (GTK_CONTAINER (main_hbox), 12);
 
246
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_hbox);
 
247
  gtk_widget_show (main_hbox);
 
248
 
 
249
  /* Left */
 
250
  vbox = gtk_vbox_new (FALSE, 12);
 
251
  gtk_box_pack_start (GTK_BOX (main_hbox), vbox, FALSE, FALSE, 0);
 
252
  gtk_widget_show (vbox);
 
253
 
 
254
  frame = gimp_frame_new (_("Division"));
 
255
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
256
  gtk_widget_show (frame);
 
257
 
 
258
  table = gtk_table_new (3, 2, FALSE);
 
259
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
 
260
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
 
261
  gtk_container_add (GTK_CONTAINER (frame), table);
 
262
  gtk_widget_show (table);
 
263
 
 
264
  button = gimp_spin_button_new (&w.division_x_adj, p.params.division_x,
 
265
                                 1.0, p.drawable->width, 1.0, 5.0, 0, 1, 0);
 
266
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
 
267
                             _("_X:"), 0.0, 0.5,
 
268
                             button, 1, TRUE);
 
269
  g_signal_connect (w.division_x_adj, "value_changed",
 
270
                    G_CALLBACK (division_x_adj_changed),
 
271
                    NULL);
 
272
 
 
273
  button = gimp_spin_button_new (&w.division_y_adj, p.params.division_y,
 
274
                                 1.0, p.drawable->width, 1.0, 5.0, 0, 1, 0);
 
275
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
 
276
                             _("_Y:"), 0.0, 0.5,
 
277
                             button, 1, TRUE);
 
278
  g_signal_connect (w.division_y_adj, "value_changed",
 
279
                    G_CALLBACK (division_y_adj_changed),
 
280
                    NULL);
 
281
 
 
282
  button = gimp_spin_button_new (&w.tile_size_adj, p.params.tile_size,
 
283
                                 1.0, MAX (p.drawable->width,
 
284
                                           p.drawable->height),
 
285
                                 1.0, 5.0, 0, 1, 0);
 
286
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
 
287
                             _("_Size:"), 0.0, 0.5,
 
288
                             button, 1, TRUE);
 
289
  g_signal_connect (w.tile_size_adj, "value_changed",
 
290
                    G_CALLBACK (tile_size_adj_changed),
 
291
                    NULL);
 
292
 
 
293
  frame = gimp_int_radio_group_new (TRUE, _("Fractional Pixels"),
 
294
                                    G_CALLBACK (gimp_radio_button_update),
 
295
                                    &p.params.fractional_type,
 
296
                                    p.params.fractional_type,
 
297
 
 
298
                                    _("_Background"),
 
299
                                    FRACTIONAL_TYPE_BACKGROUND, NULL,
 
300
                                    _("_Ignore"),
 
301
                                    FRACTIONAL_TYPE_IGNORE, NULL,
 
302
                                    _("_Force"),
 
303
                                    FRACTIONAL_TYPE_FORCE, NULL,
 
304
 
 
305
                                    NULL);
 
306
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
307
  gtk_widget_show (frame);
 
308
 
 
309
  button = gtk_check_button_new_with_mnemonic(_("C_entering"));
 
310
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
 
311
                                p.params.centering);
 
312
  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
 
313
  gtk_widget_show (button);
 
314
 
 
315
  g_signal_connect (button, "toggled",
 
316
                    G_CALLBACK (gimp_toggle_button_update),
 
317
                    &p.params.centering);
 
318
 
 
319
  /* Right */
 
320
  vbox = gtk_vbox_new (FALSE, 12);
 
321
  gtk_box_pack_start (GTK_BOX (main_hbox), vbox, TRUE, TRUE, 0);
 
322
  gtk_widget_show (vbox);
 
323
 
 
324
  frame = gimp_frame_new (_("Movement"));
 
325
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
326
  gtk_widget_show (frame);
 
327
 
 
328
  table = gtk_table_new (2, 2, FALSE);
 
329
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
 
330
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
 
331
  gtk_container_add (GTK_CONTAINER (frame), table);
 
332
  gtk_widget_show (table);
 
333
 
 
334
  button = gimp_spin_button_new (&adjustment, p.params.move_max_rate,
 
335
                                 0.0, 100.0, 1.0, 10.0, 0, 1, 0);
 
336
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
 
337
                             _("_Max (%):"), 0.0, 0.5,
 
338
                             button, 1, TRUE);
 
339
  g_signal_connect (adjustment, "value_changed",
 
340
                    G_CALLBACK (gimp_double_adjustment_update),
 
341
                    &p.params.move_max_rate);
 
342
 
 
343
  button = gtk_check_button_new_with_mnemonic (_("_Wrap around"));
 
344
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
 
345
                                p.params.wrap_around);
 
346
  gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 2, 1, 2);
 
347
  gtk_widget_show (button);
 
348
 
 
349
  g_signal_connect (button, "toggled",
 
350
                    G_CALLBACK (gimp_toggle_button_update),
 
351
                    &p.params.wrap_around);
 
352
 
 
353
  frame = gimp_int_radio_group_new (TRUE, _("Background Type"),
 
354
                                    G_CALLBACK (gimp_radio_button_update),
 
355
                                    &p.params.background_type,
 
356
                                    p.params.background_type,
 
357
 
 
358
                                    _("_Transparent"),
 
359
                                    BACKGROUND_TYPE_TRANSPARENT, NULL,
 
360
                                    _("I_nverted image"),
 
361
                                    BACKGROUND_TYPE_INVERTED, NULL,
 
362
                                    _("Im_age"),
 
363
                                    BACKGROUND_TYPE_IMAGE, NULL,
 
364
                                    _("Fo_reground color"),
 
365
                                    BACKGROUND_TYPE_FOREGROUND, NULL,
 
366
                                    _("Bac_kground color"),
 
367
                                    BACKGROUND_TYPE_BACKGROUND, NULL,
 
368
                                    _("S_elect here:"),
 
369
                                    BACKGROUND_TYPE_COLOR, &button,
 
370
 
 
371
                                    NULL);
 
372
  gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
 
373
  gtk_widget_show (frame);
 
374
 
 
375
  color_button = gimp_color_button_new (_("Background Color"), 100, 16,
 
376
                                        &p.params.background_color,
 
377
                                        p.drawable_has_alpha ?
 
378
                                        GIMP_COLOR_AREA_SMALL_CHECKS :
 
379
                                        GIMP_COLOR_AREA_FLAT);
 
380
  gtk_box_pack_start (GTK_BOX (GTK_BIN (frame)->child),
 
381
                      color_button, TRUE, TRUE, 0);
 
382
  gtk_widget_show (color_button);
 
383
 
 
384
  gtk_widget_set_sensitive (color_button,
 
385
                            p.params.background_type == BACKGROUND_TYPE_COLOR);
 
386
  g_object_set_data (G_OBJECT (button), "set_sensitive", color_button);
 
387
 
 
388
  g_signal_connect (color_button, "color_changed",
 
389
                    G_CALLBACK (gimp_color_button_get_color),
 
390
                    &p.params.background_color);
 
391
 
 
392
  gtk_widget_show (dialog);
 
393
 
 
394
  p.run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
 
395
 
 
396
  gtk_widget_destroy (dialog);
 
397
}
 
398
 
 
399
/*===========================================================================*/
 
400
/* PLUGIN CORE                                                               */
 
401
/*===========================================================================*/
 
402
typedef struct _Tile
 
403
{
 
404
  guint x;
 
405
  guint y;
 
406
  gint  z;
 
407
  guint width;
 
408
  guint height;
 
409
  gint  move_x;
 
410
  gint  move_y;
 
411
} Tile;
 
412
 
 
413
static gint
 
414
tile_compare (const void *x,
 
415
              const void *y)
 
416
{
 
417
  return ((Tile *) x)->z - ((Tile *) y)->z;
 
418
}
 
419
 
 
420
static inline gdouble
 
421
drand (void)
 
422
{
 
423
  return g_random_double_range (-1, 1);
 
424
}
 
425
 
 
426
static inline void
 
427
random_move (gint *x,
 
428
             gint *y,
 
429
             gint  max)
 
430
{
 
431
  gdouble angle  = drand () * G_PI;
 
432
  gdouble radius = drand () * (gdouble) max;
 
433
  *x = (gint) (radius * cos (angle));
 
434
  *y = (gint) (radius * sin (angle));
 
435
}
 
436
 
 
437
static void
 
438
overlap_RGB (guchar       *base,
 
439
             const guchar *top)
 
440
{
 
441
  base[0] = top[0];
 
442
  base[1] = top[1];
 
443
  base[2] = top[2];
 
444
}
 
445
 
 
446
static void
 
447
overlap_RGBA (guchar       *base,
 
448
              const guchar *top)
 
449
{
 
450
  gdouble R1 = (gdouble) base[0] / 255.0;
 
451
  gdouble G1 = (gdouble) base[1] / 255.0;
 
452
  gdouble B1 = (gdouble) base[2] / 255.0;
 
453
  gdouble A1 = (gdouble) base[3] / 255.0;
 
454
  gdouble R2 = (gdouble)  top[0] / 255.0;
 
455
  gdouble G2 = (gdouble)  top[1] / 255.0;
 
456
  gdouble B2 = (gdouble)  top[2] / 255.0;
 
457
  gdouble A2 = (gdouble)  top[3] / 255.0;
 
458
  gdouble A3 = A2 + A1 * (1.0 - A2);
 
459
  if(0.0 < A3)
 
460
    {
 
461
      gdouble R3 = (R1 * A1 * (1.0 - A2) + R2 * A2) / A3;
 
462
      gdouble G3 = (G1 * A1 * (1.0 - A2) + G2 * A2) / A3;
 
463
      gdouble B3 = (B1 * A1 * (1.0 - A2) + B2 * A2) / A3;
 
464
      R3 = CLAMP (R3, 0.0, 1.0);
 
465
      G3 = CLAMP (G3, 0.0, 1.0);
 
466
      B3 = CLAMP (B3, 0.0, 1.0);
 
467
      base[0] = (guchar) (R3 * 255.0);
 
468
      base[1] = (guchar) (G3 * 255.0);
 
469
      base[2] = (guchar) (B3 * 255.0);
 
470
      base[3] = (guchar) (A3 * 255.0);
 
471
    }
 
472
  else
 
473
    {
 
474
      base[0] = 0;
 
475
      base[1] = 0;
 
476
      base[2] = 0;
 
477
      base[3] = 0;
 
478
    }
 
479
}
 
480
 
 
481
static inline void
 
482
filter (void)
 
483
{
 
484
  static void (* overlap)(guchar *, const guchar *);
 
485
  GimpPixelRgn  src;
 
486
  GimpPixelRgn  dst;
 
487
  GimpRGB       color;
 
488
  guchar     pixel[4];
 
489
  gint       division_x;
 
490
  gint       division_y;
 
491
  gint       offset_x;
 
492
  gint       offset_y;
 
493
  Tile      *tiles;
 
494
  gint       numof_tiles;
 
495
  Tile      *t;
 
496
  gint       i;
 
497
  gint       x;
 
498
  gint       y;
 
499
  gint       move_max_pixels;
 
500
  gint       clear_x0;
 
501
  gint       clear_y0;
 
502
  gint       clear_x1;
 
503
  gint       clear_y1;
 
504
  gint       clear_width;
 
505
  gint       clear_height;
 
506
  guchar    *pixels;
 
507
  guchar    *buffer;
 
508
  gint       dindex;
 
509
  gint       sindex;
 
510
  gint       px, py;
 
511
  GRand     *gr;
 
512
 
 
513
  gr = g_rand_new ();
 
514
 
 
515
  /* INITIALIZE */
 
516
  gimp_pixel_rgn_init (&src, p.drawable, 0, 0,
 
517
                       p.drawable->width, p.drawable->height, FALSE, FALSE);
 
518
  gimp_pixel_rgn_init (&dst, p.drawable, 0, 0,
 
519
                       p.drawable->width, p.drawable->height, TRUE, TRUE);
 
520
  pixels = g_new (guchar,
 
521
                  p.drawable->bpp * p.drawable->width * p.drawable->height);
 
522
  buffer = g_new (guchar,
 
523
                  p.drawable->bpp * p.params.tile_size * p.params.tile_size);
 
524
 
 
525
  overlap = p.drawable_has_alpha ? overlap_RGBA : overlap_RGB;
 
526
 
 
527
  gimp_progress_init (_("Paper Tile..."));
 
528
 
 
529
  gimp_drawable_mask_bounds (p.drawable->drawable_id,
 
530
                             &p.selection.x0, &p.selection.y0,
 
531
                             &p.selection.x1, &p.selection.y1);
 
532
  p.selection.width  = p.selection.x1 - p.selection.x0;
 
533
  p.selection.height = p.selection.y1 - p.selection.y0;
 
534
 
 
535
  gimp_tile_cache_ntiles (2 * (p.selection.width / gimp_tile_width () + 1));
 
536
 
 
537
  /* TILES */
 
538
  division_x = p.params.division_x;
 
539
  division_y = p.params.division_y;
 
540
  if (p.params.fractional_type == FRACTIONAL_TYPE_FORCE)
 
541
    {
 
542
      if (0 < p.drawable->width  % p.params.tile_size) division_x++;
 
543
      if (0 < p.drawable->height % p.params.tile_size) division_y++;
 
544
      if (p.params.centering)
 
545
        {
 
546
          if (1 < p.drawable->width % p.params.tile_size)
 
547
            {
 
548
              division_x++;
 
549
              offset_x =
 
550
                (p.drawable->width % p.params.tile_size) / 2 -
 
551
                p.params.tile_size;
 
552
            }
 
553
          else
 
554
            {
 
555
              offset_x = 0;
 
556
            }
 
557
          if (1 < p.drawable->height % p.params.tile_size)
 
558
            {
 
559
              division_y++;
 
560
              offset_y =
 
561
                (p.drawable->height % p.params.tile_size) / 2 -
 
562
                p.params.tile_size;
 
563
            }
 
564
          else
 
565
            {
 
566
              offset_y = 0;
 
567
            }
 
568
        }
 
569
      else
 
570
        {
 
571
          offset_x = 0;
 
572
          offset_y = 0;
 
573
        }
 
574
    }
 
575
  else
 
576
    {
 
577
      if (p.params.centering)
 
578
        {
 
579
          offset_x = (p.drawable->width  % p.params.tile_size) / 2;
 
580
          offset_y = (p.drawable->height % p.params.tile_size) / 2;
 
581
        }
 
582
      else
 
583
        {
 
584
          offset_x = 0;
 
585
          offset_y = 0;
 
586
        }
 
587
    }
 
588
  move_max_pixels = p.params.move_max_rate * p.params.tile_size / 100.0;
 
589
  numof_tiles = division_x * division_y;
 
590
  t = tiles = g_new(Tile, numof_tiles);
 
591
  for (y = 0; y < division_y; y++)
 
592
    {
 
593
      gint srcy = offset_y + p.params.tile_size * y;
 
594
      for (x = 0; x < division_x; x++, t++)
 
595
        {
 
596
          gint srcx = offset_x + p.params.tile_size * x;
 
597
          if (srcx < 0)
 
598
            {
 
599
              t->x     = 0;
 
600
              t->width = srcx + p.params.tile_size;
 
601
            }
 
602
          else if (srcx + p.params.tile_size < p.drawable->width)
 
603
            {
 
604
              t->x     = srcx;
 
605
              t->width = p.params.tile_size;
 
606
            }
 
607
          else
 
608
            {
 
609
              t->x     = srcx;
 
610
              t->width = p.drawable->width - srcx;
 
611
            }
 
612
          if (srcy < 0)
 
613
            {
 
614
              t->y      = 0;
 
615
              t->height = srcy + p.params.tile_size;
 
616
            }
 
617
          else if (srcy + p.params.tile_size < p.drawable->height)
 
618
            {
 
619
              t->y      = srcy;
 
620
              t->height = p.params.tile_size;
 
621
            }
 
622
          else
 
623
            {
 
624
              t->y      = srcy;
 
625
              t->height = p.drawable->height - srcy;
 
626
            }
 
627
          t->z = g_rand_int (gr);
 
628
          random_move (&t->move_x, &t->move_y, move_max_pixels);
 
629
        }
 
630
    }
 
631
  qsort (tiles, numof_tiles, sizeof *tiles, tile_compare);
 
632
 
 
633
  gimp_pixel_rgn_get_rect (&src, pixels, 0, 0, p.drawable->width,
 
634
                           p.drawable->height);
 
635
 
 
636
  if (p.params.fractional_type == FRACTIONAL_TYPE_IGNORE)
 
637
    {
 
638
      clear_x0     = offset_x;
 
639
      clear_y0     = offset_y;
 
640
      clear_width  = p.params.tile_size * division_x;
 
641
      clear_height = p.params.tile_size * division_y;
 
642
    }
 
643
  else
 
644
    {
 
645
      clear_x0     = 0;
 
646
      clear_y0     = 0;
 
647
      clear_width  = p.drawable->width;
 
648
      clear_height = p.drawable->height;
 
649
    }
 
650
  clear_x1 = clear_x0 + clear_width;
 
651
  clear_y1 = clear_y0 + clear_height;
 
652
 
 
653
  switch (p.params.background_type)
 
654
    {
 
655
    case BACKGROUND_TYPE_TRANSPARENT:
 
656
      for (y = clear_y0; y < clear_y1; y++)
 
657
        {
 
658
          for (x = clear_x0; x < clear_x1; x++)
 
659
            {
 
660
              dindex = p.drawable->bpp * (p.drawable->width * y + x);
 
661
              for (i = 0; i < p.drawable->bpp; i++)
 
662
                {
 
663
                  pixels[dindex+i] = 0;
 
664
                }
 
665
            }
 
666
        }
 
667
      break;
 
668
 
 
669
    case BACKGROUND_TYPE_INVERTED:
 
670
      for (y = clear_y0; y < clear_y1; y++)
 
671
        {
 
672
          for (x = clear_x0; x < clear_x1; x++)
 
673
            {
 
674
              dindex = p.drawable->bpp * (p.drawable->width * y + x);
 
675
              pixels[dindex+0] = 255 - pixels[dindex+0];
 
676
              pixels[dindex+1] = 255 - pixels[dindex+1];
 
677
              pixels[dindex+2] = 255 - pixels[dindex+2];
 
678
            }
 
679
        }
 
680
      break;
 
681
 
 
682
    case BACKGROUND_TYPE_IMAGE:
 
683
      break;
 
684
 
 
685
    case BACKGROUND_TYPE_FOREGROUND:
 
686
      gimp_context_get_foreground (&color);
 
687
      gimp_rgb_get_uchar (&color, &pixel[0], &pixel[1], &pixel[2]);
 
688
      pixel[3] = 255;
 
689
      for (y = clear_y0; y < clear_y1; y++)
 
690
        {
 
691
          for (x = clear_x0; x < clear_x1; x++)
 
692
            {
 
693
              dindex = p.drawable->bpp * (p.drawable->width * y + x);
 
694
              for (i = 0; i < p.drawable->bpp; i++)
 
695
                {
 
696
                  pixels[dindex+i] = pixel[i];
 
697
                }
 
698
            }
 
699
        }
 
700
      break;
 
701
 
 
702
    case BACKGROUND_TYPE_BACKGROUND:
 
703
      gimp_context_get_background (&color);
 
704
      gimp_rgb_get_uchar (&color, &pixel[0], &pixel[1], &pixel[2]);
 
705
      pixel[3] = 255;
 
706
      for (y = clear_y0; y < clear_y1; y++)
 
707
        {
 
708
          for (x = clear_x0; x < clear_x1; x++)
 
709
            {
 
710
              dindex = p.drawable->bpp * (p.drawable->width * y + x);
 
711
              for(i = 0; i < p.drawable->bpp; i++)
 
712
                {
 
713
                  pixels[dindex+i] = pixel[i];
 
714
                }
 
715
            }
 
716
        }
 
717
      break;
 
718
 
 
719
    case BACKGROUND_TYPE_COLOR:
 
720
      gimp_rgba_get_uchar (&p.params.background_color,
 
721
                           pixel, pixel + 1, pixel + 2, pixel + 3);
 
722
      for (y = clear_y0; y < clear_y1; y++)
 
723
        {
 
724
          for (x = clear_x0; x < clear_x1; x++)
 
725
            {
 
726
              dindex = p.drawable->bpp * (p.drawable->width * y + x);
 
727
              for(i = 0; i < p.drawable->bpp; i++)
 
728
                {
 
729
                  pixels[dindex+i] = pixel[i];
 
730
                }
 
731
            }
 
732
        }
 
733
      break;
 
734
    }
 
735
 
 
736
  /* DRAW */
 
737
  for (t = tiles, i = 0; i < numof_tiles; i++, t++)
 
738
    {
 
739
      gint x0 = t->x + t->move_x;
 
740
      gint y0 = t->y + t->move_y;
 
741
 
 
742
      gimp_pixel_rgn_get_rect (&src, buffer, t->x, t->y, t->width, t->height);
 
743
 
 
744
      for (y = 0; y < t->height; y++)
 
745
        {
 
746
          py = y0 + y;
 
747
          for (x = 0; x < t->width; x++)
 
748
            {
 
749
              px = x0 + x;
 
750
              sindex = p.drawable->bpp * (t->width * y + x);
 
751
              if (0 <= px && px < p.drawable->width &&
 
752
                  0 <= py && py < p.drawable->height)
 
753
                {
 
754
                  dindex = p.drawable->bpp * (p.drawable->width * py + px);
 
755
                  overlap(&pixels[dindex], &buffer[sindex]);
 
756
                }
 
757
              else if (p.params.wrap_around)
 
758
                {
 
759
                  px = (px + p.drawable->width)  % p.drawable->width;
 
760
                  py = (py + p.drawable->height) % p.drawable->height;
 
761
                  dindex = p.drawable->bpp * (p.drawable->width * py + px);
 
762
                  overlap(&pixels[dindex], &buffer[sindex]);
 
763
                }
 
764
            }
 
765
        }
 
766
 
 
767
      gimp_progress_update ((gdouble) i / (gdouble) numof_tiles);
 
768
    }
 
769
 
 
770
  gimp_pixel_rgn_set_rect (&dst, pixels, 0, 0, p.drawable->width,
 
771
                           p.drawable->height);
 
772
 
 
773
  gimp_drawable_flush (p.drawable);
 
774
  gimp_drawable_merge_shadow (p.drawable->drawable_id, TRUE);
 
775
  gimp_drawable_update (p.drawable->drawable_id,
 
776
                        p.selection.x0, p.selection.y0,
 
777
                        p.selection.width, p.selection.height);
 
778
 
 
779
  g_rand_free (gr);
 
780
  g_free (buffer);
 
781
  g_free (pixels);
 
782
  g_free (tiles);
 
783
}
 
784
 
 
785
/*============================================================================*/
 
786
/* PLUGIN INTERFACES                                                          */
 
787
/*============================================================================*/
 
788
 
 
789
static void
 
790
plugin_query (void)
 
791
{
 
792
  static GimpParamDef     args[]            =
 
793
  {
 
794
    { GIMP_PDB_INT32,    "run_mode",         "run mode"                         },
 
795
    { GIMP_PDB_IMAGE,    "image",            "input image"                      },
 
796
    { GIMP_PDB_DRAWABLE, "drawable",         "input drawable"                   },
 
797
    { GIMP_PDB_INT32,    "tile_size",        "tile size (pixels)"               },
 
798
    { GIMP_PDB_FLOAT,    "move_max",         "max move rate (%)"                },
 
799
    { GIMP_PDB_INT32,    "fractional_type",  "0:Background 1:Ignore 2:Force"    },
 
800
    { GIMP_PDB_INT32,    "wrap_around",      "wrap around (bool)"               },
 
801
    { GIMP_PDB_INT32,    "centering",        "centering (bool)"                 },
 
802
    { GIMP_PDB_INT32,    "background_type",
 
803
      "0:Transparent 1:Inverted 2:Image? 3:FG 4:BG 5:Color"                  },
 
804
    { GIMP_PDB_INT32,    "background_color", "background color (for bg-type 5)" },
 
805
    { GIMP_PDB_INT32,    "background_alpha", "opacity (for bg-type 5)"          }
 
806
  };
 
807
 
 
808
  gimp_install_procedure (PLUGIN_PROCEDURE_NAME,
 
809
                          "Cuts an image into paper tiles, and slides each "
 
810
                          "paper tile.",
 
811
                          "This plug-in cuts an image into paper tiles and "
 
812
                          "slides each paper tile.",
 
813
                          "Hirotsuna Mizuno <s1041150@u-aizu.ac.jp>",
 
814
                          "Copyright (c)1997-1999 Hirotsuna Mizuno",
 
815
                          _("September 31, 1999"),
 
816
                          N_("_Paper Tile..."),
 
817
                          "RGB*",
 
818
                          GIMP_PLUGIN,
 
819
                          G_N_ELEMENTS (args), 0,
 
820
                          args, NULL);
 
821
 
 
822
  gimp_plugin_menu_register (PLUGIN_PROCEDURE_NAME, "<Image>/Filters/Map");
 
823
}
 
824
 
 
825
static void
 
826
plugin_run (const gchar      *name,
 
827
            gint              numof_params,
 
828
            const GimpParam  *params,
 
829
            gint             *numof_return_vals,
 
830
            GimpParam       **return_vals)
 
831
{
 
832
  GimpPDBStatusType status;
 
833
 
 
834
  INIT_I18N ();
 
835
 
 
836
  status = GIMP_PDB_SUCCESS;
 
837
  p.run  = FALSE;
 
838
  p.run_mode = params[0].data.d_int32;
 
839
  p.image    = params[1].data.d_image;
 
840
  p.drawable = gimp_drawable_get(params[2].data.d_drawable);
 
841
  p.drawable_has_alpha = gimp_drawable_has_alpha(p.drawable->drawable_id);
 
842
 
 
843
  if (gimp_drawable_is_rgb (p.drawable->drawable_id))
 
844
    {
 
845
      switch (p.run_mode)
 
846
        {
 
847
        case GIMP_RUN_INTERACTIVE:
 
848
          params_load_from_gimp ();
 
849
          open_dialog ();
 
850
          break;
 
851
 
 
852
        case GIMP_RUN_NONINTERACTIVE:
 
853
          if (numof_params == 11)
 
854
            {
 
855
              p.params.tile_size        = params[3].data.d_int32;
 
856
              p.params.division_x       = p.drawable->width  / p.params.tile_size;
 
857
              p.params.division_y       = p.drawable->height / p.params.tile_size;
 
858
              p.params.move_max_rate    = params[4].data.d_float;
 
859
              p.params.fractional_type  = (FractionalType)params[5].data.d_int32;
 
860
              p.params.wrap_around      = params[6].data.d_int32;
 
861
              p.params.centering        = params[7].data.d_int32;
 
862
              p.params.background_type  = (BackgroundType)params[8].data.d_int32;
 
863
              p.params.background_color = params[9].data.d_color;
 
864
 
 
865
              /*  FIXME:  this used to be the alpha value
 
866
                                          params[10].data.d_int32
 
867
               */
 
868
              p.run = TRUE;
 
869
            }
 
870
          else
 
871
            {
 
872
              status = GIMP_PDB_CALLING_ERROR;
 
873
            }
 
874
          break;
 
875
 
 
876
        case GIMP_RUN_WITH_LAST_VALS:
 
877
          params_load_from_gimp ();
 
878
          p.run = TRUE;
 
879
          break;
 
880
        }
 
881
    }
 
882
  else
 
883
    {
 
884
      status = GIMP_PDB_EXECUTION_ERROR;
 
885
    }
 
886
 
 
887
  if (status == GIMP_PDB_SUCCESS && p.run)
 
888
    {
 
889
      params_save_to_gimp ();
 
890
 
 
891
      filter ();
 
892
 
 
893
      if (p.run_mode != GIMP_RUN_NONINTERACTIVE)
 
894
        gimp_displays_flush ();
 
895
    }
 
896
 
 
897
  gimp_drawable_detach (p.drawable);
 
898
 
 
899
  {
 
900
    static GimpParam return_value[1];
 
901
    return_value[0].type          = GIMP_PDB_STATUS;
 
902
    return_value[0].data.d_status = status;
 
903
    *numof_return_vals            = 1;
 
904
    *return_vals                  = return_value;
 
905
  }
 
906
}
 
907
 
 
908
GimpPlugInInfo PLUG_IN_INFO =
 
909
{
 
910
  NULL,
 
911
  NULL,
 
912
  plugin_query,
 
913
  plugin_run
 
914
};
 
915
 
 
916
MAIN ()