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

« back to all changes in this revision

Viewing changes to app/core/gimpbrushgenerated.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2007-05-02 16:33:03 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070502163303-bvzhjzbpw8qglc4y
Tags: 2.3.16-1ubuntu1
* Resynchronized with Debian, remaining Ubuntu changes:
  - debian/rules: i18n magic.
* debian/control.in:
  - Maintainer: Ubuntu Core Developers <ubuntu-devel@lists.ubuntu.com>
* debian/patches/02_help-message.patch,
  debian/patches/03_gimp.desktop.in.in.patch,
  debian/patches/10_dont_show_wizard.patch: updated.
* debian/patches/04_composite-signedness.patch,
  debian/patches/05_add-letter-spacing.patch: dropped, used upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* The GIMP -- an image manipulation program
 
1
/* GIMP - The GNU Image Manipulation Program
2
2
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3
3
 *
4
4
 * gimp_brush_generated module Copyright 1998 Jay Cox <jaycox@earthlink.net>
20
20
 
21
21
#include "config.h"
22
22
 
23
 
#include <errno.h>
24
 
#include <stdio.h>
25
 
#include <stdlib.h>
26
 
#include <string.h>
27
 
 
28
 
#ifdef HAVE_UNISTD_H
29
 
#include <unistd.h>
30
 
#endif
31
 
 
32
23
#include <glib-object.h>
33
24
 
34
25
#include "libgimpbase/gimpbase.h"
39
30
#include "base/temp-buf.h"
40
31
 
41
32
#include "gimpbrushgenerated.h"
42
 
 
43
 
#include "gimp-intl.h"
44
 
 
45
 
 
46
 
#define OVERSAMPLING 5
 
33
#include "gimpbrushgenerated-load.h"
 
34
#include "gimpbrushgenerated-save.h"
 
35
 
 
36
 
 
37
#define OVERSAMPLING 4
47
38
 
48
39
 
49
40
enum
60
51
 
61
52
/*  local function prototypes  */
62
53
 
63
 
static void   gimp_brush_generated_class_init (GimpBrushGeneratedClass *klass);
64
 
static void   gimp_brush_generated_init       (GimpBrushGenerated      *brush);
65
 
 
66
54
static void       gimp_brush_generated_set_property  (GObject      *object,
67
55
                                                      guint         property_id,
68
56
                                                      const GValue *value,
71
59
                                                      guint         property_id,
72
60
                                                      GValue       *value,
73
61
                                                      GParamSpec   *pspec);
74
 
static gboolean   gimp_brush_generated_save          (GimpData     *data,
75
 
                                                      GError      **error);
76
62
static void       gimp_brush_generated_dirty         (GimpData     *data);
77
63
static gchar    * gimp_brush_generated_get_extension (GimpData     *data);
78
 
static GimpData * gimp_brush_generated_duplicate     (GimpData     *data,
79
 
                                                      gboolean      stingy_memory_use);
80
 
 
81
 
 
82
 
static GimpBrushClass *parent_class = NULL;
83
 
 
84
 
 
85
 
GType
86
 
gimp_brush_generated_get_type (void)
87
 
{
88
 
  static GType brush_type = 0;
89
 
 
90
 
  if (! brush_type)
91
 
    {
92
 
      static const GTypeInfo brush_info =
93
 
      {
94
 
        sizeof (GimpBrushGeneratedClass),
95
 
        (GBaseInitFunc) NULL,
96
 
        (GBaseFinalizeFunc) NULL,
97
 
        (GClassInitFunc) gimp_brush_generated_class_init,
98
 
        NULL,           /* class_finalize */
99
 
        NULL,           /* class_data     */
100
 
        sizeof (GimpBrushGenerated),
101
 
        0,              /* n_preallocs    */
102
 
        (GInstanceInitFunc) gimp_brush_generated_init,
103
 
      };
104
 
 
105
 
      brush_type = g_type_register_static (GIMP_TYPE_BRUSH,
106
 
                                           "GimpBrushGenerated",
107
 
                                           &brush_info, 0);
108
 
    }
109
 
 
110
 
  return brush_type;
111
 
}
 
64
static GimpData * gimp_brush_generated_duplicate     (GimpData     *data);
 
65
static TempBuf  * gimp_brush_generated_scale_mask    (GimpBrush    *gbrush,
 
66
                                                      gdouble       scale);
 
67
static void       gimp_brush_generated_get_half_size (GimpBrushGenerated      *gbrush,
 
68
                                                      GimpBrushGeneratedShape  shape,
 
69
                                                      gfloat                   radius,
 
70
                                                      gint                     spikes,
 
71
                                                      gfloat                   hardness,
 
72
                                                      gfloat                   aspect_ratio,
 
73
                                                      gdouble                  angle_in_degrees,
 
74
                                                      gint                    *half_width,
 
75
                                                      gint                    *half_height,
 
76
                                                      gdouble                 *_s,
 
77
                                                      gdouble                 *_c,
 
78
                                                      GimpVector2             *_x_axis,
 
79
                                                      GimpVector2             *_y_axis);
 
