~ubuntu-branches/ubuntu/jaunty/gimp/jaunty-security

« back to all changes in this revision

Viewing changes to plug-ins/gradient-flare/gradient-flare.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2008-10-06 13:30:41 UTC
  • mto: This revision was merged to the branch mainline in revision 35.
  • Revision ID: james.westby@ubuntu.com-20081006133041-3panbkcanaymfsmp
Tags: upstream-2.6.0
ImportĀ upstreamĀ versionĀ 2.6.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GIMP - The GNU Image Manipulation Program
 
2
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 
3
 *
 
4
 * GFlare plug-in -- lense flare effect by using custom gradients
 
5
 * Copyright (C) 1997 Eiichi Takamori <taka@ma1.sekyou.ne.jp>
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 2 of the License, or
 
10
 * (at your option) any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
20
 *
 
21
 *
 
22
 * A fair proportion of this code was taken from GIMP & Script-fu
 
23
 * copyrighted by Spencer Kimball and Peter Mattis, and from Gradient
 
24
 * Editor copyrighted by Federico Mena Quintero. (See copyright notice
 
25
 * below) Thanks for senior GIMP hackers!!
 
26
 *
 
27
 * GIMP - The GNU Image Manipulation Program
 
28
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 
29
 *
 
30
 * Gradient editor module copyight (C) 1996-1997 Federico Mena Quintero
 
31
 * federico@nuclecu.unam.mx
 
32
 */
 
33
 
 
34
#include "config.h"
 
35
 
 
36
#include <string.h>
 
37
#include <stdlib.h>
 
38
#include <errno.h>
 
39
 
 
40
#ifdef HAVE_UNISTD_H
 
41
#include <unistd.h>
 
42
#endif
 
43
 
 
44
#include <glib/gstdio.h>
 
45
 
 
46
#include <glib-object.h>
 
47
 
 
48
#include <libgimp/gimp.h>
 
49
#include <libgimp/gimpui.h>
 
50
 
 
51
#include "libgimp/stdplugins-intl.h"
 
52
 
 
53
/* #define DEBUG */
 
54
 
 
55
#ifdef DEBUG
 
56
#define DEBUG_PRINT(X) g_print X
 
57
#else
 
58
#define DEBUG_PRINT(X)
 
59
#endif
 
60
 
 
61
#define LUMINOSITY(PIX) (GIMP_RGB_LUMINANCE (PIX[0], PIX[1], PIX[2]) + 0.5)
 
62
 
 
63
#define RESPONSE_RESCAN     1
 
64
 
 
65
#define PLUG_IN_PROC        "plug-in-gflare"
 
66
#define PLUG_IN_BINARY      "gradient-flare"
 
67
 
 
68
#define GRADIENT_NAME_MAX   256
 
69
#define GRADIENT_RESOLUTION 360
 
70
 
 
71
#define GFLARE_NAME_MAX     256
 
72
#define GFLARE_FILE_HEADER  "GIMP GFlare 0.25\n"
 
73
#define SFLARE_NUM           30
 
74
 
 
75
#define DLG_PREVIEW_WIDTH   256
 
76
#define DLG_PREVIEW_HEIGHT  256
 
77
#define DLG_PREVIEW_MASK    GDK_EXPOSURE_MASK | \
 
78
                            GDK_BUTTON_PRESS_MASK
 
79
#define DLG_LISTBOX_WIDTH   80
 
80
#define DLG_LISTBOX_HEIGHT  40
 
81
 
 
82
#define ED_PREVIEW_WIDTH    256
 
83
#define ED_PREVIEW_HEIGHT   256
 
84
 
 
85
#define GM_PREVIEW_WIDTH    80
 
86
#define GM_PREVIEW_HEIGHT   16
 
87
 
 
88
#define SCALE_WIDTH         80
 
89
 
 
90
#ifndef OPAQUE
 
91
#define OPAQUE              255
 
92
#endif
 
93
#define GRAY50              128
 
94
 
 
95
#define GRADIENT_CACHE_SIZE 32
 
96
 
 
97
#define CALC_GLOW   0x01
 
98
#define CALC_RAYS   0x02
 
99
#define CALC_SFLARE 0x04
 
100
 
 
101
typedef struct _Preview Preview;
 
102
 
 
103
typedef gchar   GradientName[GRADIENT_NAME_MAX];
 
104
 
 
105
typedef enum
 
106
{
 
107
  GF_NORMAL = 0,
 
108
  GF_ADDITION,
 
109
  GF_OVERLAY,
 
110
  GF_SCREEN,
 
111
  GF_NUM_MODES
 
112
} GFlareMode;
 
113
 
 
114
typedef enum
 
115
{
 
116
  GF_CIRCLE = 0,
 
117
  GF_POLYGON,
 
118
  GF_NUM_SHAPES
 
119
} GFlareShape;
 
120
 
 
121
typedef struct
 
122
{
 
123
  gchar        *name;
 
124
  gchar        *filename;
 
125
  gdouble       glow_opacity;
 
126
  GFlareMode    glow_mode;
 
127
  gdouble       rays_opacity;
 
128
  GFlareMode    rays_mode;
 
129
  gdouble       sflare_opacity;
 
130
  GFlareMode    sflare_mode;
 
131
  GradientName  glow_radial;
 
132
  GradientName  glow_angular;
 
133
  GradientName  glow_angular_size;
 
134
  gdouble       glow_size;
 
135
  gdouble       glow_rotation;
 
136
  gdouble       glow_hue;
 
137
  GradientName  rays_radial;
 
138
  GradientName  rays_angular;
 
139
  GradientName  rays_angular_size;
 
140
  gdouble       rays_size;
 
141
  gdouble       rays_rotation;
 
142
  gdouble       rays_hue;
 
143
  gint          rays_nspikes;
 
144
  gdouble       rays_thickness;
 
145
  GradientName  sflare_radial;
 
146
  GradientName  sflare_sizefac;
 
147
  GradientName  sflare_probability;
 
148
  gdouble       sflare_size;
 
149
  gdouble       sflare_rotation;
 
150
  gdouble       sflare_hue;
 
151
  GFlareShape   sflare_shape;
 
152
  gint          sflare_nverts;
 
153
  guint32       sflare_seed;
 
154
  gboolean      random_seed;
 
155
} GFlare;
 
156
 
 
157
typedef struct
 
158
{
 
159
  FILE *fp;
 
160
  gint  error;
 
161
} GFlareFile;
 
162
 
 
163
 
 
164
typedef enum
 
165
{
 
166
  PAGE_SETTINGS,
 
167
  PAGE_SELECTOR,
 
168
  PAGE_GENERAL,
 
169
  PAGE_GLOW,
 
170
  PAGE_RAYS,
 
171
  PAGE_SFLARE
 
172
} PageNum;
 
173
 
 
174
 
 
175
typedef struct
 
176
{
 
177
  gint       init;
 
178
  GFlare    *gflare;
 
179
  GtkWidget *shell;
 
180
  Preview   *preview;
 
181
  struct
 
182
  {
 
183
    gdouble x0, y0, x1, y1;
 
184
  } pwin;
 
185
  gboolean          update_preview;
 
186
  GtkWidget        *notebook;
 
187
  GtkWidget        *sizeentry;
 
188
  GtkWidget        *asupsample_frame;
 
189
  GtkListStore     *selector_list;
 
190
  GtkTreeSelection *selection;
 
191
  gint              init_params_done;
 
192
} GFlareDialog;
 
193
 
 
194
typedef void (* GFlareEditorCallback) (gint updated, gpointer data);
 
195
 
 
196
typedef struct
 
197
{
 
198
  gint                  init;
 
199
  gint                  run;
 
200
  GFlareEditorCallback  callback;
 
201
  gpointer              calldata;
 
202
  GFlare               *target_gflare;
 
203
  GFlare               *gflare;
 
204
  GtkWidget            *shell;
 
205
  Preview              *preview;
 
206
  GtkWidget            *notebook;
 
207
  PageNum               cur_page;
 
208
  GtkWidget            *polygon_entry;
 
209
  GtkWidget            *polygon_toggle;
 
210
  gint                  init_params_done;
 
211
} GFlareEditor;
 
212
 
 
213
typedef struct
 
214
{
 
215
  gdouble x0;
 
216
  gdouble y0;
 
217
  gdouble x1;
 
218
  gdouble y1;
 
219
} CalcBounds;
 
220
 
 
221
typedef struct
 
222
{
 
223
  gint     init;
 
224
  gint     type;
 
225
  GFlare  *gflare;
 
226
  gdouble  xcenter;
 
227
  gdouble  ycenter;
 
228
  gdouble  radius;
 
229
  gdouble  rotation;
 
230
  gdouble  hue;
 
231
  gdouble  vangle;
 
232
  gdouble  vlength;
 
233
 
 
234
  gint        glow_opacity;
 
235
  CalcBounds  glow_bounds;
 
236
  guchar     *glow_radial;
 
237
  guchar     *glow_angular;
 
238
  guchar     *glow_angular_size;
 
239
  gdouble     glow_radius;
 
240
  gdouble     glow_rotation;
 
241
 
 
242
  gint        rays_opacity;
 
243
  CalcBounds  rays_bounds;
 
244
  guchar     *rays_radial;
 
245
  guchar     *rays_angular;
 
246
  guchar     *rays_angular_size;
 
247
  gdouble     rays_radius;
 
248
  gdouble     rays_rotation;
 
249
  gdouble     rays_spike_mod;
 
250
  gdouble     rays_thinness;
 
251
 
 
252
  gint         sflare_opacity;
 
253
  GList       *sflare_list;
 
254
  guchar      *sflare_radial;
 
255
  guchar      *sflare_sizefac;
 
256
  guchar      *sflare_probability;
 
257
  gdouble      sflare_radius;
 
258
  gdouble      sflare_rotation;
 
259
  GFlareShape  sflare_shape;
 
260
  gdouble      sflare_angle;
 
261
  gdouble      sflare_factor;
 
262
} CalcParams;
 
263
 
 
264
/*
 
265
 * What's the difference between (structure) CalcParams and GFlare ?
 
266
 * well, radius and lengths are actual length for CalcParams where
 
267
 * they are typically 0 to 100 for GFlares, and angles are G_PI based
 
268
 * (radian) for CalcParams where they are degree for GFlares. et cetra.
 
269
 * This is because convienience for dialog processing and for calculating.
 
270
 * these conversion is taken place in calc init routines. see below.
 
271
 */
 
272
 
 
273
typedef struct
 
274
{
 
275
  gdouble    xcenter;
 
276
  gdouble    ycenter;
 
277
  gdouble    radius;
 
278
  CalcBounds bounds;
 
279
} CalcSFlare;
 
280
 
 
281
typedef struct
 
282
{
 
283
  gint is_color;
 
284
  gint has_alpha;
 
285
  gint x1, y1, x2, y2;          /* mask bounds */
 
286
  gint tile_width, tile_height;
 
287
  /* these values don't belong to drawable, though. */
 
288
} DrawableInfo;
 
289
 
 
290
typedef struct _GradientMenu GradientMenu;
 
291
typedef void (* GradientMenuCallback) (const gchar *gradient_name,
 
292
                                       gpointer     data);
 
293
struct _GradientMenu
 
294
{
 
295
  GtkWidget            *preview;
 
296
  GtkWidget            *combo;
 
297
  GradientMenuCallback  callback;
 
298
  gpointer              callback_data;
 
299
  GradientName          gradient_name;
 
300
};
 
301
 
 
302
typedef gint (* PreviewInitFunc)   (Preview  *preview,
 
303
                                    gpointer  data);
 
304
typedef void (* PreviewRenderFunc) (Preview  *preview,
 
305
                                    guchar   *buffer,
 
306
                                    gint      y,
 
307
                                    gpointer  data);
 
308
typedef void (* PreviewDeinitFunc) (Preview  *preview,
 
309
                                    gpointer  data);
 
310
 
 
311
struct _Preview
 
312
{
 
313
  GtkWidget         *widget;
 
314
  gint               width;
 
315
  gint               height;
 
316
  PreviewInitFunc    init_func;
 
317
  gpointer           init_data;
 
318
  PreviewRenderFunc  render_func;
 
319
  gpointer           render_data;
 
320
  PreviewDeinitFunc  deinit_func;
 
321
  gpointer           deinit_data;
 
322
  guint              timeout_tag;
 
323
  guint              idle_tag;
 
324
  gint               init_done;
 
325
  gint               current_y;
 
326
  gint               drawn_y;
 
327
  guchar            *buffer;
 
328
  guchar            *full_image_buffer;
 
329
};
 
330
 
 
331
typedef struct
 
332
{
 
333
  gint               tag;
 
334
  gint               got_gradients;
 
335
  gint               current_y;
 
336
  gint               drawn_y;
 
337
  PreviewRenderFunc  render_func;
 
338
  guchar            *buffer;
 
339
} PreviewIdle;
 
340
 
 
341
typedef struct _GradientCacheItem  GradientCacheItem;
 
342
 
 
343
struct _GradientCacheItem
 
344
{
 
345
  GradientCacheItem *next;
 
346
  GradientCacheItem *prev;
 
347
  GradientName       name;
 
348
  guchar             values[4 * GRADIENT_RESOLUTION];
 
349
};
 
350
 
 
351
typedef struct
 
352
{
 
353
  gint     xcenter;
 
354
  gint     ycenter;
 
355
  gdouble  radius;
 
356
  gdouble  rotation;
 
357
  gdouble  hue;
 
358
  gdouble  vangle;
 
359
  gdouble  vlength;
 
360
  gint     use_asupsample;
 
361
  gint     asupsample_max_depth;
 
362
  gdouble  asupsample_threshold;
 
363
  gchar    gflare_name[GFLARE_NAME_MAX];
 
364
} PluginValues;
 
365
 
 
366
 
 
367
typedef void (* QueryFunc) (GtkWidget *,
 
368
                            gpointer,
 
369
                            gpointer);
 
370
 
 
371
/***
 
372
 ***  Global Functions Prototypes
 
373
 **/
 
374
 
 
375
static void    plugin_query (void);
 
376
static void    plugin_run   (const gchar      *name,
 
377
                             gint              nparams,
 
378
                             const GimpParam  *param,
 
379
                             gint             *nreturn_vals,
 
380
                             GimpParam       **return_vals);
 
381
 
 
382
static GFlare * gflare_new_with_default (const gchar *new_name);
 
383
static GFlare * gflare_dup              (const GFlare      *src,
 
384
                                         const gchar *new_name);
 
385
static void     gflare_copy             (GFlare      *dest,
 
386
                                         const GFlare      *src);
 
387
static GFlare * gflare_load             (const gchar *filename,
 
388
                                         const gchar *name);
 
389
static void     gflare_save             (GFlare      *gflare);
 
390
static void     gflare_name_copy        (gchar       *dest,
 
391
                                         const gchar *src);
 
392
 
 
393
static gint     gflares_list_insert     (GFlare      *gflare);
 
394
static GFlare * gflares_list_lookup     (const gchar *name);
 
395
static gint     gflares_list_index      (GFlare      *gflare);
 
396
static gint     gflares_list_remove     (GFlare      *gflare);
 
397
static void     gflares_list_load_all   (void);
 
398
static void     gflares_list_free_all   (void);
 
399
 
 
400
static void     calc_init_params   (GFlare  *gflare,
 
401
                                    gint     calc_type,
 
402
                                    gdouble  xcenter,
 
403
                                    gdouble  ycenter,
 
404
                                    gdouble  radius,
 
405
                                    gdouble  rotation,
 
406
                                    gdouble  hue,
 
407
                                    gdouble  vangle,
 
408
                                    gdouble  vlength);
 
409
static gint     calc_init_progress (void);
 
410
static void     calc_deinit        (void);
 
411
static void     calc_glow_pix      (guchar  *dest_pix,
 
412
                                    gdouble  x,
 
413
                                    gdouble  y);
 
414
static void     calc_rays_pix      (guchar  *dest_pix,
 
415
                                    gdouble  x,
 
416
                                    gdouble  y);
 
417
static void     calc_sflare_pix    (guchar  *dest_pix,
 
418
                                    gdouble  x,
 
419
                                    gdouble  y,
 
420
                                    guchar  *src_pix);
 
421
static void     calc_gflare_pix    (guchar  *dest_pix,
 
422
                                    gdouble  x,
 
423
                                    gdouble  y,
 
424
                                    guchar  *src_pix);
 
425
 
 
426
static gboolean    dlg_run                 (void);
 
427
static void        dlg_preview_calc_window (void);
 
428
static void        ed_preview_calc_window  (void);
 
429
static GtkWidget * ed_mode_menu_new        (GFlareMode *mode_var);
 
430
 
 
431
static Preview   * preview_new          (gint               width,
 
432
                                         gint               height,
 
433
                                         PreviewInitFunc    init_func,
 
434
                                         gpointer           init_data,
 
435
                                         PreviewRenderFunc  render_func,
 
436
                                         gpointer           render_data,
 
437
                                         PreviewDeinitFunc  deinit_func,
 
438
                                         gpointer           deinit_data);
 
439
static void        preview_free         (Preview           *preview);
 
440
static void        preview_render_start (Preview           *preview);
 
441
static void        preview_render_end   (Preview           *preview);
 
442
static void        preview_rgba_to_rgb  (guchar            *dest,
 
443
                                         gint               x,
 
444
                                         gint               y,
 
445
                                         guchar            *src);
 
446
 
 
447
static void             gradient_menu_init    (void);
 
448
static void             gradient_menu_rescan  (void);
 
449
static GradientMenu   * gradient_menu_new     (GradientMenuCallback callback,
 
450
                                               gpointer        callback_data,
 
451
                                               const gchar    *default_gradient_name);
 
452
static void             gradient_name_copy    (gchar       *dest,
 
453
                                               const gchar *src);
 
454
static void             gradient_name_encode  (gchar       *dest,
 
455
                                               const gchar *src);
 
456
static void             gradient_name_decode  (gchar       *dest,
 
457
                                               const gchar *src);
 
458
static void             gradient_init         (void);
 
459
static void             gradient_free         (void);
 
460
static gchar         ** gradient_get_list     (gint   *num_gradients);
 
461
static void             gradient_get_values   (const gchar *gradient_name,
 
462
                                               guchar      *values,
 
463
                                               gint         nvalues);
 
464
static void             gradient_cache_flush  (void);
 
465
 
 
466
/* *** INSERT-FILE-END *** */
 
467
 
 
468
/**
 
469
***     Variables
 
470
**/
 
471
 
 
472
const GimpPlugInInfo PLUG_IN_INFO =
 
473
{
 
474
  NULL,         /* init_proc  */
 
475
  NULL,         /* quit_proc  */
 
476
  plugin_query, /* query_proc */
 
477
  plugin_run,   /* run_proc   */
 
478
};
 
479
 
 
480
PluginValues pvals =
 
481
{
 
482
  128,          /* xcenter */
 
483
  128,          /* ycenter */
 
484
  100.0,        /* radius */
 
485
  0.0,          /* rotation */
 
486
  0.0,          /* hue */
 
487
  60.0,         /* vangle */
 
488
  400.0,        /* vlength */
 
489
  FALSE,        /* use_asupsample */
 
490
  3,            /* asupsample_max_depth */
 
491
  0.2,          /* asupsample_threshold */
 
492
  "Default"     /* gflare_name */
 
493
};
 
494
 
 
495
GFlare default_gflare =
 
496
{
 
497
  NULL,         /* name */
 
498
  NULL,         /* filename */
 
499
  100,          /* glow_opacity */
 
500
  GF_NORMAL,    /* glow_mode */
 
501
  100,          /* rays_opacity */
 
502
  GF_NORMAL,    /* rays_mode */
 
503
  100,          /* sflare_opacity */
 
504
  GF_NORMAL,    /* sflare_mode */
 
505
  "%red_grad",  /* glow_radial */
 
506
  "%white",     /* glow_angular */
 
507
  "%white",     /* glow_angular_size */
 
508
  100.0,        /* glow_size */
 
509
  0.0,          /* glow_rotation */
 
510
  0.0,          /* glow_hue */
 
511
  "%white_grad",/* rays_radial */
 
512
  "%random",    /* rays_angular */
 
513
  "%random",    /* rays_angular_size */
 
514
  100.0,        /* rays_size */
 
515
  0.0,          /* rays_rotation */
 
516
  0.0,          /* rays_hue */
 
517
  40,           /* rays_nspikes */
 
518
  20.0,         /* rays_thickness */
 
519
  "%white_grad",/* sflare_radial */
 
520
  "%random",    /* sflare_sizefac */
 
521
  "%random",    /* sflare_probability */
 
522
  40.0,         /* sflare_size */
 
523
  0.0,          /* sflare_rotation */
 
524
  0.0,          /* sflare_hue */
 
525
  GF_CIRCLE,    /* sflare_shape */
 
526
  6,            /* sflare_nverts */
 
527
  0,            /* sflare_seed */
 
528
  TRUE,         /* random_seed */
 
529
};
 
530
 
 
531
/* These are keywords to be written to disk files specifying flares. */
 
532
/* They are not translated since we want gflare files to be compatible
 
533
   across languages. */
 
534
static const gchar *gflare_modes[] =
 
535
{
 
536
  "NORMAL",
 
537
  "ADDITION",
 
538
  "OVERLAY",
 
539
  "SCREEN"
 
540
};
 
541
 
 
542
static const gchar *gflare_shapes[] =
 
543
{
 
544
  "CIRCLE",
 
545
  "POLYGON"
 
546
};
 
547
 
 
548
/* These are for menu entries, so they are translated. */
 
549
static const gchar *gflare_menu_modes[] =
 
550
{
 
551
  N_("Normal"),
 
552
  N_("Addition"),
 
553
  N_("Overlay"),
 
554
  N_("Screen")
 
555
};
 
556
 
 
557
static gint32              image_ID;
 
558
static GimpDrawable       *drawable;
 
559
static DrawableInfo        dinfo;
 
560
static GimpPixelFetcher   *tk_read;
 
561
static GimpPixelFetcher   *tk_write;
 
562
static GFlareDialog       *dlg = NULL;
 
563
static GFlareEditor       *ed = NULL;
 
564
static GList              *gflares_list = NULL;
 
565
static gint                num_gflares  = 0;
 
566
static gchar              *gflare_path  = NULL;
 
567
static CalcParams          calc;
 
568
static GList              *gradient_menus;
 
569
static gchar             **gradient_names = NULL;
 
570
static gint                num_gradient_names = 0;
 
571
static GradientCacheItem  *gradient_cache_head  = NULL;
 
572
static gint                gradient_cache_count = 0;
 
573
 
 
574
 
 
575
static const gchar *internal_gradients[] =
 
576
{
 
577
  "%white", "%white_grad", "%red_grad", "%blue_grad", "%yellow_grad", "%random"
 
578
};
 
579
 
 
580
#ifdef DEBUG
 
581
static gint     get_values_external_count = 0;
 
582
static clock_t  get_values_external_clock = 0;
 
583
#endif
 
584
 
 
585
 
 
586
/**
 
587
***     +++ Static Functions Prototypes
 
588
**/
 
589
 
 
590
static void plugin_do                   (void);
 
591
 
 
592
static void plugin_do_non_asupsample    (void);
 
593
static void plugin_do_asupsample        (void);
 
594
static void plugin_render_func          (gdouble       x,
 
595
                                         gdouble       y,
 
596
                                         GimpRGB      *color,
 
597
                                         gpointer      data);
 
598
static void plugin_put_pixel_func       (gint          ix,
 
599
                                         gint          iy,
 
600
                                         GimpRGB      *color,
 
601
                                         gpointer      data);
 
602
static void plugin_progress_func        (gint          y1,
 
603
                                         gint          y2,
 
604
                                         gint          curr_y,
 
605
                                         gpointer      data);
 
606
 
 
607
static GFlare * gflare_new              (void);
 
608
static void gflare_free                 (GFlare       *gflare);
 
609
static void gflare_read_int             (gint         *intvar,
 
610
                                         GFlareFile   *gf);
 
611
static void gflare_read_double          (gdouble      *dblvar,
 
612
                                         GFlareFile   *gf);
 
613
static void gflare_read_gradient_name   (gchar        *name,
 
614
                                         GFlareFile   *gf);
 
615
static void gflare_read_shape           (GFlareShape  *shape,
 
616
                                         GFlareFile   *gf);
 
617
static void gflare_read_mode            (GFlareMode   *mode,
 
618
                                         GFlareFile   *gf);
 
619
static void gflare_write_gradient_name  (gchar        *name,
 
620
                                         FILE         *fp);
 
621
 
 
622
static gint calc_sample_one_gradient    (void);
 
623
static void calc_place_sflare           (void);
 
624
static void calc_get_gradient           (guchar       *pix,
 
625
                                         guchar       *gradient,
 
626
                                         gdouble       pos);
 
627
static gdouble fmod_positive            (gdouble       x,
 
628
                                         gdouble       m);
 
629
static void calc_paint_func             (guchar       *dest,
 
630
                                         guchar       *src1,
 
631
                                         guchar       *src2,
 
632
                                         gint          opacity,
 
633
                                         GFlareMode    mode);
 
634
static void calc_combine                (guchar       *dest,
 
635
                                         guchar       *src1,
 
636
                                         guchar       *src2,
 
637
                                         gint          opacity);
 
638
static void calc_addition               (guchar       *dest,
 
639
                                         guchar       *src1,
 
640
                                         guchar       *src2);
 
641
static void calc_screen                 (guchar       *dest,
 
642
                                         guchar       *src1,
 
643
                                         guchar       *src2);
 
644
static void calc_overlay                (guchar       *dest,
 
645
                                         guchar       *src1,
 
646
                                         guchar       *src2);
 
647
 
 
648
static void dlg_setup_gflare            (void);
 
649
static void dlg_preview_realize         (GtkWidget    *widget);
 
650
static gboolean dlg_preview_handle_event (GtkWidget    *widget,
 
651
                                          GdkEvent     *event);
 
652
static void dlg_preview_update          (void);
 
653
static gint dlg_preview_init_func       (Preview      *preview,
 
654
                                         gpointer      data);
 
655
static void dlg_preview_render_func     (Preview      *preview,
 
656
                                         guchar       *dest,
 
657
                                         gint          y,
 
658
                                         gpointer      data);
 
659
static void dlg_preview_deinit_func     (Preview      *preview,
 
660
                                         gpointer      data);
 
661
static void dlg_make_page_settings      (GFlareDialog *dlg,
 
662
                                         GtkWidget    *notebook);
 
663
static void dlg_position_entry_callback (GtkWidget    *widget,
 
664
                                         gpointer      data);
 
665
static void dlg_update_preview_callback (GtkWidget    *widget,
 
666
                                         gpointer      data);
 
667
static void dlg_make_page_selector      (GFlareDialog *dlg,
 
668
                                         GtkWidget    *notebook);
 