80
static void       gimp_brush_generated_real_scale_size
 
81
                                                     (GimpBrush  *gbrush,
 
82
                                                      gdouble     scale,
 
83
                                                      gint       *width,
 
84
                                                      gint       *height);
 
85
 
 
86
 
 
87
G_DEFINE_TYPE (GimpBrushGenerated, gimp_brush_generated, GIMP_TYPE_BRUSH)
 
88
 
 
89
#define parent_class gimp_brush_generated_parent_class
 
90
 
112
91
 
113
92
static void
114
93
gimp_brush_generated_class_init (GimpBrushGeneratedClass *klass)
115
94
{
116
 
  GObjectClass  *object_class = G_OBJECT_CLASS (klass);
117
 
  GimpDataClass *data_class   = GIMP_DATA_CLASS (klass);
118
 
 
119
 
  parent_class = g_type_class_peek_parent (klass);
120
 
 
121
 
  object_class->set_property = gimp_brush_generated_set_property;
122
 
  object_class->get_property = gimp_brush_generated_get_property;
123
 
 
124
 
  data_class->save           = gimp_brush_generated_save;
125
 
  data_class->dirty          = gimp_brush_generated_dirty;
126
 
  data_class->get_extension  = gimp_brush_generated_get_extension;
127
 
  data_class->duplicate      = gimp_brush_generated_duplicate;
 
95
  GObjectClass   *object_class = G_OBJECT_CLASS (klass);
 
96
  GimpDataClass  *data_class   = GIMP_DATA_CLASS (klass);
 
97
  GimpBrushClass *brush_class  = GIMP_BRUSH_CLASS (klass);
 
98
 
 
99
  object_class->set_property   = gimp_brush_generated_set_property;
 
100
  object_class->get_property   = gimp_brush_generated_get_property;
 
101
 
 
102
  data_class->save             = gimp_brush_generated_save;
 
103
  data_class->dirty            = gimp_brush_generated_dirty;
 
104
  data_class->get_extension    = gimp_brush_generated_get_extension;
 
105
  data_class->duplicate        = gimp_brush_generated_duplicate;
 
106
 
 
107
  brush_class->scale_size      = gimp_brush_generated_real_scale_size;
 
108
  brush_class->scale_mask      = gimp_brush_generated_scale_mask;
128
109
 
129
110
  g_object_class_install_property (object_class, PROP_SHAPE,
130
111
                                   g_param_spec_enum ("shape", NULL, NULL,
131
112
                                                      GIMP_TYPE_BRUSH_GENERATED_SHAPE,
132
113
                                                      GIMP_BRUSH_GENERATED_CIRCLE,
133
 
                                                      G_PARAM_READWRITE |
 
114
                                                      GIMP_PARAM_READWRITE |
134
115
                                                      G_PARAM_CONSTRUCT));
135
116
  g_object_class_install_property (object_class, PROP_RADIUS,
136
117
                                   g_param_spec_double ("radius", NULL, NULL,
137
 
                                                        0.1, 1000.0, 5.0,
138
 
                                                        G_PARAM_READWRITE |
 
118
                                                        0.1, 4000.0, 5.0,
 
119
                                                        GIMP_PARAM_READWRITE |
139
120
                                                        G_PARAM_CONSTRUCT));
140
121
  g_object_class_install_property (object_class, PROP_SPIKES,
141
122
                                   g_param_spec_int    ("spikes", NULL, NULL,
142
123
                                                        2, 20, 2,
143
 
                                                        G_PARAM_READWRITE |
 
124
                                                        GIMP_PARAM_READWRITE |
144
125
                                                        G_PARAM_CONSTRUCT));
145
126
  g_object_class_install_property (object_class, PROP_HARDNESS,
146
127
                                   g_param_spec_double ("hardness", NULL, NULL,
147
128
                                                        0.0, 1.0, 0.0,
148
 
                                                        G_PARAM_READWRITE |
 
129
                                                        GIMP_PARAM_READWRITE |
149
130
                                                        G_PARAM_CONSTRUCT));
150
131
  g_object_class_install_property (object_class, PROP_ASPECT_RATIO,
151
132
                                   g_param_spec_double ("aspect-ratio",
152
133
                                                        NULL, NULL,
153
134
                                                        1.0, 20.0, 1.0,
154
 
                                                        G_PARAM_READWRITE |
 
135
                                                        GIMP_PARAM_READWRITE |
155
136
                                                        G_PARAM_CONSTRUCT));
156
137
  g_object_class_install_property (object_class, PROP_ANGLE,
157
138
                                   g_param_spec_double ("angle", NULL, NULL,
158
139
                                                        0.0, 180.0, 0.0,
159
 
                                                        G_PARAM_READWRITE |
 
140
                                                        GIMP_PARAM_READWRITE |
160
141
                                                        G_PARAM_CONSTRUCT));
161
142
}
162
143
 
238
219
    }
239
220
}
240
221
 
241
 
static gboolean
242
 
gimp_brush_generated_save (GimpData  *data,
243
 
                           GError   **error)
244
 