669
 
 
670
static void dlg_selector_setup_listbox      (void);
 
671
static void dlg_selector_list_item_callback (GtkTreeSelection *selection);
 
672
 
 
673
static void dlg_selector_new_callback       (GtkWidget   *widget,
 
674
                                             gpointer     data);
 
675
static void dlg_selector_new_ok_callback    (GtkWidget   *widget,
 
676
                                             const gchar *new_name,
 
677
                                             gpointer     data);
 
678
 
 
679
static void dlg_selector_edit_callback      (GtkWidget   *widget,
 
680
                                             gpointer     data);
 
681
static void dlg_selector_edit_done_callback (gint         updated,
 
682
                                             gpointer     data);
 
683
 
 
684
static void dlg_selector_copy_callback      (GtkWidget   *widget,
 
685
                                             gpointer    data);
 
686
static void dlg_selector_copy_ok_callback   (GtkWidget   *widget,
 
687
                                             const gchar *copy_name,
 
688
                                             gpointer     data);
 
689
 
 
690
static void dlg_selector_delete_callback    (GtkWidget   *widget,
 
691
                                             gpointer     data);
 
692
static void dlg_selector_do_delete_callback (GtkWidget   *widget,
 
693
                                             gboolean     delete,
 
694
                                             gpointer     data);
 
695
 
 
696
static void ed_run                (GtkWindow            *parent,
 
697
                                   GFlare               *target_gflare,
 
698
                                   GFlareEditorCallback  callback,
 
699
                                   gpointer              calldata);
 
700
static void ed_destroy_callback   (GtkWidget    *widget,
 
701
                                   GFlareEditor *ed);
 
702
static void ed_response           (GtkWidget    *widget,
 
703
                                   gint          response_id,
 
704
                                   GFlareEditor *ed);
 
705
static void ed_make_page_general  (GFlareEditor *ed,
 
706
                                   GtkWidget    *notebook);
 
707
static void ed_make_page_glow     (GFlareEditor *ed,
 
708
                                   GtkWidget    *notebook);
 
709
static void ed_make_page_rays     (GFlareEditor *ed,
 
710
                                   GtkWidget    *notebook);
 
711
static void ed_make_page_sflare   (GFlareEditor *ed,
 
712
                                   GtkWidget    *notebook);
 
713
static void ed_put_gradient_menu  (GtkWidget    *table,
 
714
                                   gint          x,
 
715
                                   gint          y,
 
716
                                   const gchar  *caption,
 
717
                                   GradientMenu *gm);
 
718
static void ed_mode_menu_callback (GtkWidget    *widget,
 
719
                                   gpointer      data);
 
720
static void ed_gradient_menu_callback (const gchar *gradient_name,
 
721
                                       gpointer     data);
 
722
static void ed_shape_radio_callback   (GtkWidget *widget, gpointer data);
 
723
static void ed_ientry_callback        (GtkWidget *widget, gpointer data);
 
724
static void ed_page_map_callback      (GtkWidget *widget, gpointer data);
 
725
static void ed_preview_update         (void);
 
726
static gint ed_preview_init_func      (Preview *preview, gpointer data);
 
727
static void ed_preview_deinit_func    (Preview *preview, gpointer data);
 
728
static void ed_preview_render_func    (Preview *preview,
 
729
                                       guchar *buffer, gint y, gpointer data);
 
730
static void ed_preview_render_general (guchar *buffer, gint y);
 
731
static void ed_preview_render_glow    (guchar *buffer, gint y);
 
732
static void ed_preview_render_rays    (guchar *buffer, gint y);
 
733
static void ed_preview_render_sflare  (guchar *buffer, gint y);
 
734
 
 
735
static gint preview_render_start_2    (Preview *preview);
 
736
static gint preview_handle_idle       (Preview *preview);
 
737
 
 
738
static void gm_gradient_get_list            (void);
 
739
static void gm_gradient_combo_fill          (GradientMenu *gm,
 
740
                                             const gchar  *default_gradient);
 
741
static void gm_gradient_combo_callback      (GtkWidget    *widget,
 
742
                                             gpointer      data);
 
743
static void gm_preview_draw                 (GtkWidget    *preview,
 
744
                                             const gchar  *gradient_name);
 
745
static void gm_combo_destroy_callback       (GtkWidget    *widget,
 
746
                                             gpointer      data);
 
747
 
 
748
static void gradient_get_values_internal    (const gchar *gradient_name,
 
749
                                             guchar *values, gint nvalues);
 
750
static void gradient_get_blend              (const guchar *fg,
 
751
                                             const guchar *bg,
 
752
                                             guchar *values, gint nvalues);
 
753
static void gradient_get_random             (guchar *values, gint nvalues);
 
754
static void gradient_get_default            (const gchar *name,
 
755
                                             guchar *values, gint nvalues);
 
756
static void gradient_get_values_external    (const gchar *gradient_name,
 
757
                                             guchar *values, gint nvalues);
 
758
static void gradient_get_values_real_external   (const gchar *gradient_name,
 
759
                                                 guchar   *values,
 
760
                                                 gint      nvalues,
 
761
                                                 gboolean  reverse);
 
762
static GradientCacheItem *gradient_cache_lookup (const gchar *name,
 
763
                                                 gboolean    *found);
 
764
static void gradient_cache_zorch                (void);
 
765
 
 
766
/* *** INSERT-FILE-END *** */
 
767
 
 
768
 
 
769
/*************************************************************************/
 
770
/**                                                                     **/
 
771
/**             +++ Plug-in Interfaces                                  **/
 
772
/**                                                                     **/
 
773
/*************************************************************************/
 
774
 
 
775
MAIN ()
 
776
 
 
777
void
 
778
plugin_query (void)
 
779
{
 
780
  static const GimpParamDef args[]=
 
781
  {
 
782
    { GIMP_PDB_INT32,    "run-mode", "Interactive, non-interactive" },
 
783
    { GIMP_PDB_IMAGE,    "image",    "Input image (unused)" },
 
784
    { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
 
785
    { GIMP_PDB_STRING,   "gflare-name", "The name of GFlare" },
 
786
    { GIMP_PDB_INT32,    "xcenter",  "X coordinate of center of GFlare" },
 
787
    { GIMP_PDB_INT32,    "ycenter",  "Y coordinate of center of GFlare" },
 
788
    { GIMP_PDB_FLOAT,    "radius",   "Radius of GFlare (pixel)" },
 
789
    { GIMP_PDB_FLOAT,    "rotation", "Rotation of GFlare (degree)" },
 
790
    { GIMP_PDB_FLOAT,    "hue",      "Hue rotation of GFlare (degree)" },
 
791
    { GIMP_PDB_FLOAT,    "vangle",   "Vector angle for second flares (degree)" },
 
792
    { GIMP_PDB_FLOAT,    "vlength",  "Vector length for second flares (percentage to Radius)" },
 
793
    { GIMP_PDB_INT32,    "use-asupsample", "Whether it uses or not adaptive supersampling while rendering (boolean)" },
 
794
    { GIMP_PDB_INT32,    "asupsample-max-depth", "Max depth for adaptive supersampling"},
 
795
    { GIMP_PDB_FLOAT,    "asupsample-threshold", "Threshold for adaptive supersampling"}
 
796
  };
 
797
 
 
798
  const gchar *help_string =
 
799
    "This plug-in produces a lense flare effect using custom gradients. "
 
800
    "In interactive call, the user can edit his/her own favorite lense flare "
 
801
    "(GFlare) and render it. Edited gflare is saved automatically to "
 
802
    "the folder in gflare-path, if it is defined in gimprc. "
 
803
    "In non-interactive call, the user can only render one of GFlare "
 
804
    "which has been stored in gflare-path already.";
 
805
 
 
806
  gimp_install_procedure (PLUG_IN_PROC,
 
807
                          N_("Produce a lense flare effect using gradients"),
 
808
                          help_string,
 
809
                          "Eiichi Takamori",
 
810
                          "Eiichi Takamori, and a lot of GIMP people",
 
811
                          "1997",
 
812
                          N_("_Gradient Flare..."),
 
813
                          "RGB*, GRAY*",
 
814
                          GIMP_PLUGIN,
 
815
                          G_N_ELEMENTS (args), 0,
 
816
                          args, NULL);
 
817
 
 
818
  gimp_plugin_menu_register (PLUG_IN_PROC,
 
819
                             "<Image>/Filters/Light and Shadow/Light");
 
820
}
 
821
 
 
822
void
 
823
plugin_run (const gchar      *name,
 
824
            gint              nparams,
 
825
            const GimpParam  *param,
 
826
            gint             *nreturn_vals,
 
827
            GimpParam       **return_vals)
 
828
{
 
829
  static GimpParam   values[2];
 
830
  GimpRunMode        run_mode;
 
831
  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
 
832
  gchar             *path;
 
833
 
 
834
  /* Initialize */
 
835
  run_mode = param[0].data.d_int32;
 
836
 
 
837
  INIT_I18N ();
 
838
 
 
839
  *nreturn_vals = 1;
 
840
  *return_vals = values;
 
841
 
 
842
  values[0].type = GIMP_PDB_STATUS;
 
843
  values[0].data.d_status = status;
 
844
 
 
845
  /*
 
846
   *    Get the specified drawable and its info (global variable)
 
847
   */
 
848
 
 
849
  image_ID = param[1].data.d_image;
 
850
  drawable = gimp_drawable_get (param[2].data.d_drawable);
 
851
  dinfo.is_color  = gimp_drawable_is_rgb (drawable->drawable_id);
 
852
  dinfo.has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);
 
853
  gimp_drawable_mask_bounds (drawable->drawable_id, &dinfo.x1, &dinfo.y1,
 
854
                             &dinfo.x2, &dinfo.y2);
 
855
  dinfo.tile_width = gimp_tile_width ();
 
856
  dinfo.tile_height = gimp_tile_height ();
 
857
 
 
858
  /*
 
859
   *    Start gradient caching
 
860
   */
 
861
 
 
862
  gradient_init ();
 
863
 
 
864
  /*
 
865
   *    Parse gflare path from gimprc and load gflares
 
866
   */
 
867
 
 
868
  path = gimp_gimprc_query ("gflare-path");
 
869
  if (path)
 
870
    {
 
871
      gflare_path = g_filename_from_utf8 (path, -1, NULL, NULL, NULL);
 
872
      g_free (path);
 
873
    }
 
874
  else
 
875
    {
 
876
      gchar *gimprc    = gimp_personal_rc_file ("gimprc");
 
877
      gchar *full_path = gimp_config_build_data_path ("gflare");
 
878
      gchar *esc_path  = g_strescape (full_path, NULL);
 
879
      g_free (full_path);
 
880
 
 
881
      g_message (_("No %s in gimprc:\n"
 
882
                   "You need to add an entry like\n"
 
883
                   "(%s \"%s\")\n"
 
884
                   "to your %s file."),
 
885
                 "gflare-path", "gflare-path",
 
886
                 esc_path, gimp_filename_to_utf8 (gimprc));
 
887
 
 
888
      g_free (gimprc);
 
889
      g_free (esc_path);
 
890
    }
 
891
 
 
892
  gflares_list_load_all ();
 
893
 
 
894
  gimp_tile_cache_ntiles (drawable->width / gimp_tile_width () + 2);
 
895
 
 
896
 
 
897
  switch (run_mode)
 
898
    {
 
899
    case GIMP_RUN_INTERACTIVE:
 
900
 
 
901
      /*  Possibly retrieve data  */
 
902
      gimp_get_data (PLUG_IN_PROC, &pvals);
 
903
 
 
904
      /*  First acquire information with a dialog  */
 
905
      if (! dlg_run ())
 
906
        {
 
907
          gimp_drawable_detach (drawable);
 
908
          return;
 
909
        }
 
910
      break;
 
911
 
 
912
    case GIMP_RUN_NONINTERACTIVE:
 
913
      if (nparams != 14)
 
914
        {
 
915
          status = GIMP_PDB_CALLING_ERROR;
 
916
        }
 
917
      else
 
918
        {
 
919
          gflare_name_copy (pvals.gflare_name, param[3].data.d_string);
 
920
          pvals.xcenter              = param[4].data.d_int32;
 
921
          pvals.ycenter              = param[5].data.d_int32;
 
922
          pvals.radius               = param[6].data.d_float;
 
923
          pvals.rotation             = param[7].data.d_float;
 
924
          pvals.hue                  = param[8].data.d_float;
 
925
          pvals.vangle               = param[9].data.d_float;
 
926
          pvals.vlength              = param[10].data.d_float;
 
927
          pvals.use_asupsample       = param[11].data.d_int32;
 
928
          pvals.asupsample_max_depth = param[12].data.d_int32;
 
929
          pvals.asupsample_threshold = param[13].data.d_float;
 
930
 
 
931
          if (pvals.radius <= 0)
 
932
            status = GIMP_PDB_CALLING_ERROR;
 
933
        }
 
934
      break;
 
935
 
 
936
    case GIMP_RUN_WITH_LAST_VALS:
 
937
      /*  Possibly retrieve data  */
 
938
      gimp_get_data (PLUG_IN_PROC, &pvals);
 
939
      break;
 
940
 
 
941
    default:
 
942
      break;
 
943
    }
 
944
 
 
945
  if (status == GIMP_PDB_SUCCESS)
 
946
    {
 
947
      /*  Make sure that the drawable is gray or RGB color  */
 
948
      if (gimp_drawable_is_rgb (drawable->drawable_id) ||
 
949
          gimp_drawable_is_gray (drawable->drawable_id))
 
950
        {
 
951
          gimp_progress_init (_("Gradient Flare"));
 
952
          plugin_do ();
 
953
 
 
954
          if (run_mode != GIMP_RUN_NONINTERACTIVE)
 
955
            gimp_displays_flush ();
 
956
 
 
957
          /*  Store data  */
 
958
          if (run_mode == GIMP_RUN_INTERACTIVE)
 
959
            gimp_set_data (PLUG_IN_PROC, &pvals, sizeof (PluginValues));
 
960
        }
 
961
      else
 
962
        {
 
963
          status        = GIMP_PDB_EXECUTION_ERROR;
 
964
          *nreturn_vals = 2;
 
965
          values[1].type          = GIMP_PDB_STRING;
 
966
          values[1].data.d_string = _("Cannot operate on indexed color images.");
 
967
        }
 
968
    }
 
969
 
 
970
  values[0].data.d_status = status;
 
971
 
 
972
  /*
 
973
   *    Deinitialization
 
974
   */
 
975
  gradient_free ();
 
976
  gimp_drawable_detach (drawable);
 
977
}
 
978
 
 
979
static void
 
980
plugin_do (void)
 
981
{
 
982
  GFlare *gflare;
 
983
 
 
984
  gflare = gflares_list_lookup (pvals.gflare_name);
 
985
  if (gflare == NULL)
 
986
    {
 
987
      /* FIXME */
 
988
      g_warning ("Not found %s\n", pvals.gflare_name);
 
989
      return;
 
990
    }
 
991
 
 
992
  /* Initialize calc params and gradients */
 
993
  calc_init_params (gflare, CALC_GLOW | CALC_RAYS | CALC_SFLARE,
 
994
                    pvals.xcenter, pvals.ycenter,
 
995
                    pvals.radius, pvals.rotation, pvals.hue,
 
996
                    pvals.vangle, pvals.vlength);
 
997
  while (calc_init_progress ()) ;
 
998
 
 
999
  /* Render it ! */
 
1000
  if (pvals.use_asupsample)
 
1001
    plugin_do_asupsample ();
 
1002
  else
 
1003
    plugin_do_non_asupsample ();
 
1004
 
 
1005
  /* Clean up */
 
1006
  calc_deinit ();
 
1007
  gimp_drawable_flush (drawable);
 
1008
  gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
 
1009
  gimp_drawable_update (drawable->drawable_id, dinfo.x1, dinfo.y1,
 
1010
                        (dinfo.x2 - dinfo.x1), (dinfo.y2 - dinfo.y1));
 
1011
}
 
1012
 
 
1013
/* these routines should be almost rewritten anyway */
 
1014
 
 
1015
static void
 
1016
plugin_do_non_asupsample (void)
 
1017
{
 
1018
  GimpPixelRgn  src_rgn, dest_rgn;
 
1019
  gpointer      pr;
 
1020
  gint          width, height;
 
1021
  gint          progress, max_progress;
 
1022
 
 
1023
  width  = dinfo.x2 - dinfo.x1;
 
1024
  height = dinfo.y2 - dinfo.y1;
 
1025
 
 
1026
  progress = 0;
 
1027
  max_progress = width * height;
 
1028
 
 
1029
  gimp_pixel_rgn_init (&src_rgn, drawable,
 
1030
                       dinfo.x1, dinfo.y1, width, height, FALSE, FALSE);
 
1031
  gimp_pixel_rgn_init (&dest_rgn, drawable,
 
1032
                       dinfo.x1, dinfo.y1, width, height, TRUE, TRUE);
 
1033
 
 
1034
  for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn);
 
1035
       pr != NULL; pr = gimp_pixel_rgns_process (pr))
 
1036
    {
 
1037
      const guchar *src_row  = src_rgn.data;
 
1038
      guchar       *dest_row = dest_rgn.data;
 
1039
      gint          row, y;
 
1040
 
 
1041
      for (row = 0, y = src_rgn.y; row < src_rgn.h; row++, y++)
 
1042
        {
 
1043
          const guchar *src  = src_row;
 
1044
          guchar       *dest = dest_row;
 
1045
          gint          col, x;
 
1046
 
 
1047
          for (col = 0, x = src_rgn.x; col < src_rgn.w; col++, x++)
 
1048
            {
 
1049
              guchar  src_pix[4];
 
1050
              guchar  dest_pix[4];
 
1051
              gint    b;
 
1052
 
 
1053
              for (b = 0; b < 3; b++)
 
1054
                src_pix[b] = dinfo.is_color ? src[b] : src[0];
 
1055
 
 
1056
              src_pix[3] = dinfo.has_alpha ? src[src_rgn.bpp - 1] : OPAQUE;
 
1057
 
 
1058
              calc_gflare_pix (dest_pix, x, y, src_pix);
 
1059
 
 
1060
              if (dinfo.is_color)
 
1061
                {
 
1062
                  for (b = 0; b < 3; b++)
 
1063
                    dest[b] = dest_pix[b];
 
1064
                }
 
1065
              else
 
1066
                {
 
1067
                  dest[0] = LUMINOSITY (dest_pix);
 
1068
                }
 
1069
 
 
1070
              if (dinfo.has_alpha)
 
1071
                dest[src_rgn.bpp - 1] = dest_pix[3];
 
1072
 
 
1073
              src  += src_rgn.bpp;
 
1074
              dest += dest_rgn.bpp;
 
1075
            }
 
1076
 
 
1077
          src_row  += src_rgn.rowstride;
 
1078
          dest_row += dest_rgn.rowstride;
 
1079
        }
 
1080
 
 
1081
      /* Update progress */
 
1082
      progress += src_rgn.w * src_rgn.h;
 
1083
      gimp_progress_update ((double) progress / (double) max_progress);
 
1084
    }
 
1085
}
 
1086
 
 
1087
static void
 
1088
plugin_do_asupsample (void)
 
1089
{
 
1090
  tk_read  = gimp_pixel_fetcher_new (drawable, FALSE);
 
1091
  gimp_pixel_fetcher_set_edge_mode (tk_read, GIMP_PIXEL_FETCHER_EDGE_BLACK);
 
1092
 
 
1093
  tk_write = gimp_pixel_fetcher_new (drawable, TRUE);
 
1094
 
 
1095
  gimp_adaptive_supersample_area (dinfo.x1, dinfo.y1,
 
1096
                                  dinfo.x2 - 1, dinfo.y2 - 1,
 
1097
                                  pvals.asupsample_max_depth,
 
1098
                                  pvals.asupsample_threshold,
 
1099
                                  plugin_render_func,
 
1100
                                  NULL,
 
1101
                                  plugin_put_pixel_func,
 
1102
                                  NULL,
 
1103
                                  plugin_progress_func,
 
1104
                                  NULL);
 
1105
 
 
1106
  gimp_pixel_fetcher_destroy (tk_write);
 
1107
  gimp_pixel_fetcher_destroy (tk_read);
 
1108
}
 
1109
 
 
1110
/*
 
1111
  Adaptive supersampling callback functions
 
1112
 
 
1113
  These routines may look messy, since adaptive supersampling needs
 
1114
  pixel values in `double' (from 0.0 to 1.0) but calc_*_pix () returns
 
1115
  guchar values. */
 
1116
 
 
1117
static void
 
1118
plugin_render_func (gdouble   x,
 
1119
                    gdouble   y,
 
1120
                    GimpRGB  *color,
 
1121
                    gpointer  data)
 
1122
{
 
1123
  guchar        src_pix[4];
 
1124
  guchar        flare_pix[4];
 
1125
  guchar        src[4];
 
1126
  gint          b;
 
1127
  gint          ix, iy;
 
1128
 
 
1129
  /* translate (0.5, 0.5) before convert to `int' so that it can surely
 
1130
     point the center of pixel */
 
1131
  ix = floor (x + 0.5);
 
1132
  iy = floor (y + 0.5);
 
1133
 
 
1134
  gimp_pixel_fetcher_get_pixel (tk_read, ix, iy, src);
 
1135
 
 
1136
  for (b = 0; b < 3; b++)
 
1137
    src_pix[b] = dinfo.is_color ? src[b] : src[0];
 
1138
  src_pix[3] = dinfo.has_alpha ? src[drawable->bpp - 1] : OPAQUE;
 
1139
 
 
1140
  calc_gflare_pix (flare_pix, x, y, src_pix);
 
1141
 
 
1142
  color->r = flare_pix[0] / 255.0;
 
1143
  color->g = flare_pix[1] / 255.0;
 
1144
  color->b = flare_pix[2] / 255.0;
 
1145
  color->a = flare_pix[3] / 255.0;
 
1146
}
 
1147
 
 
1148
static void
 
1149
plugin_put_pixel_func (gint      ix,
 
1150
                       gint      iy,
 
1151
                       GimpRGB  *color,
 
1152
                       gpointer  data)
 
1153
{
 
1154
  guchar dest[4];
 
1155
 
 
1156
  if (dinfo.is_color)
 
1157
    {
 
1158
      dest[0] = color->r * 255;
 
1159
      dest[1] = color->g * 255;
 
1160
      dest[2] = color->b * 255;
 
1161
    }
 
1162
  else
 
1163
    {
 
1164
      dest[0] = gimp_rgb_luminance_uchar (color);
 
1165
    }
 
1166
 
 
1167
  if (dinfo.has_alpha)
 
1168
    dest[drawable->bpp - 1] = color->a * 255;
 
1169
 
 
1170
  gimp_pixel_fetcher_put_pixel (tk_write, ix, iy, dest);
 
1171
}
 
1172
 
 
1173
static void
 
1174
plugin_progress_func (gint     y1,
 
1175
                      gint     y2,
 
1176
                      gint     curr_y,
 
1177
                      gpointer data)
 
1178
{
 
1179
  gimp_progress_update ((double) curr_y / (double) (y2 - y1));
 
1180
}
 
1181
 
 
1182
/*************************************************************************/
 
1183
/**                                                                     **/
 
1184
/**             +++ GFlare Routines                                     **/
 
1185
/**                                                                     **/
 
1186
/*************************************************************************/
 
1187
 
 
1188
/*
 
1189
 *      These code are more or less based on Quartic's gradient.c,
 
1190
 *      other gimp sources, and script-fu.
 
1191
 */
 
1192
 
 
1193
static GFlare *
 
1194
gflare_new (void)
 
1195
{
 
1196
  GFlare *gflare = g_new0 (GFlare, 1);
 
1197
 
 
1198
  gflare->name     = NULL;
 
1199
  gflare->filename = NULL;
 
1200
 
 
1201
  return gflare;
 
1202
}
 
1203
 
 
1204
static GFlare *
 
1205
gflare_new_with_default (const gchar *new_name)
 
1206
{
 
1207
  return gflare_dup (&default_gflare, new_name);
 
1208
}
 
1209
 
 
1210
static GFlare *
 
1211
gflare_dup (const GFlare *src,
 
1212
            const gchar  *new_name)
 
1213
{
 
1214
  GFlare *dest = g_new0 (GFlare, 1);
 
1215
 
 
1216
  *dest = *src;
 
1217
 
 
1218
  dest->name = g_strdup (new_name);
 
1219
  dest->filename = NULL;
 
1220
 
 
1221
  return dest;
 
1222
}
 
1223
 
 
1224
static void
 
1225
gflare_copy (GFlare       *dest,
 
1226
             const GFlare *src)
 
1227
{
 
1228
  gchar *name, *filename;
 
1229
 
 
1230
  name = dest->name;
 
1231
  filename = dest->filename;
 
1232
 
 
1233
  *dest = *src;
 
1234
 
 
1235
  dest->name = name;
 
1236
  dest->filename =filename;
 
1237
}
 
1238
 
 
1239
 
 
1240
static void
 
1241
gflare_free (GFlare *gflare)
 
1242
{
 
1243
  g_return_if_fail (gflare != NULL);
 
1244
 
 
1245
  g_free (gflare->name);
 
1246
  g_free (gflare->filename);
 
1247
  g_free (gflare);
 
1248
}
 
1249
 
 
1250
GFlare *
 
1251
gflare_load (const gchar *filename,
 
1252
             const gchar *name)
 
1253
{
 
1254
  FILE          *fp;
 
1255
  GFlareFile    *gf;
 
1256
  GFlare        *gflare;
 
1257
  gchar         header[256];
 
1258
 
 
1259
  g_return_val_if_fail (filename != NULL, NULL);
 
1260
 
 
1261
  fp = g_fopen (filename, "rb");
 
1262
  if (!fp)
 
1263
    {
 
1264
      g_message (_("Failed to open GFlare file '%s': %s"),
 
1265
                  gimp_filename_to_utf8 (filename), g_strerror (errno));
 
1266
      return NULL;
 
1267
    }
 
1268
 
 
1269
  if (fgets (header, sizeof(header), fp) == NULL
 
1270
      || strcmp (header, GFLARE_FILE_HEADER) != 0)
 
1271
    {
 
1272
      g_warning (_("'%s' is not a valid GFlare file."),
 
1273
                  gimp_filename_to_utf8 (filename));
 
1274
      fclose (fp);
 
1275
      return NULL;
 
1276
    }
 
1277
 
 
1278
  gf = g_new (GFlareFile, 1);
 
1279
  gf->fp = fp;
 
1280
  gf->error = FALSE;
 
1281
 
 
1282
  gflare = gflare_new ();
 
1283
  gflare->name = g_strdup (name);
 
1284
  gflare->filename = g_strdup (filename);
 
1285
 
 
1286
  gflare_read_double   (&gflare->glow_opacity, gf);
 
1287
  gflare_read_mode     (&gflare->glow_mode, gf);
 
1288
  gflare_read_double   (&gflare->rays_opacity, gf);
 
1289
  gflare_read_mode     (&gflare->rays_mode, gf);
 
1290
  gflare_read_double   (&gflare->sflare_opacity, gf);
 
1291
  gflare_read_mode     (&gflare->sflare_mode, gf);
 
1292
 
 
1293
  gflare_read_gradient_name (gflare->glow_radial, gf);
 
1294
  gflare_read_gradient_name (gflare->glow_angular, gf);
 
1295
  gflare_read_gradient_name (gflare->glow_angular_size, gf);
 
1296
  gflare_read_double   (&gflare->glow_size, gf);
 
1297
  gflare_read_double   (&gflare->glow_rotation, gf);
 
1298
  gflare_read_double   (&gflare->glow_hue, gf);
 
1299
 
 
1300
  gflare_read_gradient_name (gflare->rays_radial, gf);
 
1301
  gflare_read_gradient_name (gflare->rays_angular, gf);
 
1302
  gflare_read_gradient_name (gflare->rays_angular_size, gf);
 
1303
  gflare_read_double   (&gflare->rays_size, gf);
 
1304
  gflare_read_double   (&gflare->rays_rotation, gf);
 
1305
  gflare_read_double   (&gflare->rays_hue, gf);
 
1306
  gflare_read_int      (&gflare->rays_nspikes, gf);
 
1307
  gflare_read_double   (&gflare->rays_thickness, gf);
 
1308
 
 
1309
  gflare_read_gradient_name (gflare->sflare_radial, gf);
 
1310
  gflare_read_gradient_name (gflare->sflare_sizefac, gf);
 
1311
  gflare_read_gradient_name (gflare->sflare_probability, gf);
 
1312
  gflare_read_double   (&gflare->sflare_size, gf);
 
1313
  gflare_read_double   (&gflare->sflare_hue, gf);
 
1314
  gflare_read_double   (&gflare->sflare_rotation, gf);
 
1315
  gflare_read_shape    (&gflare->sflare_shape, gf);
 
1316
  gflare_read_int      (&gflare->sflare_nverts, gf);
 
1317
  gflare_read_int      ((gint *) &gflare->sflare_seed, gf);
 
1318
 
 
1319
  if (gflare->sflare_seed == 0)
 
1320
    gflare->sflare_seed = g_random_int();
 
1321
 
 
1322
  fclose (gf->fp);
 
1323
 
 
1324
  if (gf->error)
 
1325
    {
 
1326
      g_warning (_("invalid formatted GFlare file: %s\n"), filename);
 
1327
      g_free (gflare);
 
1328
      g_free (gf);
 
1329
      return NULL;
 
1330
    }
 
1331
 
 
1332
  g_free (gf);
 
1333
 
 
1334
  return gflare;
 
1335
}
 
1336
 
 
1337
static void
 
1338
gflare_read_int (gint       *intvar,
 
1339
                 GFlareFile *gf)
 
1340
{
 
1341
  if (gf->error)
 
1342
    return;
 
1343
 
 
1344
  if (fscanf (gf->fp, "%d", intvar) != 1)
 
1345
    gf->error = TRUE;
 
1346
}
 
1347
 
 
1348
static void
 
1349
gflare_read_double (gdouble    *dblvar,
 
1350
                    GFlareFile *gf)
 
1351
{
 
1352
  gchar buf[31];
 
1353
 
 
1354
  if (gf->error)
 
1355
    return;
 
1356
 
 
1357
  if (fscanf (gf->fp, "%30s", buf) == 1)
 
1358
    *dblvar = g_ascii_strtod (buf, NULL);
 
1359
  else
 
1360
    gf->error = TRUE;
 
1361
}
 
1362
 
 
1363
static void
 
1364
gflare_read_gradient_name (GradientName  name,
 
1365
                           GFlareFile   *gf)
 
1366
{
 
1367
  gchar tmp[1024], dec[1024];
 
1368
 
 
1369
  if (gf->error)
 
1370
    return;
 
1371
 
 
1372
  /* FIXME: this is buggy */
 
1373
 
 
1374
  if (fscanf (gf->fp, "%1023s", tmp) == 1)
 
1375
    {
 
1376
      /* @GRADIENT_NAME */
 
1377
      gradient_name_decode (dec, tmp);
 
1378
      gradient_name_copy (name, dec);
 
1379
    }
 
1380
  else
 
1381
    gf->error = TRUE;
 
1382
}
 
1383
 
 
1384
static void
 
1385
gflare_read_shape (GFlareShape *shape,
 
1386
                   GFlareFile  *gf)
 
1387
{
 
1388
  gchar tmp[1024];
 
1389
  gint  i;
 
1390
 
 
1391
  if (gf->error)
 
1392
    return;
 
1393
 
 
1394
  if (fscanf (gf->fp, "%1023s", tmp) == 1)
 
1395
    {
 
1396
      for (i = 0; i < GF_NUM_SHAPES; i++)
 
1397
        if (strcmp (tmp, gflare_shapes[i]) == 0)
 
1398
          {
 
1399
            *shape = i;
 
1400
            return;
 
1401
          }
 
1402
    }
 
1403
  gf->error = TRUE;
 
1404
}
 
1405
 
 
1406
static void
 
1407
gflare_read_mode (GFlareMode *mode,
 
1408
                  GFlareFile *gf)
 
1409
{
 
1410
  gchar tmp[1024];
 
1411
  gint  i;
 
1412
 
 
1413
  if (gf->error)
 
1414
    return;
 
1415
 
 
1416
  if (fscanf (gf->fp, "%1023s", tmp) == 1)
 
1417
    {
 
1418
      for (i = 0; i < GF_NUM_MODES; i++)
 
1419
        if (strcmp (tmp, gflare_modes[i]) == 0)
 
1420
          {
 
1421
            *mode = i;
 
1422
            return;
 
1423
          }
 
1424
    }
 
1425
  gf->error = TRUE;
 
1426
}
 
1427
 
 
1428
static void
 
1429
gflare_save (GFlare *gflare)
 
1430
{
 
1431
  FILE  *fp;
 
1432
  gchar *path;
 
1433
  gchar  buf[3][G_ASCII_DTOSTR_BUF_SIZE];
 
1434
  static gboolean message_ok = FALSE;
 
1435
 
 
1436
  if (gflare->filename == NULL)
 
1437
    {
 
1438
      GList *list;
 
1439
 
 
1440
      if (gflare_path == NULL)
 
1441
        {
 
1442
          if (! message_ok)
 
1443
            {
 
1444
              gchar *gimprc      = gimp_personal_rc_file ("gimprc");
 
1445
              gchar *dir         = gimp_personal_rc_file ("gflare");
 
1446
              gchar *gflare_dir;
 
1447
 
 
1448
              gflare_dir =
 
1449
                g_strescape ("${gimp_dir}" G_DIR_SEPARATOR_S "gflare", NULL);
 
1450
 
 
1451
              g_message (_("GFlare '%s' is not saved. If you add a new entry "
 
1452
                           "in '%s', like:\n"
 
1453
                           "(gflare-path \"%s\")\n"
 
1454
                           "and make a folder '%s', then you can save "
 
1455
                           "your own GFlares into that folder."),
 
1456
                         gflare->name, gimprc, gflare_dir,
 
1457
                         gimp_filename_to_utf8 (dir));
 
1458
 
 
1459
              g_free (gimprc);
 
1460
              g_free (gflare_dir);
 
1461
              g_free (dir);
 
1462
 
 
1463
              message_ok = TRUE;
 
1464
            }
 
1465
 
 
1466
          return;
 
1467
        }
 
1468
 
 
1469
      list = gimp_path_parse (gflare_path, 16, FALSE, NULL);
 
1470
      path = gimp_path_get_user_writable_dir (list);
 
1471
      gimp_path_free (list);
 
1472
 
 
1473
      if (! path)
 
1474
        path = g_strdup (gimp_directory ());
 
1475
 
 
1476
      gflare->filename = g_build_filename (path, gflare->name, NULL);
 
1477
 
 
1478
      g_free (path);
 
1479
    }
 
1480
 
 
1481
  fp = g_fopen (gflare->filename, "wb");
 
1482
  if (!fp)
 
1483
    {
 
1484
      g_message (_("Failed to write GFlare file '%s': %s"),
 
1485
                  gimp_filename_to_utf8 (gflare->filename), g_strerror (errno));
 
1486
      return;
 
1487
    }
 
1488
 
 
1489
  fprintf (fp, "%s", GFLARE_FILE_HEADER);
 
1490
  g_ascii_formatd (buf[0],
 
1491
                   G_ASCII_DTOSTR_BUF_SIZE, "%f", gflare->glow_opacity);
 
1492
  fprintf (fp, "%s %s\n", buf[0], gflare_modes[gflare->glow_mode]);
 
1493
  g_ascii_formatd (buf[0],
 
1494
                   G_ASCII_DTOSTR_BUF_SIZE, "%f", gflare->rays_opacity);
 
1495
  fprintf (fp, "%s %s\n", buf[0], gflare_modes[gflare->rays_mode]);
 
1496
  g_ascii_formatd (buf[0],
 
1497
                   G_ASCII_DTOSTR_BUF_SIZE, "%f", gflare->sflare_opacity);
 
1498
  fprintf (fp, "%s %s\n", buf[0], gflare_modes[gflare->sflare_mode]);
 
1499
 
 
1500
  gflare_write_gradient_name (gflare->glow_radial, fp);
 
1501
  gflare_write_gradient_name (gflare->glow_angular, fp);
 
1502
  gflare_write_gradient_name (gflare->glow_angular_size, fp);
 
1503
  g_ascii_formatd (buf[0],
 
1504
                   G_ASCII_DTOSTR_BUF_SIZE, "%f", gflare->glow_size);
 
1505
  g_ascii_formatd (buf[1],
 
1506
                   G_ASCII_DTOSTR_BUF_SIZE, "%f", gflare->glow_rotation);
 
1507
  g_ascii_formatd (buf[2],
 
1508
                   G_ASCII_DTOSTR_BUF_SIZE, "%f", gflare->glow_hue);
 
1509
  fprintf (fp, "%s %s %s\n", buf[0], buf[1], buf[2]);
 
1510
 
 
1511
  gflare_write_gradient_name (gflare->rays_radial, fp);
 
1512
  gflare_write_gradient_name (gflare->rays_angular, fp);
 
1513
  gflare_write_gradient_name (gflare->rays_angular_size, fp);
 
1514
  g_ascii_formatd (buf[0],
 
1515
                   G_ASCII_DTOSTR_BUF_SIZE, "%f", gflare->rays_size);
 
1516
  g_ascii_formatd (buf[1],
 
1517
                   G_ASCII_DTOSTR_BUF_SIZE, "%f", gflare->rays_rotation);
 
1518
  g_ascii_formatd (buf[2],
 
1519
                   G_ASCII_DTOSTR_BUF_SIZE, "%f", gflare->rays_hue);
 
1520
  fprintf (fp, "%s %s %s\n", buf[0], buf[1], buf[2]);
 
1521
  g_ascii_formatd (buf[0],
 
1522
                   G_ASCII_DTOSTR_BUF_SIZE, "%f", gflare->rays_thickness);
 
1523
  fprintf (fp, "%d %s\n", gflare->rays_nspikes, buf[0]);
 
1524
 
 
1525
  gflare_write_gradient_name (gflare->sflare_radial, fp);
 
1526
  gflare_write_gradient_name (gflare->sflare_sizefac, fp);
 
1527
  gflare_write_gradient_name (gflare->sflare_probability, fp);
 
1528
  g_ascii_formatd (buf[0],
 
1529
                   G_ASCII_DTOSTR_BUF_SIZE, "%f", gflare->sflare_size);
 
1530
  g_ascii_formatd (buf[1],
 
1531
                   G_ASCII_DTOSTR_BUF_SIZE, "%f", gflare->sflare_rotation);
 
1532
  g_ascii_formatd (buf[2],
 
1533
                   G_ASCII_DTOSTR_BUF_SIZE, "%f", gflare->sflare_hue);
 
1534
  fprintf (fp, "%s %s %s\n", buf[0], buf[1], buf[2]);
 
1535
  fprintf (fp, "%s %d %d\n",
 
1536
           gflare_shapes[gflare->sflare_shape],
 
1537
           gflare->sflare_nverts, gflare->sflare_seed);
 
1538
 
 
1539
  fclose (fp);
 
1540
}
 
1541
 
 
1542
static void
 
1543
gflare_write_gradient_name (GradientName  name,
 
1544
                            FILE         *fp)
 
1545
{
 
1546
  gchar enc[1024];
 
1547
 
 
1548
  /* @GRADIENT_NAME */
 
1549
 
 
1550
  /* encode white spaces and control characters (if any) */
 
1551
  gradient_name_encode (enc, name);
 
1552
 
 
1553
  fprintf (fp, "%s\n", enc);
 
1554
}
 
1555
 
 
1556
static void
 
1557
gflare_name_copy (gchar       *dest,
 
1558
                  const gchar *src)
 
1559
{
 
1560
  strncpy (dest, src, GFLARE_NAME_MAX);
 
1561
  dest[GFLARE_NAME_MAX-1] = '\0';
 
1562
}
 
1563
 
 
1564
/*************************************************************************/
 
1565
/**                                                                     **/
 
1566
/**             +++ GFlares List                                        **/
 
1567
/**                                                                     **/
 
1568
/*************************************************************************/
 
1569
 
 
1570
static gint
 
1571
gflare_compare (const GFlare *flare1,
 
1572
                const GFlare *flare2)
 
1573
{
 
1574
  return strcmp (flare1->name, flare2->name);
 
1575
}
 
1576
 
 
1577
static gint
 
1578
gflares_list_insert (GFlare *gflare)
 
1579
{
 
1580
  num_gflares++;
 
1581
  gflares_list = g_list_insert_sorted (gflares_list, gflare,
 
1582
                                       (GCompareFunc) gflare_compare);
 
1583
  return gflares_list_index (gflare);
 
1584
}
 
1585
 
 
1586
static gint
 
1587
gflare_compare_name (const GFlare *flare,
 
1588
                     const gchar  *name)
 
1589
{
 
1590
  return strcmp (flare->name, name);
 
1591
}
 
1592
 
 
1593
static GFlare *
 
1594
gflares_list_lookup (const gchar *name)
 
1595
{
 
1596
  GList *llink;
 
1597
  llink = g_list_find_custom (gflares_list, name,
 
1598
                              (GCompareFunc) gflare_compare_name);
 
1599
  return (llink) ? llink->data : NULL;
 
1600
}
 
1601
 
 
1602
static gint
 
1603
gflares_list_index (GFlare *gflare)
 
1604
{
 
1605
  return g_list_index (gflares_list, gflare);
 
1606
}
 
1607
 
 
1608
static gint
 
1609
gflares_list_remove (GFlare *gflare)
 
1610
{
 
1611
  GList         *tmp;
 
1612
  gint          n;
 
1613
 
 
1614
  n = 0;
 
1615
  tmp = gflares_list;
 
1616
  while (tmp)
 
1617
    {
 
1618
      if (tmp->data == gflare)
 
1619
        {
 
1620
          /* Found! */
 
1621
          if (tmp->next == NULL)
 
1622
          num_gflares--;
 
1623
          gflares_list = g_list_remove (gflares_list, gflare);
 
1624
          return n;
 
1625
        }
 
1626
      tmp = tmp->next;
 
1627
      n++;
 
1628
    }
 
1629
  return -1;
 
1630
}
 
1631
 
 
1632
/*
 
1633
 * Load all gflares, which are founded in gflare-path-list, into gflares_list.
 
1634
 */
 
1635
static void
 
1636
gflares_list_load_one (const GimpDatafileData *file_data,
 
1637
                       gpointer                user_data)
 
1638
{
 
1639
  GFlare *gflare;
 
1640
 
 
1641
  gflare = gflare_load (file_data->filename, file_data->basename);
 
1642
 
 
1643
  if (gflare)
 
1644
    gflares_list_insert (gflare);
 
1645
}
 
1646
 
 
1647
static void
 
1648
gflares_list_load_all (void)
 
1649
{
 
1650
  /*  Make sure to clear any existing gflares  */
 
1651
  gflares_list_free_all ();
 
1652
 
 
1653
  gimp_datafiles_read_directories (gflare_path, G_FILE_TEST_EXISTS,
 
1654
                                   gflares_list_load_one,
 
1655
                                   NULL);
 
1656
}
 
1657
 
 
1658
static void
 
1659
gflares_list_free_all (void)
 
1660
{
 
1661
  g_list_foreach (gflares_list, (GFunc) gflare_free, NULL);
 
1662
  g_list_free (gflares_list);
 
1663
  gflares_list = NULL;
 
1664
}
 
1665
 
 
1666
/*************************************************************************/
 
1667
/**                                                                     **/
 
1668
/**             +++ Calculator                                          **/
 
1669
/**                                                                     **/
 
1670
/*************************************************************************/
 
1671
 
 
1672
 
 
1673
/*
 
1674
 * These routines calculates pixel values of particular gflare, at
 
1675
 * specified point.  The client which wants to get benefit from these
 
1676
 * calculation routines must call calc_init_params() first, and
 
1677
 * iterate calling calc_init_progress() until it returns FALSE. and
 
1678
 * must call calc_deinit() when job is done.
 
1679
 */
 
1680
 
 
1681
static void
 
1682
calc_init_params (GFlare  *gflare,
 
1683
                  gint     calc_type,
 
1684
                  gdouble  xcenter,
 
1685
                  gdouble  ycenter,
 
1686
                  gdouble  radius,
 
1687
                  gdouble  rotation,
 
1688
                  gdouble  hue,
 
1689
                  gdouble  vangle,
 
1690
                  gdouble  vlength)
 
1691
{
 
1692
  calc.type            = calc_type;
 
1693
  calc.gflare          = gflare;
 
1694
  calc.xcenter         = xcenter;
 
1695
  calc.ycenter         = ycenter;
 
1696
  calc.radius          = radius;
 
1697
  calc.rotation        = rotation * G_PI / 180.0;
 
1698
  calc.hue             = hue;
 
1699
  calc.vangle          = vangle * G_PI / 180.0;
 
1700
  calc.vlength         = radius * vlength / 100.0;
 
1701
  calc.glow_radius     = radius * gflare->glow_size / 100.0;
 
1702
  calc.rays_radius     = radius * gflare->rays_size / 100.0;
 
1703
  calc.sflare_radius   = radius * gflare->sflare_size / 100.0;
 
1704
  calc.glow_rotation   = (rotation + gflare->glow_rotation) * G_PI / 180.0;
 
1705
  calc.rays_rotation   = (rotation + gflare->rays_rotation) * G_PI / 180.0;
 
1706
  calc.sflare_rotation = (rotation + gflare->sflare_rotation) * G_PI / 180.0;
 
1707
  calc.glow_opacity    = gflare->glow_opacity * 255 / 100.0;
 
1708
  calc.rays_opacity    = gflare->rays_opacity * 255 / 100.0;
 
1709
  calc.sflare_opacity  = gflare->sflare_opacity * 255 / 100.0;
 
1710
 
 
1711
  calc.glow_bounds.x0 = calc.xcenter - calc.glow_radius - 0.1;
 
1712
  calc.glow_bounds.x1 = calc.xcenter + calc.glow_radius + 0.1;
 
1713
  calc.glow_bounds.y0 = calc.ycenter - calc.glow_radius - 0.1;
 
1714
  calc.glow_bounds.y1 = calc.ycenter + calc.glow_radius + 0.1;
 
1715
  calc.rays_bounds.x0 = calc.xcenter - calc.rays_radius - 0.1;
 
1716
  calc.rays_bounds.x1 = calc.xcenter + calc.rays_radius + 0.1;
 
1717
  calc.rays_bounds.y0 = calc.ycenter - calc.rays_radius - 0.1;
 
1718
  calc.rays_bounds.y1 = calc.ycenter + calc.rays_radius + 0.1;
 
1719
 
 
1720
  /* Thanks to Marcelo Malheiros for this algorithm */
 
1721
  calc.rays_thinness  = log (gflare->rays_thickness / 100.0) / log(0.8);
 
1722
 
 
1723
  calc.rays_spike_mod = 1.0 / (2 * gflare->rays_nspikes);
 
1724
 
 
1725
  /*
 
1726
    Initialize part of sflare
 
1727
    The rest will be initialized in calc_sflare()
 
1728
   */
 
1729
  calc.sflare_list = NULL;
 
1730
  calc.sflare_shape = gflare->sflare_shape;
 
1731
  if (calc.sflare_shape == GF_POLYGON)
 
1732
    {
 
1733
      calc.sflare_angle = 2 * G_PI / (2 * gflare->sflare_nverts);
 
1734
      calc.sflare_factor = 1.0 / cos (calc.sflare_angle);
 
1735
    }
 
1736
 
 
1737
  calc.glow_radial        = NULL;
 
1738
  calc.glow_angular       = NULL;
 
1739
  calc.glow_angular_size  = NULL;
 
1740
  calc.rays_radial        = NULL;
 
1741
  calc.rays_angular       = NULL;
 
1742
  calc.rays_angular_size  = NULL;
 
1743
  calc.sflare_radial      = NULL;
 
1744
  calc.sflare_sizefac     = NULL;
 
1745
  calc.sflare_probability = NULL;
 
1746
 
 
1747
  calc.init = TRUE;
 
1748
}
 
1749
 
 
1750
static int
 
1751
calc_init_progress (void)
 
1752
{
 
1753
  if (calc_sample_one_gradient ())
 
1754
    return TRUE;
 
1755
  calc_place_sflare ();
 
1756
  return FALSE;
 
1757
}
 
1758
 
 
1759
/*
 
1760
   Store samples of gradient into an array
 
1761
   this routine is called during Calc initialization
 
1762
   this code is very messy... :( */
 
1763
static int
 
1764
calc_sample_one_gradient (void)
 
1765
{
 
1766
  static struct
 
1767
  {
 
1768
    guchar **values;
 
1769
    gint     name_offset;
 
1770
    gint     hue_offset;
 
1771
    gint     gray;
 
1772
  } table[] = {
 
1773
    {
 
1774
      &calc.glow_radial,
 
1775
      G_STRUCT_OFFSET (GFlare, glow_radial),
 
1776
      G_STRUCT_OFFSET (GFlare, glow_hue),
 
1777
      FALSE
 
1778
    },
 
1779
    {
 
1780
      &calc.glow_angular,
 
1781
      G_STRUCT_OFFSET (GFlare, glow_angular),
 
1782
      0,
 
1783
      FALSE
 
1784
    },
 
1785
    {
 
1786
      &calc.glow_angular_size,
 
1787
      G_STRUCT_OFFSET (GFlare, glow_angular_size),
 
1788
      0,
 
1789
      TRUE
 
1790
    },
 
1791
    {
 
1792
      &calc.rays_radial,
 
1793
      G_STRUCT_OFFSET (GFlare, rays_radial),
 
1794
      G_STRUCT_OFFSET (GFlare, rays_hue),
 
1795
      FALSE
 
1796
    },
 
1797
    {
 
1798
      &calc.rays_angular,
 
1799
      G_STRUCT_OFFSET (GFlare, rays_angular),
 
1800
      0,
 
1801
      FALSE
 
1802
    },
 
1803
    {
 
1804
      &calc.rays_angular_size,
 
1805
      G_STRUCT_OFFSET (GFlare, rays_angular_size),
 
1806
      0,
 
1807
      TRUE
 
1808
    },
 
1809
    {
 
1810
      &calc.sflare_radial,
 
1811
      G_STRUCT_OFFSET (GFlare, sflare_radial),
 
1812
      G_STRUCT_OFFSET (GFlare, sflare_hue),
 
1813
      FALSE
 
1814
    },
 
1815
    {
 
1816
      &calc.sflare_sizefac,
 
1817
      G_STRUCT_OFFSET (GFlare, sflare_sizefac),
 
1818
      0,
 
1819
      TRUE
 
1820
    },
 
1821
    {
 
1822
      &calc.sflare_probability,
 
1823
      G_STRUCT_OFFSET (GFlare, sflare_probability),
 
1824
      0,
 
1825
      TRUE
 
1826
    }
 
1827
  };
 
1828
  GFlare        *gflare = calc.gflare;
 
1829
  GradientName  *grad_name;
 
1830
  guchar        *gradient;
 
1831
  gdouble       hue_deg;
 
1832
  gint          i, j, hue;
 
1833
 
 
1834
  for (i = 0; i < G_N_ELEMENTS (table); i++)
 
1835
    {
 
1836
      if (*(table[i].values) == NULL)
 
1837
        {
 
1838
          /* @GRADIENT_NAME */
 
1839
          grad_name = (GradientName *) ((char*) gflare + table[i].name_offset);
 
1840
          gradient = *(table[i].values) = g_new (guchar, 4 * GRADIENT_RESOLUTION);
 
1841
          gradient_get_values (*grad_name, gradient, GRADIENT_RESOLUTION);
 
1842
 
 
1843
          /*
 
1844
           * Do hue rotation, if needed
 
1845
           */
 
1846
 
 
1847
          if (table[i].hue_offset != 0)
 
1848
            {
 
1849
              hue_deg = calc.hue + *(gdouble *) ((char*) gflare + table[i].hue_offset);
 
1850
              hue = (gint) (hue_deg / 360.0 * 256.0) % 256;
 
1851
              if (hue < 0)
 
1852
                hue += 256;
 
1853
              g_assert (0 <= hue && hue < 256);
 
1854
 
 
1855
              if (hue > 0)
 
1856
                {
 
1857
                  for (j = 0; j < GRADIENT_RESOLUTION; j++)
 
1858
                    {
 
1859
                      gint      r, g, b;
 
1860
 
 
1861
                      r = gradient[j*4];
 
1862
                      g = gradient[j*4+1];
 
1863
                      b = gradient[j*4+2];
 
1864
 
 
1865
                      gimp_rgb_to_hsv_int (&r, &g, &b);
 
1866
                      r = (r + hue) % 256;
 
1867
                      gimp_hsv_to_rgb_int (&r, &g, &b);
 
1868
 
 
1869
                      gradient[j*4] = r;
 
1870
                      gradient[j*4+1] = g;
 
1871
                      gradient[j*4+2] = b;
 
1872
                    }
 
1873
                }
 
1874
            }
 
1875
 
 
1876
          /*
 
1877
           *    Grayfy gradient, if needed
 
1878
           */
 
1879
 
 
1880
          if (table[i].gray)
 
1881
            {
 
1882
              for (j = 0; j < GRADIENT_RESOLUTION; j++)
 
1883
                /* the first byte is enough */
 
1884
                gradient[j*4] = LUMINOSITY ((gradient + j*4));
 
1885
 
 
1886
            }
 
1887
 
 
1888
          /* sampling of one gradient is done */
 
1889
          return TRUE;
 
1890
        }
 
1891
    }
 
1892
  return FALSE;
 
1893
}
 