{
245
 
  GimpBrushGenerated *brush = GIMP_BRUSH_GENERATED (data);
246
 
  FILE               *file;
247
 
  gchar               buf[G_ASCII_DTOSTR_BUF_SIZE];
248
 
  gboolean            have_shape = FALSE;
249
 
 
250
 
  file  = fopen (data->filename, "wb");
251
 
 
252
 
  if (! file)
253
 
    {
254
 
      g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_OPEN,
255
 
                   _("Could not open '%s' for writing: %s"),
256
 
                   gimp_filename_to_utf8 (data->filename),
257
 
                   g_strerror (errno));
258
 
      return FALSE;
259
 
    }
260
 
 
261
 
  /* write magic header */
262
 
  fprintf (file, "GIMP-VBR\n");
263
 
 
264
 
  /* write version */
265
 
  if (brush->shape != GIMP_BRUSH_GENERATED_CIRCLE || brush->spikes > 2)
266
 
    {
267
 
      fprintf (file, "1.5\n");
268
 
      have_shape = TRUE;
269
 
    }
270
 
  else
271
 
    {
272
 
      fprintf (file, "1.0\n");
273
 
    }
274
 
 
275
 
  /* write name */
276
 
  fprintf (file, "%.255s\n", GIMP_OBJECT (brush)->name);
277
 
 
278
 
  if (have_shape)
279
 
    {
280
 
      GEnumClass *enum_class;
281
 
      GEnumValue *shape_val;
282
 
 
283
 
      enum_class = g_type_class_peek (GIMP_TYPE_BRUSH_GENERATED_SHAPE);
284
 
 
285
 
      /* write shape */
286
 
      shape_val = g_enum_get_value (enum_class, brush->shape);
287
 
      fprintf (file, "%s\n", shape_val->value_nick);
288
 
    }
289
 
 
290
 
  /* write brush spacing */
291
 
  fprintf (file, "%s\n",
292
 
           g_ascii_formatd (buf, G_ASCII_DTOSTR_BUF_SIZE, "%f",
293
 
                            GIMP_BRUSH (brush)->spacing));
294
 
 
295
 
  /* write brush radius */
296
 
  fprintf (file, "%s\n",
297
 
           g_ascii_formatd (buf, G_ASCII_DTOSTR_BUF_SIZE, "%f",
298
 
                            brush->radius));
299
 
 
300
 
  if (have_shape)
301
 
    {
302
 
      /* write brush spikes */
303
 
      fprintf (file, "%d\n", brush->spikes);
304
 
    }
305
 
 
306
 
  /* write brush hardness */
307
 
  fprintf (file, "%s\n",
308
 
           g_ascii_formatd (buf, G_ASCII_DTOSTR_BUF_SIZE, "%f",
309
 
                            brush->hardness));
310
 
 
311
 
  /* write brush aspect_ratio */
312
 
  fprintf (file, "%s\n",
313
 
           g_ascii_formatd (buf, G_ASCII_DTOSTR_BUF_SIZE, "%f",
314
 
                            brush->aspect_ratio));
315
 
 
316
 
  /* write brush angle */
317
 
  fprintf (file, "%s\n",
318
 
           g_ascii_formatd (buf, G_ASCII_DTOSTR_BUF_SIZE, "%f",
319
 
                            brush->angle));
320
 
 
321
 
  fclose (file);
322
 
 
323
 
  return TRUE;
324
 
}
325
 
 
326
222
static gchar *
327
223
gimp_brush_generated_get_extension (GimpData *data)
328
224
{
330
226
}
331
227
 
332
228
static GimpData *
333
 
gimp_brush_generated_duplicate (GimpData *data,
334
 
                                gboolean  stingy_memory_use)
 
229
gimp_brush_generated_duplicate (GimpData *data)
335
230
{
336
231
  GimpBrushGenerated *brush = GIMP_BRUSH_GENERATED (data);
337
232
 
341
236
                                   brush->spikes,
342
237
                                   brush->hardness,
343
238
                                   brush->aspect_ratio,
344
 
                                   brush->angle,
345
 
                                   stingy_memory_use);
 
239
                                   brush->angle);
346
240
}
347
241
 
348
242
static gdouble
362
256
  return (2.0 * f*f);
363
257
}
364
258
 
365
 
static void
366
 
gimp_brush_generated_dirty (GimpData *data)
 
259
/* set up lookup table */
 
260
static guchar *
 
261
gimp_brush_generated_calc_lut (gdouble radius,
 
262
                               gdouble hardness)