1894
 
 
1895
static void
 
1896
calc_place_sflare (void)
 
1897
{
 
1898
  GFlare        *gflare;
 
1899
  CalcSFlare    *sflare;
 
1900
  gdouble       prob[GRADIENT_RESOLUTION];
 
1901
  gdouble       sum, sum2;
 
1902
  gdouble       pos;
 
1903
  gdouble       rnd, sizefac;
 
1904
  int           n;
 
1905
  int           i;
 
1906
  GRand        *gr;
 
1907
 
 
1908
  gr = g_rand_new ();
 
1909
  if ((calc.type & CALC_SFLARE) == 0)
 
1910
    return;
 
1911
 
 
1912
  gflare = calc.gflare;
 
1913
 
 
1914
  /*
 
1915
    Calc cumulative probability
 
1916
    */
 
1917
 
 
1918
  sum = 0.0;
 
1919
  for (i = 0; i < GRADIENT_RESOLUTION; i++)
 
1920
    {
 
1921
      /* probability gradient was grayfied already */
 
1922
      prob[i] = calc.sflare_probability[i*4];
 
1923
      sum += prob[i];
 
1924
    }
 
1925
 
 
1926
  if (sum == 0.0)
 
1927
    sum = 1.0;
 
1928
 
 
1929
  sum2 = 0;
 
1930
  for (i = 0; i < GRADIENT_RESOLUTION; i++)
 
1931
    {
 
1932
      sum2 += prob[i];          /* cumulation */
 
1933
      prob[i] = sum2 / sum;
 
1934
    }
 
1935
 
 
1936
  g_rand_set_seed (gr, gflare->sflare_seed);
 
1937
 
 
1938
  for (n = 0; n < SFLARE_NUM; n++)
 
1939
    {
 
1940
      sflare = g_new (CalcSFlare, 1);
 
1941
      rnd = g_rand_double (gr);
 
1942
      for (i = 0; i < GRADIENT_RESOLUTION; i++)
 
1943
        if (prob[i] >= rnd)
 
1944
          break;
 
1945
      if (i >= GRADIENT_RESOLUTION)
 
1946
        i = GRADIENT_RESOLUTION - 1;
 
1947
 
 
1948
      /* sizefac gradient was grayfied already */
 
1949
      sizefac = calc.sflare_sizefac[i*4] / 255.0;
 
1950
      sizefac = pow (sizefac, 5.0);
 
1951
 
 
1952
      pos = (double) (i - GRADIENT_RESOLUTION / 2) / GRADIENT_RESOLUTION;
 
1953
      sflare->xcenter = calc.xcenter + cos (calc.vangle) * calc.vlength * pos;
 
1954
      sflare->ycenter = calc.ycenter - sin (calc.vangle) * calc.vlength * pos;
 
1955
      sflare->radius = sizefac * calc.sflare_radius; /* FIXME */
 
1956
      sflare->bounds.x0 = sflare->xcenter - sflare->radius - 1;
 
1957
      sflare->bounds.x1 = sflare->xcenter + sflare->radius + 1;
 
1958
      sflare->bounds.y0 = sflare->ycenter - sflare->radius - 1;
 
1959
      sflare->bounds.y1 = sflare->ycenter + sflare->radius + 1;
 
1960
      calc.sflare_list = g_list_append (calc.sflare_list, sflare);
 
1961
    }
 
1962
 
 
1963
  g_rand_free (gr);
 
1964
}
 
1965
 
 
1966
static void
 
1967
calc_deinit (void)
 
1968
{
 
1969
  if (!calc.init)
 
1970
    {
 
1971
      g_warning("calc_deinit: not initialized");
 
1972
      return;
 
1973
    }
 
1974
 
 
1975
  g_list_foreach (calc.sflare_list, (GFunc) g_free, NULL);
 
1976
  g_list_free (calc.sflare_list);
 
1977
 
 
1978
  g_free (calc.glow_radial);
 
1979
  g_free (calc.glow_angular);
 
1980
  g_free (calc.glow_angular_size);
 
1981
  g_free (calc.rays_radial);
 
1982
  g_free (calc.rays_angular);
 
1983
  g_free (calc.rays_angular_size);
 
1984
  g_free (calc.sflare_radial);
 
1985
  g_free (calc.sflare_sizefac);
 
1986
  g_free (calc.sflare_probability);
 
1987
 
 
1988
  calc.init = FALSE;
 
1989
}
 
1990
 
 
1991
/*
 
1992
 *  Get sample value at specified position of a gradient
 
1993
 *
 
1994
 *  gradient samples are stored into array at the time of
 
1995
 *  calc_sample_one_gradients (), and it is now linear interpolated.
 
1996
 *
 
1997
 *  INPUT:
 
1998
 *      guchar  gradient[4*GRADIENT_RESOLUTION]         gradient array(RGBA)
 
1999
 *      gdouble pos                                     position (0<=pos<=1)
 
2000
 *  OUTPUT:
 
2001
 *      guchar  pix[4]
 
2002
 */
 
2003
static void
 
2004
calc_get_gradient (guchar *pix, guchar *gradient, gdouble pos)
 
2005
{
 
2006
  gint          ipos;
 
2007
  gdouble       frac;
 
2008
  gint          i;
 
2009
 
 
2010
  if (pos < 0 || pos > 1)
 
2011
    {
 
2012
      pix[0] = pix[1] = pix[2] = pix[3] = 0;
 
2013
      return;
 
2014
    }
 
2015
  pos *= GRADIENT_RESOLUTION - 1.0001;
 
2016
  ipos = (gint) pos;    frac = pos - ipos;
 
2017
  gradient += ipos * 4;
 
2018
 
 
2019
  for (i = 0; i < 4; i++)
 
2020
    {
 
2021
      pix[i] = gradient[i] * (1 - frac) + gradient[i+4] * frac;
 
2022
    }
 
2023
}
 
2024
 
 
2025
/* I need fmod to return always positive value */
 
2026
static gdouble
 
2027
fmod_positive (gdouble x, gdouble m)
 
2028
{
 
2029
  return x - floor (x/m) * m;
 
2030
}
 
2031
 
 
2032
/*
 
2033
 *  Calc glow's pixel (RGBA) value
 
2034
 *  INPUT:
 
2035
 *      gdouble x, y                    image coordinates
 
2036
 *  OUTPUT:
 
2037
 *      guchar  pix[4]
 
2038
 */
 
2039
static void
 
2040
calc_glow_pix (guchar *dest_pix, gdouble x, gdouble y)
 
2041
{
 
2042
  gdouble radius, angle;
 
2043
  gdouble angular_size;
 
2044
  guchar  radial_pix[4], angular_pix[4], size_pix[4];
 
2045
  gint    i;
 
2046
 
 
2047
  if ((calc.type & CALC_GLOW) == 0
 
2048
      || x < calc.glow_bounds.x0 || x > calc.glow_bounds.x1
 
2049
      || y < calc.glow_bounds.y0 || y > calc.glow_bounds.y1)
 
2050
    {
 
2051
      memset (dest_pix, 0, 4);
 
2052
      return;
 
2053
    }
 
2054
 
 
2055
  x -= calc.xcenter;
 
2056
  y -= calc.ycenter;
 
2057
  radius = sqrt (x*x + y*y) / calc.glow_radius;
 
2058
  angle = (atan2 (-y, x) + calc.glow_rotation ) / (2 * G_PI);
 
2059
  angle = fmod_positive (angle, 1.0);
 
2060
 
 
2061
  calc_get_gradient (size_pix, calc.glow_angular_size, angle);
 
2062
  /* angular_size gradient was grayfied already */
 
2063
  angular_size = size_pix[0] / 255.0;
 
2064
  radius /= (angular_size+0.0001);      /* in case angular_size == 0.0 */
 
2065
  if (radius < 0 || radius > 1)
 
2066
    {
 
2067
      memset (dest_pix, 0, 4);
 
2068
      return;
 
2069
    }
 
2070
 
 
2071
  calc_get_gradient (radial_pix, calc.glow_radial, radius);
 
2072
  calc_get_gradient (angular_pix, calc.glow_angular, angle);
 
2073
 
 
2074
  for (i = 0; i < 4; i++)
 
2075
    dest_pix[i] = radial_pix[i] * angular_pix[i] / 255;
 
2076
}
 
2077
 
 
2078
/*
 
2079
 *  Calc rays's pixel (RGBA) value
 
2080
 *
 
2081
 */
 
2082
static void
 
2083
calc_rays_pix (guchar *dest_pix, gdouble x, gdouble y)
 
2084
{
 
2085
  gdouble radius, angle;
 
2086
  gdouble angular_size;
 
2087
  gdouble spike_frac, spike_inten, spike_angle;
 
2088
  guchar  radial_pix[4], angular_pix[4], size_pix[4];
 
2089
  gint    i;
 
2090
 
 
2091
  if ((calc.type & CALC_RAYS) == 0
 
2092
      || x < calc.rays_bounds.x0 || x > calc.rays_bounds.x1
 
2093
      || y < calc.rays_bounds.y0 || y > calc.rays_bounds.y1)
 
2094
    {
 
2095
      memset (dest_pix, 0, 4);
 
2096
      return;
 
2097
    }
 
2098
 
 
2099
  x -= calc.xcenter;
 
2100
  y -= calc.ycenter;
 
2101
  radius = sqrt (x*x + y*y) / calc.rays_radius;
 
2102
  angle = (atan2 (-y, x) + calc.rays_rotation ) / (2 * G_PI);
 
2103
  angle = fmod_positive (angle, 1.0);   /* make sure 0 <= angle < 1.0 */
 
2104
  spike_frac = fmod (angle, calc.rays_spike_mod * 2);
 
2105
  spike_angle = angle - spike_frac + calc.rays_spike_mod;
 
2106
  spike_frac = (angle - spike_angle) / calc.rays_spike_mod;
 
2107
  /* spike_frac is between -1.0 and 1.0 here (except round error...) */
 
2108
 
 
2109
  spike_inten = pow (1.0 - fabs (spike_frac), calc.rays_thinness);
 
2110
 
 
2111
  calc_get_gradient (size_pix, calc.rays_angular_size, spike_angle);
 
2112
  /* angular_size gradient was grayfied already */
 
2113
  angular_size = size_pix[0] / 255.0;
 
2114
  radius /= (angular_size+0.0001);      /* in case angular_size == 0.0 */
 
2115
  if(radius < 0 || radius > 1)
 
2116
    {
 
2117
      memset (dest_pix, 0, 4);
 
2118
      return;
 
2119
    }
 
2120
 
 
2121
  calc_get_gradient (radial_pix, calc.rays_radial, radius);
 
2122
  calc_get_gradient (angular_pix, calc.rays_angular, spike_angle);
 
2123
 
 
2124
  for (i = 0; i < 3; i++)
 
2125
    dest_pix[i] =  radial_pix[i] * angular_pix[i] / 255;
 
2126
  dest_pix[3] = spike_inten * radial_pix[3] * angular_pix[3] / 255;
 
2127
}
 
2128
 
 
2129
/*
 
2130
 *  Calc sflare's pixel (RGBA) value
 
2131
 *
 
2132
 *  the sflare (second flares) are needed to be rendered one each
 
2133
 *  sequencially, onto the source image, such as like usual layer
 
2134
 *  operations. So the function takes src_pix as argment.  glow, rays
 
2135
 *  routines don't have src_pix as argment, because of convienience.
 
2136
 *
 
2137
 *  @JAPANESE
 
2138
 *  sflare $B$OJ#?t$N%U%l%"$r=g$K(B($B%l%$%dE*$K(B)$B$+$V$;$J$,$iIA2h$9$kI,MW$,(B
 
2139
 *  $B$"$k$N$G!"$3$l$@$1(B src_pix $B$r0z?t$K$H$C$F(B paint_func $B$rE,MQ$9$k!#(B
 
2140
 *  glow, rays $B$O4J0W2=$N$?$a$K$J$7!#(B
 
2141
 */
 
2142
void
 
2143
calc_sflare_pix (guchar *dest_pix, gdouble x, gdouble y, guchar *src_pix)
 
2144
{
 
2145
  GList         *list;
 
2146
  CalcSFlare    *sflare;
 
2147
  gdouble       sx, sy, th;
 
2148
  gdouble       radius, angle;
 
2149
  guchar        radial_pix[4], tmp_pix[4];
 
2150
 
 
2151
  memcpy (dest_pix, src_pix, 4);
 
2152
 
 
2153
  if ((calc.type & CALC_SFLARE) == 0)
 
2154
    return;
 
2155
 
 
2156
  list = calc.sflare_list;
 
2157
  while (list)
 
2158
    {
 
2159
      sflare = list->data;
 
2160
      list = list->next;
 
2161
 
 
2162
      if (x < sflare->bounds.x0 || x > sflare->bounds.x1
 
2163
          || y < sflare->bounds.y0 || y > sflare->bounds.y1)
 
2164
        continue;
 
2165
      sx = x - sflare->xcenter;
 
2166
      sy = y - sflare->ycenter;
 
2167
      radius = sqrt (sx * sx + sy * sy) / sflare->radius;
 
2168
      if (calc.sflare_shape == GF_POLYGON)
 
2169
        {
 
2170
          angle = atan2 (-sy, sx) - calc.vangle + calc.sflare_rotation;
 
2171
          th = fmod_positive (angle, calc.sflare_angle * 2) - calc.sflare_angle;
 
2172
          radius *= cos (th) * calc.sflare_factor;
 
2173
        }
 
2174
      if (radius < 0 || radius > 1)
 
2175
        continue;
 
2176
 
 
2177
      calc_get_gradient (radial_pix, calc.sflare_radial, radius);
 
2178
      memcpy (tmp_pix, dest_pix, 4);
 
2179
      calc_paint_func (dest_pix, tmp_pix, radial_pix,
 
2180
                       calc.sflare_opacity, calc.gflare->sflare_mode);
 
2181
    }
 
2182
}
 
2183
 
 
2184
static void
 
2185
calc_gflare_pix (guchar *dest_pix, gdouble x, gdouble y, guchar *src_pix)
 
2186
{
 
2187
  GFlare        *gflare = calc.gflare;
 
2188
  guchar        glow_pix[4], rays_pix[4];
 
2189
  guchar        tmp_pix[4];
 
2190
 
 
2191
  memcpy (dest_pix, src_pix, 4);
 
2192
 
 
2193
  if (calc.type & CALC_GLOW)
 
2194
    {
 
2195
      memcpy (tmp_pix, dest_pix, 4);
 
2196
      calc_glow_pix (glow_pix, x, y);
 
2197
      calc_paint_func (dest_pix, tmp_pix, glow_pix,
 
2198
                       calc.glow_opacity, gflare->glow_mode);
 
2199
    }
 
2200
  if (calc.type & CALC_RAYS)
 
2201
    {
 
2202
      memcpy (tmp_pix, dest_pix, 4);
 
2203
      calc_rays_pix (rays_pix, x, y);
 
2204
      calc_paint_func (dest_pix, tmp_pix, rays_pix,
 
2205
                       calc.rays_opacity, gflare->rays_mode);
 
2206
    }
 
2207
  if (calc.type & CALC_SFLARE)
 
2208
    {
 
2209
      memcpy (tmp_pix, dest_pix, 4);
 
2210
      calc_sflare_pix (dest_pix, x, y, tmp_pix);
 
2211
    }
 
2212
}
 
2213
 
 
2214
/*
 
2215
        Paint func routines, such as Normal, Addition, ...
 
2216
 */
 
2217
static void
 
2218
calc_paint_func (guchar *dest, guchar *src1, guchar *src2, gint opacity,
 
2219
                 GFlareMode mode)
 
2220
{
 
2221
  guchar        buf[4], *s=buf;
 
2222
 
 
2223
  if (src2[3] == 0 || opacity <= 0)
 
2224
    {
 
2225
      memcpy (dest, src1, 4);
 
2226
      return;
 
2227
    }
 
2228
 
 
2229
  switch (mode)
 
2230
    {
 
2231
    case GF_NORMAL:
 
2232
      s = src2;
 
2233
      break;
 
2234
    case GF_ADDITION:
 
2235
      calc_addition (s, src1, src2);
 
2236
      break;
 
2237
    case GF_OVERLAY:
 
2238
      calc_overlay (s, src1, src2);
 
2239
      break;
 
2240
    case GF_SCREEN:
 
2241
      calc_screen (s, src1, src2);
 
2242
      break;
 
2243
    default:
 
2244
      s = src2;
 
2245
      break;
 
2246
    }
 
2247
  calc_combine (dest, src1, s, opacity);
 
2248
}
 
2249
 
 
2250
static void
 
2251
calc_combine (guchar *dest, guchar *src1, guchar *src2, gint opacity)
 
2252
{
 
2253
  gdouble       s1_a, s2_a, new_a;
 
2254
  gdouble       ratio, compl_ratio;
 
2255
  gint          i;
 
2256
 
 
2257
  s1_a = src1[3] / 255.0;
 
2258
  s2_a = src2[3] * opacity / 65025.0;
 
2259
  new_a  = s1_a + (1.0 - s1_a) * s2_a;
 
2260
 
 
2261
  if (new_a != 0.0)
 
2262
    ratio = s2_a / new_a;
 
2263
  else
 
2264
    ratio = 0.0;
 
2265
 
 
2266
  compl_ratio = 1.0 - ratio;
 
2267
 
 
2268
  for (i = 0; i < 3; i++)
 
2269
    dest[i] = src1[i] * compl_ratio + src2[i] * ratio;
 
2270
 
 
2271
  dest[3] = new_a * 255.0;
 
2272
}
 
2273
 
 
2274
static void
 
2275
calc_addition (guchar *dest, guchar *src1, guchar *src2)
 
2276
{
 
2277
  gint          tmp, i;
 
2278
 
 
2279
  for (i = 0; i < 3; i++)
 
2280
    {
 
2281
      tmp = src1[i] + src2[i];
 
2282
      dest[i] = tmp <= 255 ? tmp: 255;
 
2283
    }
 
2284
  dest[3] = MIN (src1[3], src2[3]);
 
2285
}
 
2286
 
 
2287
static void
 
2288
calc_screen (guchar *dest, guchar *src1, guchar *src2)
 
2289
{
 
2290
  gint          i;
 
2291
 
 
2292
  for (i = 0; i < 3; i++)
 
2293
    {
 
2294
      dest[i] = 255 - ((255 - src1[i]) * (255 - src2[i])) / 255;
 
2295
    }
 
2296
  dest[3] = MIN (src1[3], src2[3]);
 
2297
}
 
2298
 
 
2299
static void
 
2300
calc_overlay (guchar *dest, guchar *src1, guchar *src2)
 
2301
{
 
2302
  gint          screen, mult, i;
 
2303
 
 
2304
  for (i = 0; i < 3; i++)
 
2305
    {
 
2306
      screen = 255 - ((255 - src1[i]) * (255 - src2[i])) / 255;
 
2307
      mult = (src1[i] * src2[i]) / 255;
 
2308
      dest[i] = (screen * src1[i] + mult * (255 - src1[i])) / 255;
 
2309
    }
 
2310
  dest[3] = MIN (src1[3], src2[3]);
 
2311
}
 
2312
 
 
2313
/*************************************************************************/
 
2314
/**                                                                     **/
 
2315
/**                     Main Dialog                                     **/
 
2316
/**                     +++ dlg                                         **/
 
2317
/**                                                                     **/
 
2318
/*************************************************************************/
 
2319
 
 
2320
/*
 
2321
        This is gflare main dialog, one which opens in first.
 
2322
 */
 
2323
 
 
2324
static gboolean
 
2325
dlg_run (void)
 
2326
{
 
2327
  GtkWidget *shell;
 
2328
  GtkWidget *hbox;
 
2329
  GtkWidget *vbox;
 
2330
  GtkWidget *frame;
 
2331
  GtkWidget *abox;
 
2332
  GtkWidget *button;
 
2333
  GtkWidget *notebook;
 
2334
  gboolean   run = FALSE;
 
2335
 
 
2336
  gimp_ui_init (PLUG_IN_BINARY, TRUE);
 
2337
 
 
2338
  /*
 
2339
   *    Init Main Dialog
 
2340
   */
 
2341
 
 
2342
  dlg = g_new0 (GFlareDialog, 1);
 
2343
  dlg->init           = TRUE;
 
2344
  dlg->update_preview = TRUE;
 
2345
 
 
2346
  gradient_menu_init (); /* FIXME: this should go elsewhere  */
 
2347
  dlg_setup_gflare ();
 
2348
 
 
2349
  g_assert (gflares_list != NULL);
 
2350
  g_assert (dlg->gflare != NULL);
 
2351
  g_assert (dlg->gflare->name != NULL);
 
2352
 
 
2353
  /*
 
2354
   *    Dialog Shell
 
2355
   */
 
2356
 
 
2357
  shell = dlg->shell = gimp_dialog_new (_("Gradient Flare"), PLUG_IN_BINARY,
 
2358
                                        NULL, 0,
 
2359
                                        gimp_standard_help_func, PLUG_IN_PROC,
 
2360
 
 
2361
                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 
2362
                                        GTK_STOCK_OK,     GTK_RESPONSE_OK,
 
2363
 
 
2364
                                        NULL);
 
2365
 
 
2366
  gtk_dialog_set_alternative_button_order (GTK_DIALOG (shell),
 
2367
                                           GTK_RESPONSE_OK,
 
2368
                                           GTK_RESPONSE_CANCEL,
 
2369
                                           -1);
 
2370
 
 
2371
  /*
 
2372
   *    main hbox
 
2373
   */
 
2374
 
 
2375
  hbox = gtk_hbox_new (FALSE, 12);
 
2376
  gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
 
2377
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (shell)->vbox), hbox,
 
2378
                      FALSE, FALSE, 0);
 
2379
  gtk_widget_show (hbox);
 
2380
 
 
2381
  /*
 
2382
   *    Preview
 
2383
   */
 
2384
 
 
2385
  vbox = gtk_vbox_new (FALSE, 6);
 
2386
  gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
 
2387
  gtk_widget_show (vbox);
 
2388
 
 
2389
  abox = gtk_alignment_new (0.0, 0.0, 0.0, 0.0);
 
2390
  gtk_box_pack_start (GTK_BOX (vbox), abox, TRUE, TRUE, 0);
 
2391
  gtk_widget_show (abox);
 
2392
 
 
2393
  frame = gtk_frame_new (NULL);
 
2394
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
 
2395
  gtk_container_add (GTK_CONTAINER (abox), frame);
 
2396
  gtk_widget_show (frame);
 
2397
 
 
2398
  dlg->preview = preview_new (DLG_PREVIEW_WIDTH, DLG_PREVIEW_HEIGHT,
 
2399
                              dlg_preview_init_func, NULL,
 
2400
                              dlg_preview_render_func, NULL,
 
2401
                              dlg_preview_deinit_func, NULL);
 
2402
  gtk_widget_set_events (GTK_WIDGET (dlg->preview->widget), DLG_PREVIEW_MASK);
 
2403
  gtk_container_add (GTK_CONTAINER (frame), dlg->preview->widget);
 
2404
 
 
2405
  g_signal_connect (dlg->preview->widget, "realize",
 
2406
                    G_CALLBACK (dlg_preview_realize),
 
2407
                    NULL);
 
2408
  g_signal_connect (dlg->preview->widget, "event",
 
2409
                    G_CALLBACK (dlg_preview_handle_event),
 
2410
                    NULL);
 
2411
 
 
2412
  dlg_preview_calc_window ();
 
2413
 
 
2414
  button = gtk_check_button_new_with_mnemonic (_("A_uto update preview"));
 
2415
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
 
2416
                                dlg->update_preview);
 
2417
  gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
 
2418
  gtk_widget_show (button);
 
2419
 
 
2420
  g_signal_connect (button, "toggled",
 
2421
                    G_CALLBACK (dlg_update_preview_callback),
 
2422
                    &dlg->update_preview);
 
2423
 
 
2424
  /*
 
2425
   *    Notebook
 
2426
   */
 
2427
 
 
2428
  notebook = dlg->notebook = gtk_notebook_new ();
 
2429
  gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0);
 
2430
  gtk_widget_show (notebook);
 
2431
 
 
2432
  dlg_make_page_settings (dlg, notebook);
 
2433
  dlg_make_page_selector (dlg, notebook);
 
2434
 
 
2435
  gtk_widget_show (shell);
 
2436
 
 
2437
  /*
 
2438
   *    Initialization done
 
2439
   */
 
2440
  dlg->init = FALSE;
 
2441
  dlg_preview_update ();
 
2442
 
 
2443
  if (gimp_dialog_run (GIMP_DIALOG (shell)) == GTK_RESPONSE_OK)
 
2444
    {
 
2445
      gflare_name_copy (pvals.gflare_name, dlg->gflare->name);
 
2446
 
 
2447
      run = TRUE;
 
2448
    }
 
2449
 
 
2450
  gtk_widget_destroy (shell);
 
2451
 
 
2452
  return run;
 
2453
}
 
2454
 
 
2455
static void
 
2456
dlg_setup_gflare (void)
 
2457
{
 
2458
  dlg->gflare = gflares_list_lookup (pvals.gflare_name);
 
2459
 
 
2460
  if (!dlg->gflare)
 
2461
    {
 
2462
      dlg->gflare = gflares_list_lookup ("Default");
 
2463
      if (!dlg->gflare)
 
2464
        {
 
2465
          g_warning (_("`Default' is created."));
 
2466
          dlg->gflare = gflare_new_with_default (_("Default"));
 
2467
          gflares_list_insert (dlg->gflare);
 
2468
        }
 
2469
    }
 
2470
}
 
2471
 
 
2472
/***********************************/
 
2473
/**     Main Dialog / Preview     **/
 
2474
/***********************************/
 
2475
 
 
2476
/*
 
2477
 *      Calculate preview's window, ie. translation of preview widget and
 
2478
 *      drawable.
 
2479
 *
 
2480
 *      x0, x1, y0, y1 are drawable coord, corresponding with top left
 
2481
 *      corner of preview widget, etc.
 
2482
 */
 
2483
void
 
2484
dlg_preview_calc_window (void)
 
2485
{
 
2486
  gint     is_wide;
 
2487
  gdouble  offx, offy;
 
2488
 
 
2489
  is_wide = ((double) DLG_PREVIEW_HEIGHT * drawable->width
 
2490
             >= (double) DLG_PREVIEW_WIDTH * drawable->height);
 
2491
  if (is_wide)
 
2492
    {
 
2493
      offy = ((double) drawable->width * DLG_PREVIEW_HEIGHT / DLG_PREVIEW_WIDTH) / 2.0;
 
2494
 
 
2495
      dlg->pwin.x0 = 0;
 
2496
      dlg->pwin.x1 = drawable->width;
 
2497
      dlg->pwin.y0 = drawable->height / 2.0 - offy;
 
2498
      dlg->pwin.y1 = drawable->height / 2.0 + offy;
 
2499
    }
 
2500
  else
 
2501
    {
 
2502
      offx = ((double) drawable->height * DLG_PREVIEW_WIDTH / DLG_PREVIEW_HEIGHT) / 2.0;
 
2503
 
 
2504
      dlg->pwin.x0 = drawable->width / 2.0 - offx;
 
2505
      dlg->pwin.x1 = drawable->width / 2.0 + offx;
 
2506
      dlg->pwin.y0 = 0;
 
2507
      dlg->pwin.y1 = drawable->height;
 
2508
    }
 
2509
}
 
2510
 
 
2511
void
 
2512
ed_preview_calc_window (void)
 
2513
{
 
2514
  gint     is_wide;
 
2515
  gdouble  offx, offy;
 
2516
 
 
2517
  is_wide = ((double) DLG_PREVIEW_HEIGHT * drawable->width
 
2518
             >= (double) DLG_PREVIEW_WIDTH * drawable->height);
 
2519
  if (is_wide)
 
2520
    {
 
2521
      offy = ((double) drawable->width * DLG_PREVIEW_HEIGHT / DLG_PREVIEW_WIDTH) / 2.0;
 
2522
 
 
2523
      dlg->pwin.x0 = 0;
 
2524
      dlg->pwin.x1 = drawable->width;
 
2525
      dlg->pwin.y0 = drawable->height / 2.0 - offy;
 
2526
      dlg->pwin.y1 = drawable->height / 2.0 + offy;
 
2527
    }
 
2528
  else
 
2529
    {
 
2530
      offx = ((double) drawable->height * DLG_PREVIEW_WIDTH / DLG_PREVIEW_HEIGHT) / 2.0;
 
2531
 
 
2532
      dlg->pwin.x0 = drawable->width / 2.0 - offx;
 
2533
      dlg->pwin.x1 = drawable->width / 2.0 + offx;
 
2534
      dlg->pwin.y0 = 0;
 
2535
      dlg->pwin.y1 = drawable->height;
 
2536
    }
 
2537
}
 
2538
 
 
2539
static void
 
2540
dlg_preview_realize (GtkWidget *widget)
 
2541
{
 
2542
  GdkDisplay *display = gtk_widget_get_display (widget);
 
2543
  GdkCursor  *cursor  = gdk_cursor_new_for_display (display, GDK_CROSSHAIR);
 
2544
 
 
2545
  gdk_window_set_cursor (widget->window, cursor);
 
2546
  gdk_cursor_unref (cursor);
 
2547
}
 
2548
 
 
2549
static gboolean
 
2550
dlg_preview_handle_event (GtkWidget *widget,
 
2551
                          GdkEvent  *event)
 
2552
{
 
2553
  GdkEventButton *bevent;
 
2554
  gint           bx, by, x, y;
 
2555
 
 
2556
  switch (event->type)
 
2557
    {
 
2558
    case GDK_BUTTON_PRESS:
 
2559
      bevent = (GdkEventButton *) event;
 
2560
      bx = bevent->x;
 
2561
      by = bevent->y;
 
2562
 
 
2563
      /* convert widget coord to drawable coord */
 
2564
      x = dlg->pwin.x0 + (double) (dlg->pwin.x1 - dlg->pwin.x0)
 
2565
                                        * bx / DLG_PREVIEW_WIDTH;
 
2566
      y = dlg->pwin.y0 + (double) (dlg->pwin.y1 - dlg->pwin.y0)
 
2567
                                        * by / DLG_PREVIEW_HEIGHT;
 
2568
 
 
2569
      if ((x != pvals.xcenter || y != pvals.ycenter))
 
2570
        {
 
2571
          if (x != pvals.xcenter)
 
2572
            {
 
2573
              pvals.xcenter = x;
 
2574
              gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (dlg->sizeentry),
 
2575
                                          0, x);
 
2576
            }
 
2577
          if (y != pvals.ycenter)
 
2578
            {
 
2579
              pvals.ycenter = y;
 
2580
              gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (dlg->sizeentry),
 
2581
                                          1, y);
 
2582
            }
 
2583
          dlg_preview_update ();
 
2584
        }
 
2585
      return TRUE;
 
2586
    default:
 
2587
      break;
 
2588
    }
 
2589
  return FALSE;
 
2590
}
 
2591
 
 
2592
static void
 
2593
dlg_preview_update (void)
 
2594
{
 
2595
  if (!dlg->init && dlg->update_preview)
 
2596
    {
 
2597
      dlg->init_params_done = FALSE;
 
2598
      preview_render_start (dlg->preview);
 
2599
    }
 
2600
}
 
2601
 
 
2602
/*      preview callbacks       */
 
2603
static gint
 
2604
dlg_preview_init_func (Preview *preview, gpointer data)
 
2605
{
 
2606
  /* call init_params first, and iterate init_progress while
 
2607
     it returns true */
 
2608
  if (dlg->init_params_done == FALSE)
 
2609
    {
 
2610
      calc_init_params (dlg->gflare,
 
2611
                        CALC_GLOW | CALC_RAYS | CALC_SFLARE,
 
2612
                        pvals.xcenter, pvals.ycenter,
 
2613
                        pvals.radius, pvals.rotation, pvals.hue,
 
2614
                        pvals.vangle, pvals.vlength);
 
2615
      dlg->init_params_done = TRUE;
 
2616
      return TRUE;
 
2617
    }
 
2618
  return calc_init_progress ();
 
2619
}
 
2620
 
 
2621
/* render preview
 
2622
   do what "preview" means, ie. render lense flare effect onto drawable */
 
2623
static void
 
2624
dlg_preview_render_func (Preview  *preview,
 
2625
                         guchar   *dest,
 
2626
                         gint      y,
 
2627
                         gpointer  data)
 
2628
{
 
2629
  GimpPixelRgn  srcPR;
 
2630
  gint          x;
 
2631
  gint          dx, dy;         /* drawable x, y */
 
2632
  guchar       *src_row, *src;
 
2633
  guchar        src_pix[4], dest_pix[4];
 
2634
  gint          b;
 
2635
 
 
2636
  dy = (dlg->pwin.y0 +
 
2637
        (gdouble) (dlg->pwin.y1 - dlg->pwin.y0) * y / DLG_PREVIEW_HEIGHT);
 
2638
 
 
2639
  if (dy < 0 || dy >= drawable->height)
 
2640
    {
 
2641
      memset (dest, GRAY50, 3 * DLG_PREVIEW_WIDTH);
 
2642
      return;
 
2643
    }
 
2644
 
 
2645
  src_row = g_new (guchar, drawable->bpp * drawable->width);
 
2646
  gimp_pixel_rgn_init (&srcPR, drawable,
 
2647
                       0, 0, drawable->width, drawable->height, FALSE, FALSE);
 
2648
  gimp_pixel_rgn_get_row (&srcPR, src_row, 0, dy, drawable->width);
 
2649
 
 
2650
  for (x = 0; x < DLG_PREVIEW_HEIGHT; x++)
 
2651
    {
 
2652
      dx = (dlg->pwin.x0 +
 
2653
            (double) (dlg->pwin.x1 - dlg->pwin.x0) * x / DLG_PREVIEW_WIDTH);
 
2654
 
 
2655
      if (dx < 0 || dx >= drawable->width)
 
2656
        {
 
2657
          for (b = 0; b < 3; b++)
 
2658
            *dest++ = GRAY50;
 
2659
          continue;
 
2660
        }
 
2661
 
 
2662
      /* Get drawable pix value */
 
2663
      src = &src_row[dx * drawable->bpp];
 
2664
 
 
2665
      for (b = 0; b < 3; b++)
 
2666
        src_pix[b] = dinfo.is_color ? src[b] : src[0];
 
2667
      src_pix[3] = dinfo.has_alpha ? src[drawable->bpp-1] : OPAQUE;
 
2668
 
 
2669
      /* Get GFlare pix value */
 
2670
 
 
2671
      calc_gflare_pix (dest_pix, dx, dy, src_pix);
 
2672
 
 
2673
      /* Draw gray check if needed */
 
2674
      preview_rgba_to_rgb (dest, x, y, dest_pix);
 
2675
      dest += 3;
 
2676
    }
 
2677
 
 
2678
  g_free (src_row);
 
2679
}
 
2680
 
 
2681
static void
 
2682
dlg_preview_deinit_func (Preview *preview, gpointer data)
 
2683
{
 
2684
  if (dlg->init_params_done)
 
2685
    {
 
2686
      calc_deinit ();
 
2687
      dlg->init_params_done = TRUE;
 
2688
    }
 
2689
}
 
2690
 
 
2691
/*****************************************/
 
2692
/**     Main Dialog / Settings Page     **/
 
2693
/*****************************************/
 
2694
 
 
2695
static void
 
2696
dlg_make_page_settings (GFlareDialog *dlg,
 
2697
                        GtkWidget    *notebook)
 
2698
{
 
2699
  GtkWidget *main_vbox;
 
2700
  GtkWidget *frame;
 
2701
  GtkWidget *center;
 
2702
  GtkWidget *chain;
 
2703
  GtkWidget *table;
 
2704
  GtkWidget *button;
 
2705
  GtkWidget *asup_table;
 
2706
  GtkObject *adj;
 
2707
  gdouble    xres, yres;
 
2708
  gint       row;
 
2709
 
 
2710
  main_vbox = gtk_vbox_new (FALSE, 12);
 
2711
  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
 
2712
 
 
2713
  frame = gimp_frame_new (_("Center"));
 
2714
  gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
 
2715
  gtk_widget_show (frame);
 
2716
 
 
2717
  gimp_image_get_resolution (image_ID, &xres, &yres);
 
2718
 
 
2719
  center = dlg->sizeentry =
 
2720
    gimp_coordinates_new (gimp_image_get_unit (image_ID), "%a",
 
2721
                          TRUE, TRUE, 75, GIMP_SIZE_ENTRY_UPDATE_SIZE,
 
2722
 
 
2723
                          FALSE, FALSE,
 
2724
 
 
2725
                          _("_X:"), pvals.xcenter, xres,
 
2726
                          -GIMP_MAX_IMAGE_SIZE, GIMP_MAX_IMAGE_SIZE,
 
2727
                          0, gimp_drawable_width (drawable->drawable_id),
 
2728
 
 
2729
                          _("_Y:"), pvals.ycenter, yres,
 
2730
                          -GIMP_MAX_IMAGE_SIZE, GIMP_MAX_IMAGE_SIZE,
 
2731
                          0, gimp_drawable_height (drawable->drawable_id));
 
2732
 
 
2733
  chain = GTK_WIDGET (GIMP_COORDINATES_CHAINBUTTON (center));
 
2734
 
 
2735
  gtk_container_add (GTK_CONTAINER (frame), center);
 
2736
  g_signal_connect (center, "value-changed",
 
2737
                    G_CALLBACK (dlg_position_entry_callback),
 
2738
                    NULL);
 
2739
  g_signal_connect (center, "refval-changed",
 
2740
                    G_CALLBACK (dlg_position_entry_callback),
 
2741
                    NULL);
 
2742
  gtk_widget_hide (chain);
 
2743
  gtk_widget_show (center);
 
2744
 
 
2745
  frame = gimp_frame_new (_("Parameters"));
 
2746
  gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
 
2747
  gtk_widget_show (frame);
 
2748
 
 
2749
  table = gtk_table_new (5, 3, FALSE);
 
2750
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
 
2751
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
 
2752
  gtk_container_add (GTK_CONTAINER (frame), table);
 
2753
  gtk_widget_show (table);
 
2754
 
 
2755
  row = 0;
 
2756
 
 
2757
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
 
2758
                              _("_Radius:"), SCALE_WIDTH, 6,
 
2759
                              pvals.radius, 0.0, drawable->width / 2,
 
2760
                              1.0, 10.0, 1,
 
2761
                              FALSE, 0.0, GIMP_MAX_IMAGE_SIZE,
 
2762
                              NULL, NULL);
 
2763
  g_signal_connect (adj, "value-changed",
 
2764
                    G_CALLBACK (gimp_double_adjustment_update),
 
2765
                    &pvals.radius);
 
2766
  g_signal_connect (adj, "value-changed",
 
2767
                    G_CALLBACK (dlg_preview_update),
 
2768
                    NULL);
 
2769
 
 
2770
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
 
2771
                              _("Ro_tation:"), SCALE_WIDTH, 6,
 
2772
                              pvals.rotation, -180.0, 180.0, 1.0, 15.0, 1,
 
2773
                              TRUE, 0, 0,
 
2774
                              NULL, NULL);
 
2775
  g_signal_connect (adj, "value-changed",
 
2776
                    G_CALLBACK (gimp_double_adjustment_update),
 
2777
                    &pvals.rotation);
 
2778
  g_signal_connect (adj, "value-changed",
 
2779
                    G_CALLBACK (dlg_preview_update),
 
2780
                    NULL);
 
2781
 
 
2782
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
 
2783
                              _("_Hue rotation:"), SCALE_WIDTH, 6,
 
2784
                              pvals.hue, -180.0, 180.0, 1.0, 15.0, 1,
 
2785
                              TRUE, 0, 0,
 
2786
                              NULL, NULL);
 
2787
  g_signal_connect (adj, "value-changed",
 
2788
                    G_CALLBACK (gimp_double_adjustment_update),
 
2789
                    &pvals.hue);
 
2790
  g_signal_connect (adj, "value-changed",
 
2791
                    G_CALLBACK (dlg_preview_update),
 
2792
                    NULL);
 
2793
 
 
2794
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
 
2795
                              _("Vector _angle:"), SCALE_WIDTH, 6,
 
2796
                              pvals.vangle, 0.0, 359.0, 1.0, 15.0, 1,
 
2797
                              TRUE, 0, 0,
 
2798
                              NULL, NULL);
 
2799
  g_signal_connect (adj, "value-changed",
 
2800
                    G_CALLBACK (gimp_double_adjustment_update),
 
2801
                    &pvals.vangle);
 
2802
  g_signal_connect (adj, "value-changed",
 
2803
                    G_CALLBACK (dlg_preview_update),
 
2804
                    NULL);
 
2805
 
 
2806
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
 
2807
                              _("Vector _length:"), SCALE_WIDTH, 6,
 
2808
                              pvals.vlength, 1, 1000, 1.0, 10.0, 1,
 
2809
                              FALSE, 1, GIMP_MAX_IMAGE_SIZE,
 
2810
                              NULL, NULL);
 
2811
  g_signal_connect (adj, "value-changed",
 
2812
                    G_CALLBACK (gimp_double_adjustment_update),
 
2813
                    &pvals.vlength);
 
2814
  g_signal_connect (adj, "value-changed",
 
2815
                    G_CALLBACK (dlg_preview_update),
 
2816
                    NULL);
 
2817
 
 
2818
  /**
 
2819
  ***   Asupsample settings
 
2820
  ***   This code is stolen from gimp-0.99.x/app/blend.c
 
2821
  **/
 
2822
 
 
2823
  /*  asupsample frame */
 
2824
  frame = dlg->asupsample_frame = gimp_frame_new (NULL);
 
2825
  gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
 
2826
  gtk_widget_show (frame);
 
2827
 
 
2828
  button = gtk_check_button_new_with_mnemonic (_("A_daptive supersampling"));
 
2829
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
 
2830
                                pvals.use_asupsample);
 
2831
  gtk_frame_set_label_widget (GTK_FRAME (frame), button);
 
2832
  gtk_widget_show (button);
 
2833
 
 
2834
  asup_table = gtk_table_new (2, 3, FALSE);
 
2835
  gtk_table_set_col_spacings (GTK_TABLE (asup_table), 6);
 
2836
  gtk_table_set_row_spacings (GTK_TABLE (asup_table), 6);
 
2837
  gtk_container_add (GTK_CONTAINER (frame), asup_table);
 
2838
  gtk_widget_show (asup_table);
 
2839
 
 
2840
  gtk_widget_set_sensitive (asup_table, pvals.use_asupsample);
 
2841
  g_object_set_data (G_OBJECT (button), "set_sensitive", asup_table);
 
2842
  g_signal_connect (button, "toggled",
 
2843
                    G_CALLBACK (gimp_toggle_button_update),
 
2844
                    &pvals.use_asupsample);
 
2845
 
 
2846
  adj = gimp_scale_entry_new (GTK_TABLE (asup_table), 0, 0,
 
2847
                              _("_Max depth:"), -1, 4,
 
2848
                              pvals.asupsample_max_depth,
 
2849
                              1.0, 10.0, 1.0, 1.0, 0,
 
2850
                              TRUE, 0.0, 0.0,
 
2851
                              NULL, NULL);
 
2852
  g_signal_connect (adj, "value-changed",
 
2853
                    G_CALLBACK (gimp_int_adjustment_update),
 
2854
                    &pvals.asupsample_max_depth);
 
2855
 
 
2856
  adj = gimp_scale_entry_new (GTK_TABLE (asup_table), 0, 1,
 
2857
                              _("_Threshold"), -1, 4,
 
2858
                              pvals.asupsample_threshold,
 
2859
                              0.0, 4.0, 0.01, 0.01, 2,
 
2860
                              TRUE, 0.0, 0.0,
 
2861
                              NULL, NULL);
 
2862
  g_signal_connect (adj, "value-changed",
 
2863
                    G_CALLBACK (gimp_double_adjustment_update),
 
2864
                    &pvals.asupsample_threshold);
 
2865
 
 
2866
  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), main_vbox,
 
2867
                            gtk_label_new_with_mnemonic (_("_Settings")));
 
2868
  gtk_widget_show (main_vbox);
 
2869
}
 
2870
 
 
2871
static void
 
2872
dlg_position_entry_callback (GtkWidget *widget, gpointer data)
 
2873
{
 
2874
  gint x, y;
 
2875
 
 
2876
  x = RINT (gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (widget), 0));
 
2877
  y = RINT (gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (widget), 1));
 
2878
 
 
2879
  DEBUG_PRINT (("dlg_position_entry_callback\n"));
 
2880
 
 
2881
  if (pvals.xcenter != x ||
 
2882
      pvals.ycenter != y)
 
2883
    {
 
2884
      pvals.xcenter = x;
 
2885
      pvals.ycenter = y;
 
2886
 
 
2887
      dlg_preview_update ();
 
2888
    }
 
2889
}
 
2890
 
 
2891
static void
 
2892
dlg_update_preview_callback (GtkWidget *widget,
 
2893
                             gpointer   data)
 
2894
{
 
2895
  gimp_toggle_button_update (widget, data);
 
2896
 
 
2897
  dlg_preview_update ();
 
2898
}
 
2899
 
 
2900
/*****************************************/
 
2901
/**     Main Dialog / Selector Page     **/
 
2902
/*****************************************/
 
2903
 
 
2904
static void
 
2905
dlg_make_page_selector (GFlareDialog *dlg,
 
2906
                        GtkWidget    *notebook)
 
2907
{
 
2908
  GtkWidget         *vbox;
 
2909
  GtkWidget         *hbox;
 
2910
  GtkWidget         *listbox;
 
2911
  GtkListStore      *list;
 
2912
  GtkWidget         *listview;
 
2913
  GtkCellRenderer   *renderer;
 
2914
  GtkTreeViewColumn *column;
 
2915
  GtkWidget         *button;
 
2916
  gint               i;
 
2917
 
 
2918
  static struct
 
2919
  {
 
2920
    const gchar *label;
 
2921
    GCallback    callback;
 
2922
  }
 
2923
  buttons[] =
 
2924
  {
 
2925
    { GTK_STOCK_NEW,    G_CALLBACK (dlg_selector_new_callback)    },
 
2926
    { GTK_STOCK_EDIT,   G_CALLBACK (dlg_selector_edit_callback)   },
 
2927
    { GTK_STOCK_COPY,   G_CALLBACK (dlg_selector_copy_callback)   },
 
2928
    { GTK_STOCK_DELETE, G_CALLBACK (dlg_selector_delete_callback) }
 
2929
  };
 
2930
 
 
2931
  DEBUG_PRINT (("dlg_make_page_selector\n"));
 
2932
 
 
2933
  vbox = gtk_vbox_new (FALSE, 12);
 
2934
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
 
2935
 
 
2936
  /*
 
2937
   *    List Box
 
2938
   */
 
2939
 
 
2940
  listbox = gtk_scrolled_window_new (NULL, NULL);
 
2941
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (listbox),
 
2942
                                  GTK_POLICY_AUTOMATIC,
 
2943
                                  GTK_POLICY_AUTOMATIC);
 
2944
 
 
2945
  gtk_widget_set_size_request (listbox, DLG_LISTBOX_WIDTH, DLG_LISTBOX_HEIGHT);
 
2946
  gtk_box_pack_start (GTK_BOX (vbox), listbox, TRUE, TRUE, 0);
 
2947
 
 
2948
  list = dlg->selector_list = gtk_list_store_new (2,
 
2949
                                                  G_TYPE_STRING,
 
2950
                                                  G_TYPE_POINTER);
 
2951
  listview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (list));
 
2952
  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (listview), FALSE);
 
2953
 
 
2954
  gtk_container_add (GTK_CONTAINER (listbox), listview);
 
2955
  gtk_widget_show (listbox);
 
2956
  dlg->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (listview));
 
2957
  gtk_tree_selection_set_mode (dlg->selection, GTK_SELECTION_BROWSE);
 
2958
  gtk_widget_show (listview);
 
2959
  g_signal_connect (dlg->selection, "changed",
 
2960
                    G_CALLBACK (dlg_selector_list_item_callback),
 
2961
                    NULL);
 
2962
 
 
2963
  renderer = gtk_cell_renderer_text_new ();
 
2964
 
 
2965
  /* Note: the title isn't shown, so it doesn't need to be translated. */
 
2966
  column = gtk_tree_view_column_new_with_attributes ("GFlare", renderer,
 
2967
                                                      "text", 0,
 
2968
                                                      NULL);
 
2969
  gtk_tree_view_append_column (GTK_TREE_VIEW (listview), column);
 
2970
 
 
2971
  dlg_selector_setup_listbox ();
 
2972
 
 
2973
  /*
 
2974
   *    The buttons for the possible listbox operations
 
2975
   */
 
2976
 
 
2977
  hbox = gtk_hbox_new (FALSE, 6);
 
2978
  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
 
2979
  gtk_widget_show (hbox);
 
2980
 
 
2981
  for (i = 0; i < G_N_ELEMENTS (buttons); i++)
 
2982
    {
 
2983
      button = gtk_button_new_from_stock (buttons[i].label);
 
2984
      gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
 
2985
      gtk_widget_show (button);
 
2986
 
 
2987
      g_signal_connect (button, "clicked",
 
2988
                        buttons[i].callback,
 
2989
                        button);
 
2990
    }
 
2991
 
 
2992
  gtk_widget_show (vbox);
 
2993
 
 
2994
  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox,
 
2995
                            gtk_label_new_with_mnemonic (_("S_elector")));
 
2996
  gtk_widget_show (vbox);
 
2997
}
 
2998
 
 
2999
/*
 
3000
 *      Set up selector's listbox, according to gflares_list
 
3001
 */
 
3002
static void
 
3003
dlg_selector_setup_listbox (void)
 
3004
{
 
3005
  GList  *list;
 
3006
  GFlare *gflare;
 
3007
  gint    n;
 
3008
 
 
3009
  list = gflares_list;
 
3010
  n = 0;
 
3011
 
 
3012
  while (list)
 
3013
    {
 
3014
      GtkTreeIter   iter;
 
3015
 
 
3016
      gflare = list->data;
 
3017
 
 
3018
      /*
 
3019
        dlg->gflare should be valid (ie. not NULL) here.
 
3020
        */
 
3021
      gtk_list_store_append (dlg->selector_list, &iter);
 
3022
 
 
3023
      gtk_list_store_set (dlg->selector_list, &iter,
 
3024
                          0, gflare->name,
 
3025
                          1, gflare,
 
3026
                          -1);
 
3027
      if (gflare == dlg->gflare)
 
3028
         gtk_tree_selection_select_iter (dlg->selection,
 
3029
                                         &iter);
 
3030
 
 
3031
      list = list->next;
 
3032
      n++;
 
3033
    }
 
3034
}
 
3035
 
 
3036
static void
 
3037
dlg_selector_list_item_callback (GtkTreeSelection *selection)
 
3038
{
 
3039
  GtkTreeIter iter;
 
3040
 
 
3041
  if (gtk_tree_selection_get_selected (selection, NULL, &iter))
 
3042
    {
 
3043
      gtk_tree_model_get (GTK_TREE_MODEL (dlg->selector_list), &iter,
 
3044
                          1, &dlg->gflare, -1);
 
3045
    }
 
3046
 
 
3047
  dlg_preview_update ();
 
3048
}
 
3049
 
 
3050
/*
 
3051
 *      "New" button in Selector page
 
3052
 */
 
3053
static void
 
3054
dlg_selector_new_callback (GtkWidget *widget,
 
3055
                           gpointer   data)
 
3056
{
 
3057
  GtkWidget *query_box;
 
3058
 
 
3059
  query_box = gimp_query_string_box (_("New Gradient Flare"),
 
3060
                                     gtk_widget_get_toplevel (widget),
 
3061
                                     gimp_standard_help_func, PLUG_IN_PROC,
 
3062
                                     _("Enter a name for the new GFlare"),
 
3063
                                     _("Unnamed"),
 
3064
                                     NULL, NULL,
 
3065
                                     dlg_selector_new_ok_callback, dlg);
 
3066
  gtk_widget_show (query_box);
 
3067
}
 
3068
 
 
3069
static void
 
3070
dlg_selector_new_ok_callback (GtkWidget   *widget,
 
3071
                              const gchar *new_name,
 
3072
                              gpointer     data)
 
3073
{
 
3074
  GFlare      *gflare;
 
3075
  GtkTreeIter  iter;
 
3076
  gint         pos;
 
3077
 
 
3078
  g_return_if_fail (new_name != NULL);
 
3079
 
 
3080
  if (gflares_list_lookup (new_name))
 
3081
    {
 
3082
      g_message (_("The name '%s' is used already!"), new_name);
 
3083
      return;
 
3084
    }
 
3085
 
 
3086
  gflare = gflare_new_with_default (new_name);
 
3087
 
 
3088
  pos = gflares_list_insert (gflare);
 
3089
 
 
3090
  gtk_list_store_insert (dlg->selector_list, &iter, pos);
 
3091
  gtk_list_store_set (dlg->selector_list, &iter,
 
3092
                      0, gflare->name,
 
3093
                      1, gflare,
 
3094
                      -1);
 
3095
  gtk_tree_selection_select_iter (dlg->selection, &iter);
 
3096
 
 
3097
  dlg->gflare = gflare;
 
3098
  dlg_preview_update ();
 
3099
}
 