367
263
{
368
 
  GimpBrushGenerated *brush  = GIMP_BRUSH_GENERATED (data);
369
 
  GimpBrush          *gbrush = GIMP_BRUSH (brush);
370
 
  gint                x, y;
371
 
  guchar             *centerp;
372
 
  gdouble             d;
373
 
  gdouble             exponent;
374
 
  guchar              a;
375
 
  gint                length;
376
 
  gint                width  = 0;
377
 
  gint                height = 0;
378
 
  guchar             *lookup;
379
 
  gdouble             sum;
380
 
  gdouble             c, s, cs, ss;
381
 
  gdouble             short_radius;
382
 
  gdouble             buffer[OVERSAMPLING];
383
 
 
384
 
  if (gbrush->mask)
385
 
    temp_buf_free (gbrush->mask);
386
 
 
387
 
  s = sin (gimp_deg_to_rad (brush->angle));
388
 
  c = cos (gimp_deg_to_rad (brush->angle));
389
 
 
390
 
  short_radius = brush->radius / brush->aspect_ratio;
391
 
 
392
 
  gbrush->x_axis.x =        c * brush->radius;
393
 
  gbrush->x_axis.y = -1.0 * s * brush->radius;
394
 
  gbrush->y_axis.x =        s * short_radius;
395
 
  gbrush->y_axis.y =        c * short_radius;
396
 
 
397
 
  switch (brush->shape)
398
 
    {
399
 
    case GIMP_BRUSH_GENERATED_CIRCLE:
400
 
      width  = ceil (sqrt (gbrush->x_axis.x * gbrush->x_axis.x +
401
 
                           gbrush->y_axis.x * gbrush->y_axis.x));
402
 
      height = ceil (sqrt (gbrush->x_axis.y * gbrush->x_axis.y +
403
 
                           gbrush->y_axis.y * gbrush->y_axis.y));
404
 
      break;
405
 
 
406
 
    case GIMP_BRUSH_GENERATED_SQUARE:
407
 
      width  = ceil (fabs (gbrush->x_axis.x) + fabs (gbrush->y_axis.x));
408
 
      height = ceil (fabs (gbrush->x_axis.y) + fabs (gbrush->y_axis.y));
409
 
      break;
410
 
 
411
 
    case GIMP_BRUSH_GENERATED_DIAMOND:
412
 
      width  = ceil (MAX (fabs (gbrush->x_axis.x), fabs (gbrush->y_axis.x)));
413
 
      height = ceil (MAX (fabs (gbrush->x_axis.y), fabs (gbrush->y_axis.y)));
414
 
      break;
415
 
 
416
 
    default:
417
 
      g_return_if_reached ();
418
 
    }
419
 
 
420
 
  if (brush->spikes > 2)
421
 
    {
422
 
      /* could be optimized by respecting the angle */
423
 
      width = height = ceil (sqrt (brush->radius * brush->radius +
424
 
                                   short_radius * short_radius));
425
 
      gbrush->y_axis.x =        s * brush->radius;
426
 
      gbrush->y_axis.y =        c * brush->radius;
427
 
    }
428
 
 
429
 
  gbrush->mask = temp_buf_new (width  * 2 + 1,
430
 
                               height * 2 + 1,
431
 
                               1, width, height, NULL);
432
 
 
433
 
  centerp = temp_buf_data (gbrush->mask) + height * gbrush->mask->width + width;
434
 
 
435
 
  /* set up lookup table */
436
 
  length = OVERSAMPLING * ceil (1 + sqrt (2 *
437
 
                                          ceil (brush->radius + 1.0) *
438
 
                                          ceil (brush->radius + 1.0)));
439
 
 
440
 
  if ((1.0 - brush->hardness) < 0.0000004)
441
 
    exponent = 1000000.0;
442
 
  else
443
 
    exponent = 0.4 / (1.0 - brush->hardness);
 
264
  guchar  *lookup;
 
265
  gint     length;
 
266
  gint     x;
 
267
  gdouble  d;
 
268
  gdouble  sum;
 
269
  gdouble  exponent;
 
270
  gdouble  buffer[OVERSAMPLING];
 
271
 
 
272
  length = OVERSAMPLING * ceil (1 + sqrt (2 * SQR (ceil (radius + 1.0))));
444
273
 
445
274
  lookup = g_malloc (length);
446
275
  sum = 0.0;
447
276
 
 
277
  if ((1.0 - hardness) < 0.0000004)
 
278
    exponent = 1000000.0;
 
279
  else
 
280
    exponent = 0.4 / (1.0 - hardness);
 
281
 
448
282
  for (x = 0; x < OVERSAMPLING; x++)
449
283
    {
450
284
      d = fabs ((x + 0.5) / OVERSAMPLING - 0.5);
451
285
 
452
 
      if (d > brush->radius)
 
286
      if (d > radius)
453
287
        buffer[x] = 0.0;
454
288
      else
455
 
        buffer[x] = gauss (pow (d / brush->radius, exponent));
 
289
        buffer[x] = gauss (pow (d / radius, exponent));
456
290
 
457
291
      sum += buffer[x];
458
292
    }
459
293
 
460
 
  for (x = 0; d < brush->radius || sum > 0.00001; d += 1.0 / OVERSAMPLING)
 
294
  for (x = 0; d < radius || sum > 0.00001; d += 1.0 / OVERSAMPLING)
461
295
    {
462
296
      sum -= buffer[x % OVERSAMPLING];
463
297
 
464
 
      if (d > brush->radius)
 
298
      if (d > radius)
465
299
        buffer[x % OVERSAMPLING] = 0.0;
466
300
      else
467
 
        buffer[x % OVERSAMPLING] = gauss (pow (d / brush->radius, exponent));
 
301
        buffer[x % OVERSAMPLING] = gauss (pow (d / radius, exponent));
468
302
 
469
303
      sum += buffer[x % OVERSAMPLING];
470
304
      lookup[x++] = RINT (sum * (255.0 / OVERSAMPLING));
475
309
      lookup[x++] = 0;
476
310
    }
477
311
 
478
 
  cs = cos (- 2 * G_PI / brush->spikes);
479
 
  ss = sin (- 2 * G_PI / brush->spikes);
 
312
  return lookup;
 
313
}
 