3100
 
 
3101
/*
 
3102
 *  "Edit" button in Selector page
 
3103
 */
 
3104
static void
 
3105
dlg_selector_edit_callback (GtkWidget *widget,
 
3106
                            gpointer   data)
 
3107
{
 
3108
  preview_render_end (dlg->preview);
 
3109
  gtk_widget_set_sensitive (dlg->shell, FALSE);
 
3110
  ed_run (GTK_WINDOW (dlg->shell),
 
3111
          dlg->gflare, dlg_selector_edit_done_callback, NULL);
 
3112
}
 
3113
 
 
3114
static void
 
3115
dlg_selector_edit_done_callback (gint     updated,
 
3116
                                 gpointer data)
 
3117
{
 
3118
  gtk_widget_set_sensitive (dlg->shell, TRUE);
 
3119
  if (updated)
 
3120
    {
 
3121
      gflare_save (dlg->gflare);
 
3122
    }
 
3123
  dlg_preview_update ();
 
3124
}
 
3125
 
 
3126
/*
 
3127
 *  "Copy" button in Selector page
 
3128
 */
 
3129
static void
 
3130
dlg_selector_copy_callback (GtkWidget *widget,
 
3131
                            gpointer   data)
 
3132
{
 
3133
  GtkWidget *query_box;
 
3134
  gchar     *name;
 
3135
 
 
3136
  name = g_strdup_printf ("%s copy", dlg->gflare->name);
 
3137
 
 
3138
  query_box = gimp_query_string_box (_("Copy Gradient Flare"),
 
3139
                                     gtk_widget_get_toplevel (widget),
 
3140
                                     gimp_standard_help_func, PLUG_IN_PROC,
 
3141
                                     _("Enter a name for the copied GFlare"),
 
3142
                                     name,
 
3143
                                     NULL, NULL,
 
3144
                                     dlg_selector_copy_ok_callback, dlg);
 
3145
  g_free (name);
 
3146
 
 
3147
  gtk_widget_show (query_box);
 
3148
}
 
3149
 
 
3150
static void
 
3151
dlg_selector_copy_ok_callback (GtkWidget   *widget,
 
3152
                               const gchar *copy_name,
 
3153
                               gpointer     data)
 
3154
{
 
3155
  GFlare      *gflare;
 
3156
  GtkTreeIter  iter;
 
3157
  gint         pos;
 
3158
 
 
3159
  g_return_if_fail (copy_name != NULL);
 
3160
 
 
3161
  if (gflares_list_lookup (copy_name))
 
3162
    {
 
3163
      g_warning (_("The name `%s' is used already!"), copy_name);
 
3164
      return;
 
3165
    }
 
3166
 
 
3167
  gflare = gflare_dup (dlg->gflare, copy_name);
 
3168
 
 
3169
  pos = gflares_list_insert (gflare);
 
3170
  gtk_list_store_insert (dlg->selector_list, &iter, pos);
 
3171
  gtk_list_store_set (dlg->selector_list, &iter,
 
3172
                      0, gflare->name,
 
3173
                      1, gflare,
 
3174
                      -1);
 
3175
  gtk_tree_selection_select_iter (dlg->selection, &iter);
 
3176
 
 
3177
  dlg->gflare = gflare;
 
3178
  gflare_save (dlg->gflare);
 
3179
  dlg_preview_update ();
 
3180
}
 
3181
 
 
3182
/*
 
3183
 *      "Delete" button in Selector page
 
3184
 */
 
3185
static void
 
3186
dlg_selector_delete_callback (GtkWidget *widget,
 
3187
                              gpointer   data)
 
3188
{
 
3189
  GtkWidget *dialog;
 
3190
  gchar     *str;
 
3191
 
 
3192
  if (num_gflares <= 1)
 
3193
    {
 
3194
      g_message (_("Cannot delete!! There must be at least one GFlare."));
 
3195
      return;
 
3196
    }
 
3197
 
 
3198
  gtk_widget_set_sensitive (dlg->shell, FALSE);
 
3199
 
 
3200
  str = g_strdup_printf (_("Are you sure you want to delete "
 
3201
                           "\"%s\" from the list and from disk?"),
 
3202
                         dlg->gflare->name);
 
3203
 
 
3204
  dialog = gimp_query_boolean_box (_("Delete Gradient Flare"),
 
3205
                                   dlg->shell,
 
3206
                                   gimp_standard_help_func, PLUG_IN_PROC,
 
3207
                                   GTK_STOCK_DIALOG_QUESTION,
 
3208
                                   str,
 
3209
                                   GTK_STOCK_DELETE, GTK_STOCK_CANCEL,
 
3210
                                   NULL, NULL,
 
3211
                                   dlg_selector_do_delete_callback,
 
3212
                                   NULL);
 
3213
 
 
3214
  g_free (str);
 
3215
 
 
3216
  gtk_widget_show (dialog);
 
3217
}
 
3218
 
 
3219
static void
 
3220
dlg_selector_do_delete_callback (GtkWidget *widget,
 
3221
                                 gboolean   delete,
 
3222
                                 gpointer   data)
 
3223
{
 
3224
  GFlare      *old_gflare;
 
3225
  GList       *tmp;
 
3226
  gint         i, new_i;
 
3227
  GtkTreeIter  iter;
 
3228
 
 
3229
  gtk_widget_set_sensitive (dlg->shell, TRUE);
 
3230
 
 
3231
  if (!delete)
 
3232
    return;
 
3233
 
 
3234
  i = gflares_list_index (dlg->gflare);
 
3235
 
 
3236
  if (i >= 0)
 
3237
    {
 
3238
      /* Remove current gflare from gflares_list and free it */
 
3239
      old_gflare = dlg->gflare;
 
3240
      gflares_list_remove (dlg->gflare);
 
3241
      dlg->gflare = NULL;
 
3242
 
 
3243
      /* Remove from listbox */
 
3244
      if (!gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (dlg->selector_list),
 
3245
                                          &iter, NULL, i))
 
3246
        {
 
3247
          g_warning ("Unsynchronized lists. Bad things will happen!");
 
3248
          return;
 
3249
        }
 
3250
      gtk_list_store_remove (dlg->selector_list, &iter);
 
3251
 
 
3252
      /* Calculate new position of gflare and select it */
 
3253
      new_i = (i < num_gflares) ? i : num_gflares - 1;
 
3254
      if ((tmp = g_list_nth (gflares_list, new_i)))
 
3255
          dlg->gflare = tmp->data;
 
3256
      if (!gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (dlg->selector_list),
 
3257
                                          &iter, NULL, i))
 
3258
        {
 
3259
          g_warning ("Unsynchronized lists. Bad things will happen!");
 
3260
          return;
 
3261
        }
 
3262
       gtk_tree_selection_select_iter (dlg->selection,
 
3263
                                       &iter);
 
3264
 
 
3265
      /* Delete old one from disk and memory */
 
3266
      if (old_gflare->filename)
 
3267
        g_unlink (old_gflare->filename);
 
3268
 
 
3269
      gflare_free (old_gflare);
 
3270
 
 
3271
      /* Update */
 
3272
      dlg_preview_update ();
 
3273
    }
 
3274
  else
 
3275
    {
 
3276
      g_warning (_("not found %s in gflares_list"), dlg->gflare->name);
 
3277
    }
 
3278
}
 
3279
 
 
3280
/*************************************************************************/
 
3281
/**                                                                     **/
 
3282
/**                     GFlare Editor                                   **/
 
3283
/**                     +++ ed                                          **/
 
3284
/**                                                                     **/
 
3285
/*************************************************************************/
 
3286
 
 
3287
/*
 
3288
        This is gflare editor dilaog, one which opens by clicking
 
3289
        "Edit" button on the selector page in the main dialog.
 
3290
 */
 
3291
 
 
3292
static void
 
3293
ed_run (GtkWindow            *parent,
 
3294
        GFlare               *target_gflare,
 
3295
        GFlareEditorCallback  callback,
 
3296
        gpointer              calldata)
 
3297
{
 
3298
  GtkWidget *shell;
 
3299
  GtkWidget *hbox;
 
3300
  GtkWidget *frame;
 
3301
  GtkWidget *abox;
 
3302
  GtkWidget *notebook;
 
3303
 
 
3304
  if (!ed)
 
3305
    ed = g_new0 (GFlareEditor, 1);
 
3306
  ed->init          = TRUE;
 
3307
  ed->run           = FALSE;
 
3308
  ed->target_gflare = target_gflare;
 
3309
  ed->gflare        = gflare_dup (target_gflare, target_gflare->name);
 
3310
  ed->callback      = callback;
 
3311
  ed->calldata      = calldata;
 
3312
 
 
3313
  /*
 
3314
   *    Dialog Shell
 
3315
   */
 
3316
  ed->shell =
 
3317
    shell = gimp_dialog_new (_("Gradient Flare Editor"), PLUG_IN_BINARY,
 
3318
                             GTK_WIDGET (parent), 0,
 
3319
                             gimp_standard_help_func, PLUG_IN_PROC,
 
3320
 
 
3321
                             _("Rescan Gradients"), RESPONSE_RESCAN,
 
3322
                             GTK_STOCK_CANCEL,      GTK_RESPONSE_CANCEL,
 
3323
                             GTK_STOCK_OK,          GTK_RESPONSE_OK,
 
3324
 
 
3325
                             NULL);
 
3326
 
 
3327
  gtk_dialog_set_alternative_button_order (GTK_DIALOG (shell),
 
3328
                                           RESPONSE_RESCAN,
 
3329
                                           GTK_RESPONSE_OK,
 
3330
                                           GTK_RESPONSE_CANCEL,
 
3331
                                           -1);
 
3332
 
 
3333
  g_signal_connect (shell, "response",
 
3334
                    G_CALLBACK (ed_response),
 
3335
                    ed);
 
3336
  g_signal_connect (shell, "destroy",
 
3337
                    G_CALLBACK (ed_destroy_callback),
 
3338
                    ed);
 
3339
 
 
3340
  /*
 
3341
   *    main hbox
 
3342
   */
 
3343
 
 
3344
  hbox = gtk_hbox_new (FALSE, 12);
 
3345
  gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
 
3346
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (shell)->vbox), hbox,
 
3347
                      FALSE, FALSE, 0);
 
3348
  gtk_widget_show (hbox);
 
3349
 
 
3350
  /*
 
3351
   *    Preview
 
3352
   */
 
3353
 
 
3354
  abox = gtk_alignment_new (0.0, 0.0, 0.0, 0.0);
 
3355
  gtk_box_pack_start (GTK_BOX (hbox), abox, FALSE, FALSE, 0);
 
3356
  gtk_widget_show (abox);
 
3357
 
 
3358
  frame = gtk_frame_new (NULL);
 
3359
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
 
3360
  gtk_container_add (GTK_CONTAINER (abox), frame);
 
3361
  gtk_widget_show (frame);
 
3362
 
 
3363
  ed->preview = preview_new (ED_PREVIEW_WIDTH, ED_PREVIEW_HEIGHT,
 
3364
                             ed_preview_init_func, NULL,
 
3365
                             ed_preview_render_func, NULL,
 
3366
                             ed_preview_deinit_func, NULL);
 
3367
  gtk_widget_set_events (GTK_WIDGET (ed->preview->widget), DLG_PREVIEW_MASK);
 
3368
  gtk_container_add (GTK_CONTAINER (frame), ed->preview->widget);
 
3369
  g_signal_connect (ed->preview->widget, "event",
 
3370
                    G_CALLBACK (dlg_preview_handle_event),
 
3371
                    NULL);
 
3372
  ed_preview_calc_window ();
 
3373
 
 
3374
  /*
 
3375
   *    Notebook
 
3376
   */
 
3377
  notebook = ed->notebook = gtk_notebook_new ();
 
3378
  gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
 
3379
  gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0);
 
3380
  gtk_widget_show (notebook);
 
3381
 
 
3382
  ed_make_page_general (ed, notebook);
 
3383
  ed_make_page_glow (ed, notebook);
 
3384
  ed_make_page_rays (ed, notebook);
 
3385
  ed_make_page_sflare (ed, notebook);
 
3386
 
 
3387
  gtk_widget_show (shell);
 
3388
 
 
3389
  ed->init = FALSE;
 
3390
  ed_preview_update ();
 
3391
}
 
3392
 
 
3393
static void
 
3394
ed_destroy_callback (GtkWidget    *widget,
 
3395
                     GFlareEditor *ed)
 
3396
{
 
3397
  preview_free (ed->preview);
 
3398
  gflare_free (ed->gflare);
 
3399
  if (ed->callback)
 
3400
    (*ed->callback) (ed->run, ed->calldata);
 
3401
}
 
3402
 
 
3403
static void
 
3404
ed_response (GtkWidget    *widget,
 
3405
             gint          response_id,
 
3406
             GFlareEditor *ed)
 
3407
{
 
3408
  switch (response_id)
 
3409
    {
 
3410
    case RESPONSE_RESCAN:
 
3411
      ed->init = TRUE;
 
3412
      gradient_menu_rescan ();
 
3413
      ed->init = FALSE;
 
3414
      ed_preview_update ();
 
3415
      gtk_widget_queue_draw (ed->notebook);
 
3416
      break;
 
3417
 
 
3418
    case GTK_RESPONSE_OK:
 
3419
      ed->run = TRUE;
 
3420
      gflare_copy (ed->target_gflare, ed->gflare);
 
3421
      gtk_widget_destroy (ed->shell);
 
3422
      break;
 
3423
 
 
3424
    default:
 
3425
      gtk_widget_destroy (ed->shell);
 
3426
      break;
 
3427
    }
 
3428
}
 
3429
 
 
3430
static void
 
3431
ed_make_page_general (GFlareEditor *ed,
 
3432
                      GtkWidget    *notebook)
 
3433
{
 
3434
  GFlare    *gflare = ed->gflare;
 
3435
  GtkWidget *vbox;
 
3436
  GtkWidget *frame;
 
3437
  GtkWidget *table;
 
3438
  GtkWidget *combo;
 
3439
  GtkObject *adj;
 
3440
 
 
3441
  vbox = gtk_vbox_new (FALSE, 12);
 
3442
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
 
3443
 
 
3444
  /*  Glow  */
 
3445
 
 
3446
  frame = gimp_frame_new (_("Glow Paint Options"));
 
3447
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
3448
  gtk_widget_show (frame);
 
3449
 
 
3450
  table = gtk_table_new (2, 3, FALSE);
 
3451
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
 
3452
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
 
3453
  gtk_container_add (GTK_CONTAINER (frame), table);
 
3454
  gtk_widget_show (table);
 
3455
 
 
3456
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
 
3457
                              _("Opacity:"), SCALE_WIDTH, 6,
 
3458
                              gflare->glow_opacity, 0.0, 100.0, 1.0, 10.0, 1,
 
3459
                              TRUE, 0, 0,
 
3460
                              NULL, NULL);
 
3461
  g_signal_connect (adj, "value-changed",
 
3462
                    G_CALLBACK (gimp_double_adjustment_update),
 
3463
                    &gflare->glow_opacity);
 
3464
  g_signal_connect (adj, "value-changed",
 
3465
                    G_CALLBACK (ed_preview_update),
 
3466
                    NULL);
 
3467
 
 
3468
  combo = ed_mode_menu_new (&gflare->glow_mode);
 
3469
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
 
3470
                             _("Paint mode:"), 0.0, 0.5, combo, 1, FALSE);
 
3471
 
 
3472
  /*  Rays  */
 
3473
 
 
3474
  frame = gimp_frame_new (_("Rays Paint Options"));
 
3475
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
3476
  gtk_widget_show (frame);
 
3477
 
 
3478
  table = gtk_table_new (2, 3, FALSE);
 
3479
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
 
3480
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
 
3481
  gtk_container_add (GTK_CONTAINER (frame), table);
 
3482
  gtk_widget_show (table);
 
3483
 
 
3484
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
 
3485
                              _("Opacity:"), SCALE_WIDTH, 6,
 
3486
                              gflare->rays_opacity, 0.0, 100.0, 1.0, 10.0, 1,
 
3487
                              TRUE, 0, 0,
 
3488
                              NULL, NULL);
 
3489
  g_signal_connect (adj, "value-changed",
 
3490
                    G_CALLBACK (gimp_double_adjustment_update),
 
3491
                    &gflare->rays_opacity);
 
3492
  g_signal_connect (adj, "value-changed",
 
3493
                    G_CALLBACK (ed_preview_update),
 
3494
                    NULL);
 
3495
 
 
3496
  combo = ed_mode_menu_new (&gflare->rays_mode);
 
3497
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
 
3498
                             _("Paint mode:"), 0.0, 0.5, combo, 1, FALSE);
 
3499
 
 
3500
  /*  Rays  */
 
3501
 
 
3502
  frame = gimp_frame_new (_("Second Flares Paint Options"));
 
3503
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
3504
  gtk_widget_show (frame);
 
3505
 
 
3506
  table = gtk_table_new (2, 3, FALSE);
 
3507
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
 
3508
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
 
3509
  gtk_container_add (GTK_CONTAINER (frame), table);
 
3510
  gtk_widget_show (table);
 
3511
 
 
3512
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
 
3513
                              _("Opacity:"), SCALE_WIDTH, 6,
 
3514
                              gflare->sflare_opacity, 0.0, 100.0, 1.0, 10.0, 1,
 
3515
                              TRUE, 0, 0,
 
3516
                              NULL, NULL);
 
3517
  g_signal_connect (adj, "value-changed",
 
3518
                    G_CALLBACK (gimp_double_adjustment_update),
 
3519
                    &gflare->sflare_opacity);
 
3520
  g_signal_connect (adj, "value-changed",
 
3521
                    G_CALLBACK (ed_preview_update),
 
3522
                    NULL);
 
3523
 
 
3524
  combo = ed_mode_menu_new (&gflare->sflare_mode);
 
3525
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
 
3526
                             _("Paint mode:"), 0.0, 0.5, combo, 1, FALSE);
 
3527
 
 
3528
  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox,
 
3529
                            gtk_label_new_with_mnemonic (_("_General")));
 
3530
  g_signal_connect (vbox, "map",
 
3531
                    G_CALLBACK (ed_page_map_callback),
 
3532
                    (gpointer) PAGE_GENERAL);
 
3533
  gtk_widget_show (vbox);
 
3534
}
 
3535
 
 
3536
static void
 
3537
ed_make_page_glow (GFlareEditor *ed,
 
3538
                   GtkWidget    *notebook)
 
3539
{
 
3540
  GFlare       *gflare = ed->gflare;
 
3541
  GradientMenu *gm;
 
3542
  GtkWidget    *vbox;
 
3543
  GtkWidget    *frame;
 
3544
  GtkWidget    *table;
 
3545
  GtkObject    *adj;
 
3546
  gint          row;
 
3547
 
 
3548
  vbox = gtk_vbox_new (FALSE, 12);
 
3549
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
 
3550
 
 
3551
  /*
 
3552
   *  Gradient Menus
 
3553
   */
 
3554
 
 
3555
  frame = gimp_frame_new (_("Gradients"));
 
3556
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
3557
  gtk_widget_show (frame);
 
3558
 
 
3559
  table = gtk_table_new (3, 3, FALSE);
 
3560
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
 
3561
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
 
3562
  gtk_container_add (GTK_CONTAINER (frame), table);
 
3563
 
 
3564
  gm = gradient_menu_new ((GradientMenuCallback) &ed_gradient_menu_callback,
 
3565
                          gflare->glow_radial, gflare->glow_radial);
 
3566
  ed_put_gradient_menu (table, 0, 0, _("Radial gradient:"), gm);
 
3567
 
 
3568
  gm = gradient_menu_new ((GradientMenuCallback) &ed_gradient_menu_callback,
 
3569
                          gflare->glow_angular, gflare->glow_angular);
 
3570
  ed_put_gradient_menu (table, 0, 1, _("Angular gradient:"), gm);
 
3571
 
 
3572
  gm = gradient_menu_new ((GradientMenuCallback) &ed_gradient_menu_callback,
 
3573
                          gflare->glow_angular_size, gflare->glow_angular_size);
 
3574
  ed_put_gradient_menu (table, 0, 2, _("Angular size gradient:"), gm);
 
3575
 
 
3576
  gtk_widget_show (table);
 
3577
 
 
3578
  /*
 
3579
   *  Scales
 
3580
   */
 
3581
 
 
3582
  frame = gimp_frame_new (_("Parameters"));
 
3583
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
3584
  gtk_widget_show (frame);
 
3585
 
 
3586
  table = gtk_table_new (3, 3, FALSE);
 
3587
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
 
3588
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
 
3589
  gtk_container_add (GTK_CONTAINER (frame), table);
 
3590
 
 
3591
  row = 0;
 
3592
 
 
3593
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
 
3594
                              _("Size (%):"), SCALE_WIDTH, 6,
 
3595
                              gflare->glow_size, 0.0, 200.0, 1.0, 10.0, 1,
 
3596
                              FALSE, 0, G_MAXINT,
 
3597
                              NULL, NULL);
 
3598
  g_signal_connect (adj, "value-changed",
 
3599
                    G_CALLBACK (gimp_double_adjustment_update),
 
3600
                    &gflare->glow_size);
 
3601
  g_signal_connect (adj, "value-changed",
 
3602
                    G_CALLBACK (ed_preview_update),
 
3603
                    NULL);
 
3604
 
 
3605
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
 
3606
                              _("Rotation:"), SCALE_WIDTH, 6,
 
3607
                              gflare->glow_rotation, -180.0, 180.0, 1.0, 15.0, 1,
 
3608
                              TRUE, 0, 0,
 
3609
                              NULL, NULL);
 
3610
  g_signal_connect (adj, "value-changed",
 
3611
                    G_CALLBACK (gimp_double_adjustment_update),
 
3612
                    &gflare->glow_rotation);
 
3613
  g_signal_connect (adj, "value-changed",
 
3614
                    G_CALLBACK (ed_preview_update),
 
3615
                    NULL);
 
3616
 
 
3617
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
 
3618
                              _("Hue rotation:"), SCALE_WIDTH, 6,
 
3619
                              gflare->glow_hue, -180.0, 180.0, 1.0, 15.0, 1,
 
3620
                              TRUE, 0, 0,
 
3621
                              NULL, NULL);
 
3622
  g_signal_connect (adj, "value-changed",
 
3623
                    G_CALLBACK (gimp_double_adjustment_update),
 
3624
                    &gflare->glow_hue);
 
3625
  g_signal_connect (adj, "value-changed",
 
3626
                    G_CALLBACK (ed_preview_update),
 
3627
                    NULL);
 
3628
 
 
3629
  gtk_widget_show (table);
 
3630
 
 
3631
  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox,
 
3632
                            gtk_label_new_with_mnemonic (_("G_low")));
 
3633
  g_signal_connect (vbox, "map",
 
3634
                    G_CALLBACK (ed_page_map_callback),
 
3635
                    (gpointer) PAGE_GLOW);
 
3636
  gtk_widget_show (vbox);
 
3637
}
 
3638
 
 
3639
static void
 
3640
ed_make_page_rays (GFlareEditor *ed,
 
3641
                   GtkWidget    *notebook)
 
3642
{
 
3643
  GFlare       *gflare = ed->gflare;
 
3644
  GradientMenu *gm;
 
3645
  GtkWidget    *vbox;
 
3646
  GtkWidget    *frame;
 
3647
  GtkWidget    *table;
 
3648
  GtkObject    *adj;
 
3649
  gint          row;
 
3650
 
 
3651
  vbox = gtk_vbox_new (FALSE, 12);
 
3652
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
 
3653
 
 
3654
  /*
 
3655
   *  Gradient Menus
 
3656
   */
 
3657
 
 
3658
  frame = gimp_frame_new (_("Gradients"));
 
3659
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
3660
  gtk_widget_show (frame);
 
3661
 
 
3662
  table = gtk_table_new (3, 3, FALSE);
 
3663
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
 
3664
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
 
3665
  gtk_container_add (GTK_CONTAINER (frame), table);
 
3666
 
 
3667
  row = 0;
 
3668
 
 
3669
  gm = gradient_menu_new ((GradientMenuCallback) &ed_gradient_menu_callback,
 
3670
                          gflare->rays_radial, gflare->rays_radial);
 
3671
  ed_put_gradient_menu (table, 0, row++, _("Radial gradient:"), gm);
 
3672
 
 
3673
  gm = gradient_menu_new ((GradientMenuCallback) &ed_gradient_menu_callback,
 
3674
                          gflare->rays_angular, gflare->rays_angular);
 
3675
  ed_put_gradient_menu (table, 0, row++, _("Angular gradient:"), gm);
 
3676
 
 
3677
  gm = gradient_menu_new ((GradientMenuCallback) &ed_gradient_menu_callback,
 
3678
                          gflare->rays_angular_size, gflare->rays_angular_size);
 
3679
  ed_put_gradient_menu (table, 0, row++, _("Angular size gradient:"), gm);
 
3680
 
 
3681
  gtk_widget_show (table);
 
3682
 
 
3683
  /*
 
3684
   *    Scales
 
3685
   */
 
3686
 
 
3687
  frame = gimp_frame_new (_("Parameters"));
 
3688
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
3689
  gtk_widget_show (frame);
 
3690
 
 
3691
  table = gtk_table_new (5, 3, FALSE);
 
3692
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
 
3693
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
 
3694
  gtk_container_add (GTK_CONTAINER (frame), table);
 
3695
 
 
3696
  row = 0;
 
3697
 
 
3698
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
 
3699
                              _("Size (%):"), SCALE_WIDTH, 6,
 
3700
                              gflare->rays_size, 0.0, 200.0, 1.0, 10.0, 1,
 
3701
                              FALSE, 0, G_MAXINT,
 
3702
                              NULL, NULL);
 
3703
  g_signal_connect (adj, "value-changed",
 
3704
                    G_CALLBACK (gimp_double_adjustment_update),
 
3705
                    &gflare->rays_size);
 
3706
  g_signal_connect (adj, "value-changed",
 
3707
                    G_CALLBACK (ed_preview_update),
 
3708
                    NULL);
 
3709
 
 
3710
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
 
3711
                              _("Rotation:"), SCALE_WIDTH, 6,
 
3712
                              gflare->rays_rotation,
 
3713
                              -180.0, 180.0, 1.0, 15.0, 1,
 
3714
                              TRUE, 0, 0,
 
3715
                              NULL, NULL);
 
3716
  g_signal_connect (adj, "value-changed",
 
3717
                    G_CALLBACK (gimp_double_adjustment_update),
 
3718
                    &gflare->rays_rotation);
 
3719
  g_signal_connect (adj, "value-changed",
 
3720
                    G_CALLBACK (ed_preview_update),
 
3721
                    NULL);
 
3722
 
 
3723
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
 
3724
                              _("Hue rotation:"), SCALE_WIDTH, 6,
 
3725
                              gflare->rays_hue, -180.0, 180.0, 1.0, 15.0, 1,
 
3726
                              TRUE, 0, 0,
 
3727
                              NULL, NULL);
 
3728
  g_signal_connect (adj, "value-changed",
 
3729
                    G_CALLBACK (gimp_double_adjustment_update),
 
3730
                    &gflare->rays_hue);
 
3731
  g_signal_connect (adj, "value-changed",
 
3732
                    G_CALLBACK (ed_preview_update),
 
3733
                    NULL);
 
3734
 
 
3735
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
 
3736
                              _("# of Spikes:"), SCALE_WIDTH, 6,
 
3737
                              gflare->rays_nspikes, 1, 300, 1.0, 10.0, 0,
 
3738
                              FALSE, 0, G_MAXINT,
 
3739
                              NULL, NULL);
 
3740
  g_signal_connect (adj, "value-changed",
 
3741
                    G_CALLBACK (gimp_int_adjustment_update),
 
3742
                    &gflare->rays_nspikes);
 
3743
  g_signal_connect (adj, "value-changed",
 
3744
                    G_CALLBACK (ed_preview_update),
 
3745
                    NULL);
 
3746
 
 
3747
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
 
3748
                              _("Spike thickness:"), SCALE_WIDTH, 6,
 
3749
                              gflare->rays_thickness, 1.0, 100.0, 1.0, 10.0, 1,
 
3750
                              FALSE, 0, GIMP_MAX_IMAGE_SIZE,
 
3751
                              NULL, NULL);
 
3752
  g_signal_connect (adj, "value-changed",
 
3753
                    G_CALLBACK (gimp_double_adjustment_update),
 
3754
                    &gflare->rays_thickness);
 
3755
  g_signal_connect (adj, "value-changed",
 
3756
                    G_CALLBACK (ed_preview_update),
 
3757
                    NULL);
 
3758
 
 
3759
  gtk_widget_show (table);
 
3760
 
 
3761
  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox,
 
3762
                            gtk_label_new_with_mnemonic (_("_Rays")));
 
3763
  g_signal_connect (vbox, "map",
 
3764
                    G_CALLBACK (ed_page_map_callback),
 
3765
                    (gpointer) PAGE_RAYS);
 
3766
  gtk_widget_show (vbox);
 
3767
}
 
3768
 
 
3769
static void
 
3770
ed_make_page_sflare (GFlareEditor *ed,
 
3771
                     GtkWidget    *notebook)
 
3772
{
 
3773
  GFlare       *gflare = ed->gflare;
 
3774
  GradientMenu *gm;
 
3775
  GtkWidget    *vbox;
 
3776
  GtkWidget    *table;
 
3777
  GtkWidget    *frame;
 
3778
  GtkWidget    *shape_vbox;
 
3779
  GSList       *shape_group = NULL;
 
3780
  GtkWidget    *polygon_hbox;
 
3781
  GtkWidget    *seed_hbox;
 
3782
  GtkWidget    *toggle;
 
3783
  GtkWidget    *label;
 
3784
  GtkWidget    *seed;
 
3785
  GtkWidget    *entry;
 
3786
  GtkObject    *adj;
 
3787
  gchar         buf[256];
 
3788
  gint          row;
 
3789
 
 
3790
  vbox = gtk_vbox_new (FALSE, 12);
 
3791
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
 
3792
 
 
3793
  /*
 
3794
   *  Gradient Menus
 
3795
   */
 
3796
 
 
3797
  frame = gimp_frame_new (_("Gradients"));
 
3798
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
3799
  gtk_widget_show (frame);
 
3800
 
 
3801
  table = gtk_table_new (3, 3, FALSE);
 
3802
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
 
3803
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
 
3804
  gtk_container_add (GTK_CONTAINER (frame), table);
 
3805
 
 
3806
  gm = gradient_menu_new ((GradientMenuCallback) &ed_gradient_menu_callback,
 
3807
                          gflare->sflare_radial, gflare->sflare_radial);
 
3808
  ed_put_gradient_menu (table, 0, 0, _("Radial gradient:"), gm);
 
3809
 
 
3810
  gm = gradient_menu_new ((GradientMenuCallback) &ed_gradient_menu_callback,
 
3811
                          gflare->sflare_sizefac, gflare->sflare_sizefac);
 
3812
  ed_put_gradient_menu (table, 0, 1, _("Size factor gradient:"), gm);
 
3813
 
 
3814
  gm = gradient_menu_new ((GradientMenuCallback) &ed_gradient_menu_callback,
 
3815
                          gflare->sflare_probability, gflare->sflare_probability);
 
3816
  ed_put_gradient_menu (table, 0, 2, _("Probability gradient:"), gm);
 
3817
 
 
3818
  gtk_widget_show (table);
 
3819
 
 
3820
  /*
 
3821
   *    Scales
 
3822
   */
 
3823
 
 
3824
  frame = gimp_frame_new (_("Parameters"));
 
3825
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
3826
  gtk_widget_show (frame);
 
3827
 
 
3828
  table = gtk_table_new (3, 3, FALSE);
 
3829
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
 
3830
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
 
3831
  gtk_container_add (GTK_CONTAINER (frame), table);
 
3832
 
 
3833
  row = 0;
 
3834
 
 
3835
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
 
3836
                              _("Size (%):"), SCALE_WIDTH, 6,
 
3837
                              gflare->sflare_size, 0.0, 200.0, 1.0, 10.0, 1,
 
3838
                              FALSE, 0, G_MAXINT,
 
3839
                              NULL, NULL);
 
3840
  g_signal_connect (adj, "value-changed",
 
3841
                    G_CALLBACK (gimp_double_adjustment_update),
 
3842
                    &gflare->sflare_size);
 
3843
  g_signal_connect (adj, "value-changed",
 
3844
                    G_CALLBACK (ed_preview_update),
 
3845
                    NULL);
 
3846
 
 
3847
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
 
3848
                              _("Rotation:"), SCALE_WIDTH, 6,
 
3849
                              gflare->sflare_rotation,
 
3850
                              -180.0, 180.0, 1.0, 15.0, 1,
 
3851
                              TRUE, 0, 0,
 
3852
                              NULL, NULL);
 
3853
  g_signal_connect (adj, "value-changed",
 
3854
                    G_CALLBACK (gimp_double_adjustment_update),
 
3855
                    &gflare->sflare_rotation);
 
3856
  g_signal_connect (adj, "value-changed",
 
3857
                    G_CALLBACK (ed_preview_update),
 
3858
                    NULL);
 
3859
 
 
3860
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
 
3861
                              _("Hue rotation:"), SCALE_WIDTH, 6,
 
3862
                              gflare->sflare_hue, -180.0, 180.0, 1.0, 15.0, 1,
 
3863
                              TRUE, 0, 0,
 
3864
                              NULL, NULL);
 
3865
  g_signal_connect (adj, "value-changed",
 
3866
                    G_CALLBACK (gimp_double_adjustment_update),
 
3867
                    &gflare->sflare_hue);
 
3868
  g_signal_connect (adj, "value-changed",
 
3869
                    G_CALLBACK (ed_preview_update),
 
3870
                    NULL);
 
3871
 
 
3872
  gtk_widget_show (table);
 
3873
 
 
3874
  /*
 
3875
   *    Shape Radio Button Frame
 
3876
   */
 
3877
 
 
3878
  frame = gimp_frame_new (_("Shape of Second Flares"));
 
3879
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
3880
  gtk_widget_show (frame);
 
3881
 
 
3882
  shape_vbox = gtk_vbox_new (FALSE, 2);
 
3883
  gtk_container_add (GTK_CONTAINER (frame), shape_vbox);
 
3884
  gtk_widget_show (shape_vbox);
 
3885
 
 
3886
  toggle = gtk_radio_button_new_with_label (shape_group, _("Circle"));
 
3887
  shape_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (toggle));
 
3888
  g_object_set_data (G_OBJECT (toggle), "gimp-item-data",
 
3889
                     GINT_TO_POINTER (GF_CIRCLE));
 
3890
  g_signal_connect (toggle, "toggled",
 
3891
                    G_CALLBACK (ed_shape_radio_callback),
 
3892
                    &gflare->sflare_shape);
 
3893
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
 
3894
                                gflare->sflare_shape == GF_CIRCLE);
 
3895
  gtk_box_pack_start (GTK_BOX (shape_vbox), toggle, FALSE, FALSE, 0);
 
3896
  gtk_widget_show (toggle);
 
3897
 
 
3898
  polygon_hbox = gtk_hbox_new (FALSE, 6);
 
3899
  gtk_box_pack_start (GTK_BOX (shape_vbox), polygon_hbox, FALSE, FALSE, 0);
 
3900
  gtk_widget_show (polygon_hbox);
 
3901
 
 
3902
  toggle = ed->polygon_toggle =
 
3903
    gtk_radio_button_new_with_label (shape_group, _("Polygon"));
 
3904
  shape_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (toggle));
 
3905
  g_object_set_data (G_OBJECT (toggle), "gimp-item-data",
 
3906
                     GINT_TO_POINTER (GF_POLYGON));
 
3907
  g_signal_connect (toggle, "toggled",
 
3908
                    G_CALLBACK (ed_shape_radio_callback),
 
3909
                    &gflare->sflare_shape);
 
3910
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
 
3911
                                gflare->sflare_shape == GF_POLYGON);
 
3912
  gtk_box_pack_start (GTK_BOX (polygon_hbox), toggle, FALSE, FALSE, 0);
 
3913
  gtk_widget_show (toggle);
 
3914
 
 
3915
  entry = ed->polygon_entry = gtk_entry_new ();
 
3916
  gtk_entry_set_width_chars (GTK_ENTRY (entry), 4);
 
3917
  g_snprintf (buf, sizeof (buf), "%d", gflare->sflare_nverts);
 
3918
  gtk_entry_set_text (GTK_ENTRY (entry), buf);
 
3919
  g_signal_connect (entry, "changed",
 
3920
                    G_CALLBACK (ed_ientry_callback),
 
3921
                    &gflare->sflare_nverts);
 
3922
  gtk_box_pack_start (GTK_BOX (polygon_hbox), entry, FALSE, FALSE, 0);
 
3923
  gtk_widget_show (entry);
 
3924
 
 
3925
  gtk_widget_set_sensitive (entry, gflare->sflare_shape == GF_POLYGON);
 
3926
  g_object_set_data (G_OBJECT (toggle), "set_sensitive", entry);
 
3927
 
 
3928
  /*
 
3929
   *    Random Seed Entry
 
3930
   */
 
3931
 
 
3932
  seed_hbox = gtk_hbox_new (FALSE, 6);
 
3933
  gtk_box_pack_start (GTK_BOX (vbox), seed_hbox, FALSE, FALSE, 0);
 
3934
  gtk_widget_show (seed_hbox);
 
3935
 
 
3936
  label = gtk_label_new (_("Random seed:"));
 
3937
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
 
3938
  gtk_box_pack_start (GTK_BOX (seed_hbox), label, FALSE, FALSE, 0);
 
3939
  gtk_widget_show (label);
 
3940
 
 
3941
  seed = gimp_random_seed_new (&gflare->sflare_seed, &gflare->random_seed);
 
3942
  gtk_box_pack_start (GTK_BOX (seed_hbox), seed, FALSE, TRUE, 0);
 
3943
  gtk_widget_show (seed);
 
3944
 
 
3945
  g_signal_connect (GIMP_RANDOM_SEED_SPINBUTTON_ADJ (seed), "value-changed",
 
3946
                    G_CALLBACK (ed_preview_update),
 
3947
                    NULL);
 
3948
 
 
3949
  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox,
 
3950
                            gtk_label_new_with_mnemonic (_("_Second Flares")));
 
3951
  g_signal_connect (vbox, "map",
 
3952
                    G_CALLBACK (ed_page_map_callback),
 
3953
                    (gpointer) PAGE_SFLARE);
 
3954
  gtk_widget_show (vbox);
 
3955
}
 
3956
 
 
3957
GtkWidget *
 
3958
ed_mode_menu_new (GFlareMode *mode_var)
 
3959
{
 
3960
  GtkWidget *combo = gimp_int_combo_box_new_array (GF_NUM_MODES,
 
3961
                                                   gflare_menu_modes);
 
3962
 
 
3963
  gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), *mode_var,
 
3964
                              G_CALLBACK (ed_mode_menu_callback),
 
3965
                              mode_var);
 
3966
 
 
3967
  return combo;
 
3968
}
 
3969
 
 
3970
/*
 
3971
  puts gradient menu with caption into table
 
3972
  occupies 1 row and 3 cols in table
 
3973
 */
 
3974
static void
 
3975
ed_put_gradient_menu (GtkWidget    *table,
 
3976
                      gint          x,
 
3977
                      gint          y,
 
3978
                      const gchar  *caption,
 
3979
                      GradientMenu *gm)
 
3980
{
 
3981
  GtkWidget *label;
 
3982
 
 
3983
  label = gtk_label_new (caption);
 
3984
  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
 
3985
  gtk_widget_show (label);
 
3986
 
 
3987
  gtk_table_attach (GTK_TABLE (table), label,
 
3988
                    x    , x + 1, y, y + 1,
 
3989
                    GTK_FILL, 0, 0, 0);
 
3990
  gtk_table_attach (GTK_TABLE (table), gm->preview,
 
3991
                    x + 1, x + 2, y, y + 1,
 
3992
                    0, 0, 0, 0);
 
3993
  gtk_table_attach (GTK_TABLE (table), gm->combo,
 
3994
                    x + 2, x + 3, y, y + 1,
 
3995
                    0, 0, 0, 0);
 
3996
}
 
3997
 
 
3998
static void
 
3999
ed_mode_menu_callback (GtkWidget *widget,
 
4000
                       gpointer   data)
 
4001
{
 
4002
  gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), (gint *) data);
 
4003
 
 
4004
  ed_preview_update ();
 
4005
}
 
4006
 
 
4007
static void
 
4008
ed_gradient_menu_callback (const gchar *gradient_name,
 
4009
                           gpointer     data)
 
4010
{
 
4011
  gchar *dest_string = data;
 
4012
 
 
4013
  /* @GRADIENT_NAME */
 
4014
  gradient_name_copy (dest_string, gradient_name);
 
4015
  ed_preview_update ();
 
4016
}
 
4017
 
 
4018
static void
 
4019
ed_shape_radio_callback (GtkWidget *widget,
 
4020
                         gpointer   data)
 
4021
{
 
4022
  gimp_radio_button_update (widget, data);
 
4023
 
 
4024
  ed_preview_update ();
 
4025
}
 
4026
 
 
4027
static void
 
4028
ed_ientry_callback (GtkWidget *widget,
 
4029
                    gpointer   data)
 
4030
{
 
4031
  gint new_val;
 
4032
 
 
4033
  new_val = atoi (gtk_entry_get_text (GTK_ENTRY (widget)));
 
4034
  *(gint *)data = new_val;
 
4035
 
 
4036
  ed_preview_update ();
 
4037
}
 
4038
 
 
4039
/*
 
4040
  NOTE: This is hack, because this code depends on internal "map"
 
4041
  signal of changing pages of gtknotebook.
 
4042
 */
 
4043
static void
 
4044
ed_page_map_callback (GtkWidget *widget,
 
4045
                      gpointer   data)
 
4046
{
 
4047
  gint page_num = GPOINTER_TO_INT (data);
 
4048
 
 
4049
  DEBUG_PRINT(("ed_page_map_callback\n"));
 
4050
 
 
4051
  ed->cur_page = page_num;
 
4052
  ed_preview_update ();
 
4053
}
 
4054
 
 
4055
 
 
4056
static void
 
4057
ed_preview_update (void)
 
4058
{
 
4059
  if (ed->init)
 
4060
    return;
 
4061
 
 
4062
  ed->init_params_done = FALSE;
 
4063
  preview_render_start (ed->preview);
 
4064
}
 
4065
 
 
4066
static gint
 
4067
ed_preview_init_func (Preview *preview, gpointer data)
 
4068
{
 
4069
  int   type = 0;
 
4070
 
 
4071
  if (ed->init_params_done == FALSE)
 
4072
    {
 
4073
      switch (ed->cur_page)
 
4074
        {
 
4075
        case PAGE_GENERAL:
 
4076
          type = (CALC_GLOW | CALC_RAYS | CALC_SFLARE);
 
4077
          break;
 
4078
        case PAGE_GLOW:
 
4079
          type = CALC_GLOW;
 
4080
          break;
 
4081
        case PAGE_RAYS:
 
4082
          type = CALC_RAYS;
 
4083
          break;
 
4084
        case PAGE_SFLARE:
 
4085
          type = CALC_SFLARE;
 
4086
          break;
 
4087
        default:
 
4088
          g_warning ("ed_preview_edit_func: bad page");
 
4089
          break;
 
4090
        }
 
4091
      calc_init_params (ed->gflare, type,
 
4092
                        ED_PREVIEW_WIDTH/2, ED_PREVIEW_HEIGHT/2,
 
4093
                        ED_PREVIEW_WIDTH/2, 0.0, 0.0,
 
4094
                        pvals.vangle, pvals.vlength);
 
4095
 
 
4096
      ed->init_params_done = TRUE;
 
4097
      return TRUE;
 
4098
    }
 
4099
  return calc_init_progress ();
 
4100
}
 
4101
 
 
4102
static void
 
4103
ed_preview_deinit_func (Preview *preview, gpointer data)
 
4104
{
 
4105
  if (ed->init_params_done)
 
4106
    {
 
4107
      calc_deinit ();
 
4108
      ed->init_params_done = FALSE;
 
4109
    }
 
4110
}
 
4111
 
 
4112
static void
 
4113
ed_preview_render_func (Preview *preview, guchar *buffer, gint y, gpointer data)
 
4114
{
 
4115
  switch (ed->cur_page)
 
4116
    {
 
4117
    case PAGE_GENERAL:
 
4118
      ed_preview_render_general (buffer, y);
 
4119
      break;
 
4120
    case PAGE_GLOW:
 
4121
      ed_preview_render_glow (buffer, y);
 
4122
      break;
 
4123
    case PAGE_RAYS:
 
4124
      ed_preview_render_rays (buffer, y);
 
4125
      break;
 
4126
    case PAGE_SFLARE:
 
4127
      ed_preview_render_sflare (buffer, y);
 
4128
      break;
 
4129
    default:
 
4130
      g_warning ("hmm, bad page in ed_preview_render_func ()");
 
4131
      break;
 
4132
    }
 
4133
}
 
4134
 
 
4135
static void
 
4136
ed_preview_render_general (guchar *buffer, gint y)
 
4137
{
 
4138
  int           x, i;
 
4139
  guchar        gflare_pix[4];
 
4140
  static guchar src_pix[4] = {0, 0, 0, OPAQUE};
 
4141
  int           gflare_a;
 
4142
 
 
4143
  for (x = 0; x < ED_PREVIEW_WIDTH; x++)
 
4144
    {
 
4145
      calc_gflare_pix (gflare_pix, x, y, src_pix);
 
4146
      gflare_a = gflare_pix[3];
 
4147
 
 
4148
      for (i = 0; i < 3; i++)
 
4149
        {
 
4150
          *buffer++ = gflare_pix[i] * gflare_a / 255;
 
4151
        }
 
4152
    }
 
4153
}
 
4154
 
 
4155
static void
 
4156
ed_preview_render_glow (guchar *buffer, gint y)
 
4157
{
 
4158
  int           x, i;
 
4159
  guchar        pix[4];
 
4160
 
 
4161
  for (x = 0; x < ED_PREVIEW_WIDTH; x++)
 
4162
    {
 
4163
      calc_glow_pix (pix, x, y);
 
4164
      for (i = 0; i < 3; i++)
 
4165
        *buffer++ = pix[i] * pix[3] / 255;
 
4166
    }
 
4167
}
 
4168
 
 
4169
static void
 
4170
ed_preview_render_rays (guchar *buffer, gint y)
 
4171
{
 
4172
  int           x, i;
 
4173
  guchar        pix[4];
 
4174
 
 
4175
  for (x = 0; x < ED_PREVIEW_WIDTH; x++)
 
4176
    {
 
4177
      calc_rays_pix (pix, x, y);
 
4178
      for (i = 0; i < 3; i++)
 
4179
        *buffer++ = pix[i] * pix[3] / 255;
 
4180
    }
 
4181
}
 
4182
 
 
4183
static void
 
4184
ed_preview_render_sflare (guchar *buffer, gint y)
 
4185
{
 
4186
  int           x, i;
 
4187
  guchar        pix[4];
 
4188
  static guchar src_pix[4] = {0, 0, 0, OPAQUE};
 
4189
 
 
4190
  for (x = 0; x < ED_PREVIEW_WIDTH; x++)
 
4191
    {
 
4192
      calc_sflare_pix (pix, x, y, src_pix);
 
4193
      for (i = 0; i < 3; i++)
 
4194
        *buffer++ = pix[i] * pix[3] / 255;
 
4195
    }
 
4196
}
 
4197
 
 
4198
/*************************************************************************/
 
4199
/**                                                                     **/
 
4200
/**                     +++ Preview                                     **/
 
4201
/**                                                                     **/
 
4202
/*************************************************************************/
 
4203
 
 
4204
/*
 
4205
        this is generic preview routines.
 
4206
 */
 
4207
 
 
4208
 
 
4209
/*
 
4210
    Routines to render the preview in background
 
4211
 */
 
4212
static Preview *
 
4213
preview_new (gint                  width,
 
4214
             gint                  height,
 
4215
             PreviewInitFunc       init_func,
 
4216
             gpointer              init_data,
 
4217
             PreviewRenderFunc     render_func,
 
4218
             gpointer              render_data,
 
4219
             PreviewDeinitFunc     deinit_func,
 
4220
             gpointer              deinit_data)
 
4221
{
 
4222
  Preview *preview;
 
4223
 
 
4224
  preview = g_new0 (Preview, 1);
 
4225
 
 
4226
  preview->widget = gimp_preview_area_new ();
 
4227
  gtk_widget_set_size_request (preview->widget, width, height);
 
4228
  gtk_widget_show (preview->widget);
 
4229
 
 
4230
  preview->width           = width;
 
4231
  preview->height          = height;
 
4232
  preview->init_func       = init_func;
 
4233
  preview->init_data       = init_data;
 
4234
  preview->render_func     = render_func;
 
4235
  preview->render_data     = render_data;
 
4236
  preview->deinit_func     = deinit_func;
 
4237
  preview->deinit_data     = deinit_data;
 
4238
  preview->idle_tag        = 0;
 
4239
  preview->buffer          = g_new (guchar, width * 3);
 
4240
  preview->full_image_buffer = g_new (guchar, width * height * 3);
 
4241
 
 
4242
  return preview;
 
4243
}
 
4244
 
 
4245
static void
 
4246
preview_free (Preview *preview)
 
4247
{
 
4248
  preview_render_end (preview);
 
4249
  /* not destroy preview->widget */
 
4250
  g_free (preview->buffer);
 
4251
  g_free (preview->full_image_buffer);
 
4252
  g_free (preview);
 
4253
}
 
4254
 
 
4255
/*
 
4256
  Start rendering of the preview in background using an idle event.
 
4257
  If already started and not yet finished, stop it first.
 
4258
 */
 
4259
static void
 
4260
preview_render_start (Preview *preview)
 
4261
{
 
4262
  preview_render_end (preview);
 
4263
 
 
4264
  preview->init_done = FALSE;
 
4265
  preview->current_y = 0;
 
4266
  preview->drawn_y = 0;
 
4267
  preview->timeout_tag = g_timeout_add (100,
 
4268
                                        (GSourceFunc) preview_render_start_2,
 
4269
                                        preview);
 
4270
}
 
4271
 
 
4272
static gint
 
4273
preview_render_start_2 (Preview *preview)
 
4274
{
 
4275
  preview->timeout_tag = 0;
 
4276
  preview->idle_tag = g_idle_add ((GSourceFunc) preview_handle_idle, preview);
 
4277
  return FALSE;
 
4278
}
 
4279
 
 
4280
static void
 
4281
preview_render_end (Preview *preview)
 
4282
{
 
4283
  if (preview->timeout_tag > 0)
 
4284
    {
 
4285
      g_source_remove (preview->timeout_tag);
 
4286
      preview->timeout_tag = 0;
 
4287
    }
 
4288
  if (preview->idle_tag > 0)
 
4289
    {
 
4290
      if (preview->deinit_func)
 
4291
        (*preview->deinit_func) (preview, preview->deinit_data);
 
4292
 
 
4293
      g_source_remove (preview->idle_tag);
 
4294
      preview->idle_tag = 0;
 
4295
    }
 
4296
}
 
4297
 
 
4298
/*
 
4299
  Handle an idle event.
 
4300
  Return FALSE if done, TRUE otherwise.
 
4301
 */
 
4302
static gboolean
 
4303
preview_handle_idle (Preview *preview)
 
4304
{
 
4305
  gboolean done = FALSE;
 
4306
 
 
4307
  if (preview->init_done == FALSE)
 
4308
    {
 
4309
      if (preview->init_func &&
 
4310
          (*preview->init_func) (preview, preview->init_data))
 
4311
        return TRUE;
 
4312
 
 
4313
      preview->init_done = TRUE;
 
4314
    }
 
4315
 
 
4316
  if (preview->render_func)
 
4317
    (*preview->render_func) (preview, preview->buffer, preview->current_y,
 
4318
                             preview->render_data);
 
4319
  else
 
4320
    memset (preview->buffer, 0, preview->width * 3);
 
4321
 
 
4322
  memcpy (preview->full_image_buffer + preview->width * 3 * preview->current_y,
 
4323
          preview->buffer,
 
4324
          preview->width * 3);
 
4325
 
 
4326
  if (++preview->current_y >= preview->height)
 
4327
    done = TRUE;
 
4328
 
 
4329
  if (done)
 
4330
    {
 
4331
      gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview->widget),
 
4332
                              0, 0, preview->width, preview->height,
 
4333
                              GIMP_RGB_IMAGE,
 
4334
                              preview->full_image_buffer,
 
4335
                              preview->width * 3);
 
4336
 
 
4337
      preview->drawn_y = preview->current_y;
 
4338
      preview_render_end (preview);
 
4339
      return FALSE;
 
4340
    }
 
4341
 
 
4342
  return TRUE;
 
4343
}
 