314
 
 
315
static TempBuf *
 
316
gimp_brush_generated_calc (GimpBrushGenerated      *brush,
 
317
                           GimpBrushGeneratedShape  shape,
 
318
                           gfloat                   radius,
 
319
                           gint                     spikes,
 
320
                           gfloat                   hardness,
 
321
                           gfloat                   aspect_ratio,
 
322
                           gfloat                   angle,
 
323
                           GimpVector2             *xaxis,
 
324
                           GimpVector2             *yaxis)
 
325
{
 
326
  guchar      *centerp;
 
327
  guchar      *lookup;
 
328
  guchar       a;
 
329
  gint         half_width  = 0;
 
330
  gint         half_height = 0;
 
331
  gint         x, y;
 
332
  gdouble      c, s, cs, ss;
 
333
  GimpVector2  x_axis;
 
334
  GimpVector2  y_axis;
 
335
  TempBuf     *mask;
 
336
 
 
337
  gimp_brush_generated_get_half_size (brush,
 
338
                                      shape,
 
339
                                      radius,
 
340
                                      spikes,
 
341
                                      hardness,
 
342
                                      aspect_ratio,
 
343
                                      angle,
 
344
                                      &half_width, &half_height,
 
345
                                      &s, &c, &x_axis, &y_axis);
 
346
 
 
347
  mask = temp_buf_new (half_width  * 2 + 1,
 
348
                       half_height * 2 + 1,
 
349
                       1, half_width, half_height, NULL);
 
350
 
 
351
  centerp = temp_buf_data (mask) + half_height * mask->width + half_width;
 
352
 
 
353
  lookup = gimp_brush_generated_calc_lut (radius, hardness);
 
354
 
 
355
  cs = cos (- 2 * G_PI / spikes);
 
356
  ss = sin (- 2 * G_PI / spikes);
480
357
 
481
358
  /* for an even number of spikes compute one half and mirror it */
482
 
  for (y = (brush->spikes % 2 ? -height : 0); y <= height; y++)
 
359
  for (y = (spikes % 2 ? -half_height : 0); y <= half_height; y++)
483
360
    {
484
 
      for (x = -width; x <= width; x++)
 
361
      for (x = -half_width; x <= half_width; x++)
485
362
        {
486
 
          gdouble tx, ty, angle;
487
 
 
488
 
          tx = c*x - s*y;
489
 
          ty = fabs (s*x + c*y);
490
 
 
491
 
          if (brush->spikes > 2)
 
363
          gdouble d  = 0;
 
364
          gdouble tx = c * x - s * y;
 
365
          gdouble ty = fabs (s * x + c * y);
 
366
 
 
367
          if (spikes > 2)
492
368
            {
493
 
              angle = atan2 (ty, tx);
 
369
              gdouble angle = atan2 (ty, tx);
494
370
 
495
 
              while (angle > G_PI / brush->spikes)
 
371
              while (angle > G_PI / spikes)
496
372
                {
497
 
                  gdouble sx = tx, sy = ty;
 
373
                  gdouble sx = tx;
 
374
                  gdouble sy = ty;
498
375
 
499
376
                  tx = cs * sx - ss * sy;
500
377
                  ty = ss * sx + cs * sy;
501
378
 
502
 
                  angle -= 2 * G_PI / brush->spikes;
 
379
                  angle -= 2 * G_PI / spikes;
503
380
                }
504
381
            }
505
382
 
506
 
          ty *= brush->aspect_ratio;
507
 
          switch (brush->shape)
 
383
          ty *= aspect_ratio;
 
384
 
 
385
          switch (shape)
508
386
            {
509
387
            case GIMP_BRUSH_GENERATED_CIRCLE:
510
 
              d = sqrt (tx*tx + ty*ty);
 
388
              d = sqrt (SQR (tx) + SQR (ty));
511
389
              break;
512
390
            case GIMP_BRUSH_GENERATED_SQUARE:
513
391
              d = MAX (fabs (tx), fabs (ty));
517
395
              break;
518
396
            }
519
397
 
520
 
          if (d < brush->radius + 1)
 
398
          if (d < radius + 1)
521
399
            a = lookup[(gint) RINT (d * OVERSAMPLING)];
522
400
          else
523
401
            a = 0;
524
402
 
525
 
          centerp[ y * gbrush->mask->width + x] = a;
 
403
          centerp[y * mask->width + x] = a;
526
404
 
527
 
          if (brush->spikes % 2 == 0)
528
 
            centerp[-1 * y * gbrush->mask->width - x] = a;
 
405
          if (spikes % 2 == 0)
 
406
            centerp[-1 * y * mask->width - x] = a;
529
407
        }
530
408
    }
531
409
 
532
410
  g_free (lookup);
533
411
 
534
 
  if (GIMP_DATA_CLASS (parent_class)->dirty)
535
 
    GIMP_DATA_CLASS (parent_class)->dirty (data);
 
412
  if (xaxis)
 
413
    *xaxis = x_axis;
 
414
 
 
415
  if (yaxis)
 
416
    *yaxis = y_axis;
 
417
 
 
418
  return mask;
 
419
}
 