4344
 
 
4345
/*
 
4346
  Convert RGBA to RGB with rendering gray check if needed.
 
4347
        (from nova.c)
 
4348
  input:  guchar src[4]         RGBA pixel
 
4349
  output: guchar dest[3]        RGB pixel
 
4350
 */
 
4351
 
 
4352
static void
 
4353
preview_rgba_to_rgb (guchar *dest,
 
4354
                     gint    x,
 
4355
                     gint    y,
 
4356
                     guchar *src)
 
4357
{
 
4358
  gint src_a;
 
4359
  gint check;
 
4360
  gint b;
 
4361
 
 
4362
  src_a = src[3];
 
4363
 
 
4364
  if (src_a == OPAQUE)  /* full opaque */
 
4365
    {
 
4366
      for (b = 0; b < 3; b++)
 
4367
        dest[b] = src[b];
 
4368
    }
 
4369
  else
 
4370
    {
 
4371
      if ((x % (GIMP_CHECK_SIZE) < GIMP_CHECK_SIZE_SM) ^
 
4372
          (y % (GIMP_CHECK_SIZE) < GIMP_CHECK_SIZE_SM))
 
4373
        check = GIMP_CHECK_LIGHT * 255;
 
4374
      else
 
4375
        check = GIMP_CHECK_DARK * 255;
 
4376
 
 
4377
      if (src_a == 0)   /* full transparent */
 
4378
        {
 
4379
          for (b = 0; b < 3; b++)
 
4380
            dest[b] = check;
 
4381
        }
 
4382
      else
 
4383
        {
 
4384
          for (b = 0; b < 3; b++)
 
4385
            dest[b] = (src[b] * src_a + check * (OPAQUE-src_a)) / OPAQUE;
 
4386
        }
 
4387
    }
 
4388
}
 
4389
 
 
4390
/*************************************************************************/
 
4391
/**                                                                     **/
 
4392
/**                     +++ Gradient Menu                               **/
 
4393
/**                     +++ gm                                          **/
 
4394
/**                                                                     **/
 
4395
/*************************************************************************/
 
4396
 
 
4397
static void
 
4398
gradient_menu_init (void)
 
4399
{
 
4400
  gm_gradient_get_list ();
 
4401
  gradient_menus = NULL;
 
4402
}
 
4403
 
 
4404
static void
 
4405
gradient_menu_rescan (void)
 
4406
{
 
4407
  GList         *tmp;
 
4408
  GradientMenu  *gm;
 
4409
  GtkTreeModel  *model;
 
4410
 
 
4411
  /* Detach and destroy menus first */
 
4412
  tmp = gradient_menus;
 
4413
  while (tmp)
 
4414
    {
 
4415
      gm  = tmp->data;
 
4416
      tmp = tmp->next;
 
4417
 
 
4418
      model = gtk_combo_box_get_model (GTK_COMBO_BOX (gm->combo));
 
4419
      gtk_list_store_clear (GTK_LIST_STORE (model));
 
4420
    }
 
4421
 
 
4422
  gm_gradient_get_list ();
 
4423
 
 
4424
  tmp = gradient_menus;
 
4425
  while (tmp)
 
4426
    {
 
4427
      gm  = tmp->data;
 
4428
      tmp = tmp->next;
 
4429
 
 
4430
      gm_gradient_combo_fill (gm, gm->gradient_name);
 
4431
    }
 
4432
}
 
4433
 
 
4434
static GradientMenu *
 
4435
gradient_menu_new (GradientMenuCallback callback,
 
4436
                   gpointer             callback_data,
 
4437
                   const gchar         *default_gradient_name)
 
4438
{
 
4439
  GradientMenu *gm = g_new (GradientMenu, 1);
 
4440
 
 
4441
  gm->callback = callback;
 
4442
  gm->callback_data = callback_data;
 
4443
 
 
4444
  gm->preview = gimp_preview_area_new ();
 
4445
  gtk_widget_set_size_request (gm->preview,
 
4446
                               GM_PREVIEW_WIDTH, GM_PREVIEW_HEIGHT);
 
4447
 
 
4448
  gm->combo = g_object_new (GIMP_TYPE_INT_COMBO_BOX, NULL);
 
4449
 
 
4450
  g_signal_connect (gm->combo, "changed",
 
4451
                    G_CALLBACK (gm_gradient_combo_callback),
 
4452
                    gm);
 
4453
 
 
4454
  gm_gradient_combo_fill (gm, default_gradient_name);
 
4455
 
 
4456
  gtk_widget_show (gm->preview);
 
4457
  gtk_widget_show (gm->combo);
 
4458
 
 
4459
  g_signal_connect (gm->combo, "destroy",
 
4460
                    G_CALLBACK (gm_combo_destroy_callback),
 
4461
                    gm);
 
4462
 
 
4463
  gradient_menus = g_list_append (gradient_menus, gm);
 
4464
 
 
4465
  return gm;
 
4466
}
 
4467
 
 
4468
/* Local Functions */
 
4469
 
 
4470
static void
 
4471
gm_gradient_get_list (void)
 
4472
{
 
4473
  int   i;
 
4474
 
 
4475
  if (gradient_names)
 
4476
    {
 
4477
      for (i = 0; i < num_gradient_names; i++)
 
4478
        g_free (gradient_names[i]);
 
4479
      g_free (gradient_names);
 
4480
    }
 
4481
 
 
4482
  gradient_cache_flush ();      /* to make sure */
 
4483
  gradient_names = gradient_get_list (&num_gradient_names);
 
4484
}
 
4485
 
 
4486
static void
 
4487
gm_gradient_combo_fill (GradientMenu *gm,
 
4488
                        const gchar  *default_gradient)
 
4489
{
 
4490
  gint active = 0;
 
4491
  gint i;
 
4492
 
 
4493
  for (i = 0; i < num_gradient_names; i++)
 
4494
    {
 
4495
      const gchar *name = gradient_names[i];
 
4496
 
 
4497
      if (strcmp (name, default_gradient) == 0)
 
4498
        active = i;
 
4499
 
 
4500
      gimp_int_combo_box_append (GIMP_INT_COMBO_BOX (gm->combo),
 
4501
                                 GIMP_INT_STORE_VALUE, i,
 
4502
                                 GIMP_INT_STORE_LABEL, name,
 
4503
                                 -1);
 
4504
    }
 
4505
 
 
4506
  gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (gm->combo), active);
 
4507
}
 
4508
 
 
4509
static void
 
4510
gm_gradient_combo_callback (GtkWidget *widget,
 
4511
                            gpointer   data)
 
4512
{
 
4513
  GradientMenu *gm = data;
 
4514
  const gchar  *gradient_name;
 
4515
  gint          index;
 
4516
 
 
4517
  if (! gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &index) ||
 
4518
      index < 0 ||
 
4519
      index >= num_gradient_names)
 
4520
    return;
 
4521
 
 
4522
  gradient_name = gradient_names[index];
 
4523
 
 
4524
  DEBUG_PRINT(("gm_combo_callback\n"));
 
4525
 
 
4526
  gradient_name_copy (gm->gradient_name, gradient_name);
 
4527
 
 
4528
  gm_preview_draw (gm->preview, gradient_name);
 
4529
 
 
4530
  if (gm->callback)
 
4531
    (* gm->callback) (gradient_name, gm->callback_data);
 
4532
}
 
4533
 
 
4534
static void
 
4535
gm_preview_draw (GtkWidget   *preview,
 
4536
                 const gchar *gradient_name)
 
4537
{
 
4538
  guchar      values[GM_PREVIEW_WIDTH][4];
 
4539
  gint        nvalues = GM_PREVIEW_WIDTH;
 
4540
  gint        row, irow, col;
 
4541
  guchar      dest_row[GM_PREVIEW_WIDTH][3];
 
4542
  guchar     *dest;
 
4543
  guchar     *src;
 
4544
  gint        check, b;
 
4545
  guchar     *dest_total_preview_buffer;
 
4546
  const gint  alpha = 3;
 
4547
 
 
4548
  gradient_get_values (gradient_name, (guchar *)values, nvalues);
 
4549
 
 
4550
  dest_total_preview_buffer = g_new (guchar,
 
4551
                                     GM_PREVIEW_HEIGHT * GM_PREVIEW_WIDTH * 3);
 
4552
 
 
4553
  for (row = 0; row < GM_PREVIEW_HEIGHT; row += GIMP_CHECK_SIZE_SM)
 
4554
    {
 
4555
      for (col = 0; col < GM_PREVIEW_WIDTH; col++)
 
4556
        {
 
4557
          dest = dest_row[col];
 
4558
          src  = values[col];
 
4559
 
 
4560
          if (src[alpha] == OPAQUE)
 
4561
            {
 
4562
              /* no alpha channel or opaque -- simple way */
 
4563
              for (b = 0; b < alpha; b++)
 
4564
                dest[b] = src[b];
 
4565
            }
 
4566
          else
 
4567
            {
 
4568
              /* more or less transparent */
 
4569
              if((col % (GIMP_CHECK_SIZE) < GIMP_CHECK_SIZE_SM) ^
 
4570
                  (row % (GIMP_CHECK_SIZE) < GIMP_CHECK_SIZE_SM))
 
4571
                {
 
4572
                  check = GIMP_CHECK_LIGHT * 255;
 
4573
                }
 
4574
              else
 
4575
                {
 
4576
                  check = GIMP_CHECK_DARK * 255;
 
4577
                }
 
4578
 
 
4579
              if (src[alpha] == 0)
 
4580
                {
 
4581
                  /* full transparent -- check */
 
4582
                  for (b = 0; b < alpha; b++)
 
4583
                    dest[b] = check;
 
4584
                }
 
4585
              else
 
4586
                {
 
4587
                  /* middlemost transparent -- mix check and src */
 
4588
                  for (b = 0; b < alpha; b++)
 
4589
                    dest[b] = (src[b] * src[alpha] +
 
4590
                               check * (OPAQUE - src[alpha])) / OPAQUE;
 
4591
                }
 
4592
            }
 
4593
        }
 
4594
 
 
4595
      for (irow = 0;
 
4596
           irow < GIMP_CHECK_SIZE_SM && row + irow < GM_PREVIEW_HEIGHT;
 
4597
           irow++)
 
4598
        {
 
4599
          memcpy (dest_total_preview_buffer + (row+irow) * 3 * GM_PREVIEW_WIDTH,
 
4600
                  dest_row,
 
4601
                  GM_PREVIEW_WIDTH * 3);
 
4602
        }
 
4603
    }
 
4604
 
 
4605
    gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview),
 
4606
                            0, 0, GM_PREVIEW_WIDTH, GM_PREVIEW_HEIGHT,
 
4607
                            GIMP_RGB_IMAGE,
 
4608
                            (const guchar *) dest_total_preview_buffer,
 
4609
                            GM_PREVIEW_WIDTH * 3);
 
4610
 
 
4611
    g_free (dest_total_preview_buffer);
 
4612
}
 
4613
 
 
4614
static void
 
4615
gm_combo_destroy_callback (GtkWidget *w,
 
4616
                           gpointer   data)
 
4617
{
 
4618
  GradientMenu *gm = data;
 
4619
  gradient_menus = g_list_remove (gradient_menus, gm);
 
4620
}
 
4621
 
 
4622
/*************************************************************************/
 
4623
/**                                                                     **/
 
4624
/**                     +++ Gradients                                   **/
 
4625
/**                                                                     **/
 
4626
/*************************************************************************/
 
4627
 
 
4628
/*
 
4629
    Manage both internal and external gradients: list up, cache,
 
4630
    sampling, etc.
 
4631
 
 
4632
    External gradients are cached.
 
4633
 */
 
4634
 
 
4635
 
 
4636
static void
 
4637
gradient_name_copy (gchar       *dest,
 
4638
                    const gchar *src)
 
4639
{
 
4640
  strncpy (dest, src, GRADIENT_NAME_MAX);
 
4641
  dest[GRADIENT_NAME_MAX-1] = '\0';
 
4642
}
 
4643
 
 
4644
/*
 
4645
  Translate SPACE to "\\040", etc.
 
4646
 */
 
4647
static void
 
4648
gradient_name_encode (gchar       *dest,
 
4649
                      const gchar *src)
 
4650
{
 
4651
  gint cnt = GRADIENT_NAME_MAX - 1;
 
4652
 
 
4653
  while (*src && cnt--)
 
4654
    {
 
4655
      if (g_ascii_iscntrl (*src) || g_ascii_isspace (*src) || *src == '\\')
 
4656
        {
 
4657
          sprintf (dest, "\\%03o", *src++);
 
4658
          dest += 4;
 
4659
        }
 
4660
      else
 
4661
        *dest++ = *src++;
 
4662
    }
 
4663
  *dest = '\0';
 
4664
}
 
4665
 
 
4666
/*
 
4667
  Translate "\\040" to SPACE, etc.
 
4668
 */
 
4669
static void
 
4670
gradient_name_decode (gchar       *dest,
 
4671
                      const gchar *src)
 
4672
{
 
4673
  gint  cnt = GRADIENT_NAME_MAX - 1;
 
4674
  guint tmp;
 
4675
 
 
4676
  while (*src && cnt--)
 
4677
    {
 
4678
      if (*src == '\\' && *(src+1) && *(src+2) && *(src+3))
 
4679
        {
 
4680
          sscanf (src+1, "%3o", &tmp);
 
4681
          *dest++ = tmp;
 
4682
          src += 4;
 
4683
        }
 
4684
      else
 
4685
        *dest++ = *src++;
 
4686
    }
 
4687
  *dest = '\0';
 
4688
}
 
4689
 
 
4690
static void
 
4691
gradient_init (void)
 
4692
{
 
4693
  gradient_cache_head = NULL;
 
4694
  gradient_cache_count = 0;
 
4695
}
 
4696
 
 
4697
static void
 
4698
gradient_free (void)
 
4699
{
 
4700
  gradient_cache_flush ();
 
4701
}
 
4702
 
 
4703
static gchar **
 
4704
gradient_get_list (gint *num_gradients)
 
4705
{
 
4706
  gchar **gradients;
 
4707
  gchar **external_gradients = NULL;
 
4708
  gint    external_ngradients = 0;
 
4709
  gint    i, n;
 
4710
 
 
4711
  gradient_cache_flush ();
 
4712
  external_gradients = gimp_gradients_get_list (NULL, &external_ngradients);
 
4713
 
 
4714
  *num_gradients = G_N_ELEMENTS (internal_gradients) + external_ngradients;
 
4715
  gradients = g_new (gchar *, *num_gradients);
 
4716
 
 
4717
  n = 0;
 
4718
  for (i = 0; i < G_N_ELEMENTS (internal_gradients); i++)
 
4719
    {
 
4720
      gradients[n++] = g_strdup (internal_gradients[i]);
 
4721
    }
 
4722
  for (i = 0; i < external_ngradients; i++)
 
4723
    {
 
4724
      gradients[n++] = g_strdup (external_gradients[i]);
 
4725
    }
 
4726
 
 
4727
  return gradients;
 
4728
}
 
4729
 
 
4730
static void
 
4731
gradient_get_values (const gchar *gradient_name,
 
4732
                     guchar      *values,
 
4733
                     gint         nvalues)
 
4734
{
 
4735
  /*
 
4736
    Criteria to distinguish internal and external is rather simple here.
 
4737
    It should be fixed later.
 
4738
   */
 
4739
  if (gradient_name[0] == '%')
 
4740
    gradient_get_values_internal (gradient_name, values, nvalues);
 
4741
  else
 
4742
    gradient_get_values_external (gradient_name, values, nvalues);
 
4743
}
 
4744
 
 
4745
static void
 
4746
gradient_get_values_internal (const gchar *gradient_name,
 
4747
                              guchar      *values,
 
4748
                              gint         nvalues)
 
4749
{
 
4750
  const guchar white[4]        = { 255, 255, 255, 255 };
 
4751
  const guchar white_trans[4]  = { 255, 255, 255, 0   };
 
4752
  const guchar red_trans[4]    = { 255, 0,   0,   0   };
 
4753
  const guchar blue_trans[4]   = { 0,   0,   255, 0   };
 
4754
  const guchar yellow_trans[4] = { 255, 255, 0,   0   };
 
4755
 
 
4756
  /*
 
4757
    The internal gradients here are example --
 
4758
    What kind of internals would be useful ?
 
4759
   */
 
4760
  if(!strcmp(gradient_name, "%white"))
 
4761
    {
 
4762
      gradient_get_blend (white, white, values, nvalues);
 
4763
    }
 
4764
  else if(!strcmp(gradient_name, "%white_grad"))
 
4765
    {
 
4766
      gradient_get_blend (white, white_trans, values, nvalues);
 
4767
    }
 
4768
  else if (!strcmp (gradient_name, "%red_grad"))
 
4769
    {
 
4770
      gradient_get_blend (white, red_trans, values, nvalues);
 
4771
    }
 
4772
  else if (!strcmp (gradient_name, "%blue_grad"))
 
4773
    {
 
4774
      gradient_get_blend (white, blue_trans, values, nvalues);
 
4775
    }
 
4776
  else if (!strcmp (gradient_name, "%yellow_grad"))
 
4777
    {
 
4778
      gradient_get_blend (white, yellow_trans, values, nvalues);
 
4779
    }
 
4780
  else if (!strcmp (gradient_name, "%random"))
 
4781
    {
 
4782
      gradient_get_random (values, nvalues);
 
4783
    }
 
4784
  else
 
4785
    {
 
4786
      gradient_get_default (gradient_name, values, nvalues);
 
4787
    }
 
4788
}
 
4789
 
 
4790
static void
 
4791
gradient_get_blend (const guchar *fg,
 
4792
                    const guchar *bg,
 
4793
                    guchar       *values,
 
4794
                    gint          nvalues)
 
4795
{
 
4796
  gdouble  x;
 
4797
  gint     i;
 
4798
  gint     j;
 
4799
  guchar  *v = values;
 
4800
 
 
4801
  for (i = 0; i < nvalues; i++)
 
4802
    {
 
4803
      x = (double) i / nvalues;
 
4804
      for (j = 0; j < 4; j++)
 
4805
        *v++ = fg[j] * (1 - x) + bg[j] * x;
 
4806
    }
 
4807
}
 
4808
 
 
4809
static void
 
4810
gradient_get_random (guchar *values,
 
4811
                     gint    nvalues)
 
4812
{
 
4813
  gint    i;
 
4814
  gint    j;
 
4815
  gint    inten;
 
4816
  guchar *v = values;
 
4817
 
 
4818
  /*
 
4819
    This is really simple  -- gaussian noise might be better
 
4820
   */
 
4821
  for (i = 0; i < nvalues; i++)
 
4822
    {
 
4823
      inten = g_random_int_range (0, 256);
 
4824
      for (j = 0; j < 3; j++)
 
4825
        *v++ = inten;
 
4826
      *v++ = 255;
 
4827
    }
 
4828
}
 
4829
 
 
4830
static void
 
4831
gradient_get_default (const gchar *name,
 
4832
                      guchar      *values,
 
4833
                      gint         nvalues)
 
4834
{
 
4835
  gdouble  e[3];
 
4836
  gdouble  x;
 
4837
  gint     i;
 
4838
  gint     j;
 
4839
  guchar  *v = values;
 
4840
 
 
4841
  /*
 
4842
    Create gradient by name
 
4843
   */
 
4844
  name++;
 
4845
  for (j = 0; j < 3; j++)
 
4846
    e[j] = name[j] / 255.0;
 
4847
 
 
4848
  for (i = 0; i < nvalues; i++)
 
4849
    {
 
4850
      x = (double) i / nvalues;
 
4851
      for (j = 0; j < 3; j++)
 
4852
        *v++ = 255 * pow (x, e[j]);
 
4853
      *v++ = 255;
 
4854
    }
 
4855
}
 
4856
 
 
4857
/*
 
4858
  Caching gradients is really needed. It really takes 0.2 seconds each
 
4859
  time to resample an external gradient. (And this plug-in has
 
4860
  currently 6 gradient menus.)
 
4861
 
 
4862
  However, this caching routine is not too good. It picks up just
 
4863
  GRADIENT_RESOLUTION samples everytime, and rescales it later.  And
 
4864
  cached values are stored in guchar array. No accuracy.
 
4865
 */
 
4866
static void
 
4867
gradient_get_values_external (const gchar *gradient_name,
 
4868
                              guchar      *values,
 
4869
                              gint         nvalues)
 
4870
{
 
4871
  GradientCacheItem *ci;
 
4872
  gboolean           found;
 
4873
#ifdef DEBUG
 
4874
  clock_t            clk = clock ();
 
4875
#endif
 
4876
 
 
4877
  g_return_if_fail (nvalues >= 2);
 
4878
 
 
4879
  ci = gradient_cache_lookup (gradient_name, &found);
 
4880
  if (!found)
 
4881
    {
 
4882
#ifdef __GNUC__
 
4883
#warning FIXME: "reverse" hardcoded to FALSE.
 
4884
#endif
 
4885
      gradient_get_values_real_external (gradient_name, ci->values,
 
4886
                                         GRADIENT_RESOLUTION, FALSE);
 
4887
    }
 
4888
  if (nvalues == GRADIENT_RESOLUTION)
 
4889
    {
 
4890
      memcpy (values, ci->values, 4 * GRADIENT_RESOLUTION);
 
4891
    }
 
4892
  else
 
4893
    {
 
4894
      double    pos, frac;
 
4895
      int       ipos;
 
4896
      int       i, j;
 
4897
 
 
4898
      for (i = 0; i < nvalues; i++)
 
4899
        {
 
4900
          pos = ((double) i / (nvalues - 1)) * (GRADIENT_RESOLUTION - 1);
 
4901
          g_assert (0 <= pos && pos <= GRADIENT_RESOLUTION - 1);
 
4902
          ipos = (int) pos; frac = pos - ipos;
 
4903
          if (frac == 0.0)
 
4904
            {
 
4905
              memcpy (&values[4 * i], &ci->values[4 * ipos], 4);
 
4906
            }
 
4907
          else
 
4908
            for (j = 0; j < 4; j++)
 
4909
              values[4 * i + j] = ci->values[4 * ipos + j] * (1 - frac)
 
4910
                                + ci->values[4 * (ipos + 1) + j] * frac;
 
4911
        }
 
4912
    }
 
4913
 
 
4914
#ifdef DEBUG
 
4915
  get_values_external_clock += clock () - clk;
 
4916
  get_values_external_count ++;
 
4917
#endif
 
4918
 
 
4919
}
 
4920
 
 
4921
static void
 
4922
gradient_get_values_real_external (const gchar *gradient_name,
 
4923
                                   guchar      *values,
 
4924
                                   gint         nvalues,
 
4925
                                   gboolean     reverse)
 
4926
{
 
4927
  gint     n_tmp_values;
 
4928
  gdouble *tmp_values;
 
4929
  gint     i;
 
4930
  gint     j;
 
4931
 
 
4932
  gimp_gradient_get_uniform_samples (gradient_name, nvalues, reverse,
 
4933
                                     &n_tmp_values, &tmp_values);
 
4934
 
 
4935
  for (i = 0; i < nvalues; i++)
 
4936
    for (j = 0; j < 4; j++)
 
4937
      values[4 * i + j] = (guchar) (tmp_values[4 * i + j] * 255);
 
4938
 
 
4939
  g_free (tmp_values);
 
4940
}
 
4941
 
 
4942
void
 
4943
gradient_cache_flush (void)
 
4944
{
 
4945
  GradientCacheItem *ci;
 
4946
  GradientCacheItem *tmp;
 
4947
 
 
4948
  ci = gradient_cache_head;
 
4949
  while (ci)
 
4950
    {
 
4951
      tmp = ci->next;
 
4952
      g_free (ci);
 
4953
      ci = tmp;
 
4954
    }
 
4955
  gradient_cache_head = NULL;
 
4956
  gradient_cache_count = 0;
 
4957
}
 
4958
 
 
4959
static GradientCacheItem *
 
4960
gradient_cache_lookup (const gchar *name,
 
4961
                       gboolean    *found)
 
4962
{
 
4963
  GradientCacheItem *ci;
 
4964
 
 
4965
  ci = gradient_cache_head;
 
4966
  while (ci)
 
4967
    {
 
4968
      if (!strcmp (ci->name, name))
 
4969
        break;
 
4970
      ci = ci->next;
 
4971
    }
 
4972
  if (ci)
 
4973
    {
 
4974
      *found = TRUE;
 
4975
      if (!ci->prev)
 
4976
        {
 
4977
          g_assert (ci == gradient_cache_head);
 
4978
          return ci;
 
4979
        }
 
4980
      ci->prev->next = ci->next;
 
4981
      if (ci->next)
 
4982
        ci->next->prev = ci->prev;
 
4983
      ci->next = gradient_cache_head;
 
4984
      gradient_cache_head->prev = ci;
 
4985
      gradient_cache_head = ci;
 
4986
      ci->prev = NULL;
 
4987
      return ci;
 
4988
    }
 
4989
  else
 
4990
    {
 
4991
      *found = FALSE;
 
4992
      while (gradient_cache_count >= GRADIENT_CACHE_SIZE)
 
4993
        gradient_cache_zorch();
 
4994
      ci = g_new (GradientCacheItem, 1);
 
4995
      strncpy (ci->name, name, GRADIENT_NAME_MAX - 1);
 
4996
      ci->next = gradient_cache_head;
 
4997
      ci->prev = NULL;
 
4998
      if (gradient_cache_head)
 
4999
        gradient_cache_head->prev = ci;
 
5000
      gradient_cache_head = ci;
 
5001
      ++gradient_cache_count;
 
5002
      return ci;
 
5003
    }
 
5004
}
 
5005
 
 
5006
static void
 
5007
gradient_cache_zorch (void)
 
5008
{
 
5009
  GradientCacheItem *ci = gradient_cache_head;
 
5010
 
 
5011
  while (ci && ci->next)
 
5012
    {
 
5013
      ci = ci->next;
 
5014
    }
 
5015
  if (ci)
 
5016
    {
 
5017
      g_assert (ci->next == NULL);
 
5018
      if (ci->prev)
 
5019
        ci->prev->next = NULL;
 
5020
      else
 
5021
        gradient_cache_head = NULL;
 
5022
      g_free (ci);
 
5023
      --gradient_cache_count;
 
5024
    }
 
5025
}
 
5026
 
 
5027
#ifdef DEBUG
 
5028
void
 
5029
gradient_report (void)
 
5030
{
 
5031
  double total = (double) get_values_external_clock / CLOCKS_PER_SEC;
 
5032
 
 
5033
  g_printerr ("gradient_get_values_external "
 
5034
              "%.2f sec. / %d times (ave %.2f sec.)\n",
 
5035
              total,
 
5036
              get_values_external_count,
 
5037
              total / get_values_external_count);
 
5038
}
 
5039
#endif