420
 
 
421
static void
 
422
gimp_brush_generated_dirty (GimpData *data)
 
423
{
 
424
  GimpBrushGenerated *brush  = GIMP_BRUSH_GENERATED (data);
 
425
  GimpBrush          *gbrush = GIMP_BRUSH (brush);
 
426
 
 
427
  if (gbrush->mask)
 
428
    temp_buf_free (gbrush->mask);
 
429
 
 
430
  gbrush->mask = gimp_brush_generated_calc (brush,
 
431
                                            brush->shape,
 
432
                                            brush->radius,
 
433
                                            brush->spikes,
 
434
                                            brush->hardness,
 
435
                                            brush->aspect_ratio,
 
436
                                            brush->angle,
 
437
                                            &gbrush->x_axis,
 
438
                                            &gbrush->y_axis);
 
439
 
 
440
  GIMP_DATA_CLASS (parent_class)->dirty (data);
 
441
}
 
442
 
 
443
/* This function is shared between gimp_brush_scale_size and
 
444
 * gimp_brush_generated_calc, therefore we provide a bunch of optional
 
445
 * pointers for returnvalues.
 
446
 */
 
447
static void
 
448
gimp_brush_generated_get_half_size (GimpBrushGenerated      *gbrush,
 
449
                                    GimpBrushGeneratedShape  shape,
 
450
                                    gfloat                   radius,
 
451
                                    gint                     spikes,
 
452
                                    gfloat                   hardness,
 
453
                                    gfloat                   aspect_ratio,
 
454
                                    gdouble                  angle_in_degrees,
 
455
                                    gint                    *half_width,
 
456
                                    gint                    *half_height,
 
457
                                    gdouble                 *_s,
 
458
                                    gdouble                 *_c,
 
459
                                    GimpVector2             *_x_axis,
 
460
                                    GimpVector2             *_y_axis)
 
461
{
 
462
  gdouble      c, s;
 
463
  gdouble      short_radius;
 
464
  GimpVector2  x_axis;
 
465
  GimpVector2  y_axis;
 
466
 
 
467
  s = sin (gimp_deg_to_rad (angle_in_degrees));
 
468
  c = cos (gimp_deg_to_rad (angle_in_degrees));
 
469
 
 
470
  short_radius = radius / aspect_ratio;
 
471
 
 
472
  x_axis.x =        c * radius;
 
473
  x_axis.y = -1.0 * s * radius;
 
474
  y_axis.x =        s * short_radius;
 
475
  y_axis.y =        c * short_radius;
 
476
 
 
477
  switch (shape)
 
478
    {
 
479
    case GIMP_BRUSH_GENERATED_CIRCLE:
 
480
      *half_width  = ceil (sqrt (x_axis.x * x_axis.x + y_axis.x * y_axis.x));
 
481
      *half_height = ceil (sqrt (x_axis.y * x_axis.y + y_axis.y * y_axis.y));
 
482
      break;
 
483
 
 
484
    case GIMP_BRUSH_GENERATED_SQUARE:
 
485
      *half_width  = ceil (fabs (x_axis.x) + fabs (y_axis.x));
 
486
      *half_height = ceil (fabs (x_axis.y) + fabs (y_axis.y));
 
487
      break;
 
488
 
 
489
    case GIMP_BRUSH_GENERATED_DIAMOND:
 
490
      *half_width  = ceil (MAX (fabs (x_axis.x), fabs (y_axis.x)));
 
491
      *half_height = ceil (MAX (fabs (x_axis.y), fabs (y_axis.y)));
 
492
      break;
 
493
    }
 
494
 
 
495
  if (spikes > 2)
 
496
    {
 
497
      /* could be optimized by respecting the angle */
 
498
      *half_width = *half_height = ceil (sqrt (radius * radius +
 
499
                                               short_radius * short_radius));
 
500
      y_axis.x = s * radius;
 
501
      y_axis.y = c * radius;
 
502
    }
 
503
 
 
504
  /*  These will typically be set then this function is called by
 
505
   *  gimp_brush_generated_calc, which needs the values in its algorithms.
 
506
   */
 
507
  if (_s != NULL)
 
508
    *_s = s;
 
509
 
 
510
  if (_c != NULL)
 
511
    *_c = c;
 
512
 
 
513
  if (_x_axis != NULL)
 
514
    *_x_axis = x_axis;
 
515
 
 
516
  if (_y_axis != NULL)
 
517
    *_y_axis = y_axis;
 
518
}
 
519
 
 
520
static void
 
521
gimp_brush_generated_real_scale_size (GimpBrush  *gbrush,
 
522
                                      gdouble     scale,
 
523
                                      gint       *width,
 
524
                                      gint       *height)
 
525
{
 
526
  GimpBrushGenerated *brush = GIMP_BRUSH_GENERATED (gbrush);
 
527
  gint                half_width;
 
528
  gint                half_height;
 
529
 
 
530
  gimp_brush_generated_get_half_size (brush,
 
531
                                      brush->shape,
 
532
                                      brush->radius * scale,
 
533
                                      brush->spikes,
 
534
                                      brush->hardness,
 
535
                                      brush->aspect_ratio,
 
536
                                      brush->angle,
 
537
                                      &half_width, &half_height,
 
538
                                      NULL, NULL, NULL, NULL);
 
539
 
 
540
  *width  = half_width  * 2 + 1;
 
541
  *height = half_height * 2 + 1;
 
542
}
 
543
 
 
544
static TempBuf *
 
545
gimp_brush_generated_scale_mask (GimpBrush *gbrush,
 
546
                                 gdouble    scale)
 
547
{
 
548
  GimpBrushGenerated *brush  = GIMP_BRUSH_GENERATED (gbrush);
 
549
 
 
550
  return gimp_brush_generated_calc (brush,
 
551
                                    brush->shape,
 
552
                                    brush->radius * scale,
 
553
                                    brush->spikes,
 
554
                                    brush->hardness,
 
555
                                    brush->aspect_ratio,
 
556
                                    brush->angle,
 
557
                                    NULL, NULL);
536
558
}
537
559
 
538
560
GimpData *
542
564
                          gint                     spikes,
543
565
                          gfloat                   hardness,
544
566
                          gfloat                   aspect_ratio,
545
 
                          gfloat                   angle,
546
 
                          gboolean                 stingy_memory_use)
 
567
                          gfloat                   angle)
547
568
{
548
569
  GimpBrushGenerated *brush;
549
570
 
552
573
 
553
574
  brush = g_object_new (GIMP_TYPE_BRUSH_GENERATED,
554
575
                        "name",         name,
 
576
                        "mime-type",    "application/x-gimp-brush-generated",
 
577
                        "spacing",      20.0,
555
578
                        "shape",        shape,
556
579
                        "radius",       radius,
557
580
                        "spikes",       spikes,
560
583
                        "angle",        angle,
561
584
                        NULL);
562
585
 
563
 
  GIMP_BRUSH (brush)->spacing = 20;
564
 
 
565
 
  /* render brush mask */
566
 
  gimp_data_dirty (GIMP_DATA (brush));
567
 
 
568
 
  if (stingy_memory_use)
569
 
    temp_buf_swap (GIMP_BRUSH (brush)->mask);
570
 
 
571
586
  return GIMP_DATA (brush);
572
587
}
573
588
 
574
 
GList *
575
 
gimp_brush_generated_load (const gchar  *filename,
576
 
                           gboolean      stingy_memory_use,
577
 
                           GError      **error)
578
 
{
579
 
  GimpBrushGenerated      *brush;
580
 
  FILE                    *file;
581
 
  gchar                    string[256];
582
 
  gchar                   *name       = NULL;
583
 
  GimpBrushGeneratedShape  shape      = GIMP_BRUSH_GENERATED_CIRCLE;
584
 
  gboolean                 have_shape = FALSE;
585
 
  gint                     spikes     = 2;
586
 
  gdouble                  spacing;
587
 
  gdouble                  radius;
588
 
  gdouble                  hardness;
589
 
  gdouble                  aspect_ratio;
590
 
  gdouble                  angle;
591
 
 
592
 
  g_return_val_if_fail (filename != NULL, NULL);
593
 
  g_return_val_if_fail (g_path_is_absolute (filename), NULL);
594
 
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
595
 
 
596
 
  file = fopen (filename, "rb");
597
 
 
598
 
  if (! file)
599
 
    {
600
 
      g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_OPEN,
601
 
                   _("Could not open '%s' for reading: %s"),
602
 
                   gimp_filename_to_utf8 (filename), g_strerror (errno));
603
 
      return NULL;
604
 
    }
605
 
 
606
 
  /* make sure the file we are reading is the right type */
607
 
  errno = 0;
608
 
  if (! fgets (string, sizeof (string), file))
609
 
    goto failed;
610
 
 
611
 
  if (strncmp (string, "GIMP-VBR", 8) != 0)
612
 
    {
613
 
      g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
614
 
                   _("Fatal parse error in brush file '%s': "
615
 
                     "Not a GIMP brush file."),
616
 
                   gimp_filename_to_utf8 (filename));
617
 
      goto failed;
618
 
    }
619
 
 
620
 
  /* make sure we are reading a compatible version */
621
 
  errno = 0;
622
 
  if (! fgets (string, sizeof (string), file))
623
 
    goto failed;
624
 
 
625
 
  if (strncmp (string, "1.0", 3))
626
 
    {
627
 
      if (strncmp (string, "1.5", 3))
628
 
        {
629
 
          g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
630
 
                       _("Fatal parse error in brush file '%s': "
631
 
                         "Unknown GIMP brush version."),
632
 
                       gimp_filename_to_utf8 (filename));
633
 
          goto failed;
634
 
        }
635
 
      else
636
 
        {
637
 
          have_shape = TRUE;
638
 
        }
639
 
    }
640
 
 
641
 
  /* read name */
642
 
  errno = 0;
643
 
  if (! fgets (string, sizeof (string), file))
644
 
    goto failed;
645
 
 
646
 
  g_strstrip (string);
647
 
  name = gimp_any_to_utf8 (string, -1,
648
 
                           _("Invalid UTF-8 string in brush file '%s'."),
649
 
                           gimp_filename_to_utf8 (filename));
650
 
 
651
 
  if (have_shape)
652
 
    {
653
 
      GEnumClass *enum_class;
654
 
      GEnumValue *shape_val;
655
 
 
656
 
      enum_class = g_type_class_peek (GIMP_TYPE_BRUSH_GENERATED_SHAPE);
657
 
 
658
 
      /* read shape */
659
 
      errno = 0;
660
 
      if (! fgets (string, sizeof (string), file))
661
 
        goto failed;
662
 
 
663
 
      g_strstrip (string);
664
 
      shape_val = g_enum_get_value_by_nick (enum_class, string);
665
 
 
666
 
      if (!shape_val)
667
 
        {
668
 
          g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
669
 
                       _("Fatal parse error in brush file '%s': "
670
 
                         "Unknown GIMP brush shape."),
671
 
                       gimp_filename_to_utf8 (filename));
672
 
          goto failed;
673
 
        }
674
 
 
675
 
      shape = shape_val->value;
676
 
    }
677
 
 
678
 
  /* read brush spacing */
679
 
  errno = 0;
680
 
  if (! fgets (string, sizeof (string), file))
681
 
    goto failed;
682
 
  spacing = g_ascii_strtod (string, NULL);
683
 
 
684
 
  /* read brush radius */
685
 
  errno = 0;
686
 
  if (! fgets (string, sizeof (string), file))
687
 
    goto failed;
688
 
  radius = g_ascii_strtod (string, NULL);
689
 
 
690
 
  if (have_shape)
691
 
    {
692
 
      /* read brush radius */
693
 
      errno = 0;
694
 
      if (! fgets (string, sizeof (string), file))
695
 
        goto failed;
696
 
      spikes = CLAMP (atoi (string), 2, 20);
697
 
    }
698
 
 
699
 
  /* read brush hardness */
700
 
  errno = 0;
701
 
  if (! fgets (string, sizeof (string), file))
702
 
    goto failed;
703
 
  hardness = g_ascii_strtod (string, NULL);
704
 
 
705
 
  /* read brush aspect_ratio */
706
 
  errno = 0;
707
 
  if (! fgets (string, sizeof (string), file))
708
 
    goto failed;
709
 
  aspect_ratio = g_ascii_strtod (string, NULL);
710
 
 
711
 
  /* read brush angle */
712
 
  errno = 0;
713
 
  if (! fgets (string, sizeof (string), file))
714
 
    goto failed;
715
 
  angle = g_ascii_strtod (string, NULL);
716
 
 
717
 
  fclose (file);
718
 
 
719
 
  /* create new brush */
720
 
  brush = g_object_new (GIMP_TYPE_BRUSH_GENERATED,
721
 
                        "name",         name,
722
 
                        "shape",        shape,
723
 
                        "radius",       radius,
724
 
                        "spikes",       spikes,
725
 
                        "hardness",     hardness,
726
 
                        "aspect-ratio", aspect_ratio,
727
 
                        "angle",        angle,
728
 
                        NULL);
729
 
  g_free (name);
730
 
 
731
 
  GIMP_BRUSH (brush)->spacing = spacing;
732
 
 
733
 
  /* render brush mask */
734
 
  gimp_data_dirty (GIMP_DATA (brush));
735
 
 
736
 
  if (stingy_memory_use)
737
 
    temp_buf_swap (GIMP_BRUSH (brush)->mask);
738
 
 
739
 
  return g_list_prepend (NULL, brush);
740
 
 
741
 
 failed:
742
 
 
743
 
  fclose (file);
744
 
 
745
 
  if (name)
746
 
    g_free (name);
747
 
 
748
 
  if (error && *error == NULL)
749
 
    g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
750
 
                 _("Error while reading brush file '%s': %s"),
751
 
                 gimp_filename_to_utf8 (filename),
752
 
                 errno ? g_strerror (errno) : _("File is truncated"));
753
 
 
754
 
  return NULL;
755
 
}
756
 
 
757
589
GimpBrushGeneratedShape
758
590
gimp_brush_generated_set_shape (GimpBrushGenerated      *brush,
759
591
                                GimpBrushGeneratedShape  shape)