gimpbrushpipe.c 11.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 * Copyright (C) 1999 Adrian Likins and Tor Lillqvist
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

20
21
22
23
24
25
26
27
28
29
30
#include "config.h"

#include <math.h>
#include <stdio.h>
#include <string.h>

#include "appenv.h"
#include "brush_header.h"
#include "pattern_header.h"
#include "patterns.h"
#include "gimpbrush.h"
31
32
#include "gimpbrushpipe.h"
#include "gimpbrushpipeP.h"
33
34
35
36
#include "paint_core.h"
#include "gimprc.h"
#include "libgimp/gimpintl.h"

37
38
39
40
41
42
43
44
45
46
47
48
49
50
static GimpBrushClass* gimp_brush_class;
static GtkObjectClass* gimp_object_class;

static GimpBrush *gimp_brush_pixmap_select_brush (PaintCore *paint_core);

static void paint_line_pixmap_mask(GImage	   *dest,
				   GimpDrawable    *drawable,
				   GimpBrushPixmap *brush,
				   guchar	   *d,
				   int		    x,
				   int              y,
				   int              bytes,
				   int              width);

51
static void
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
gimp_brush_pixmap_destroy (GtkObject *object)
{
  GimpBrushPixmap *pixmap;

  g_return_if_fail (GIMP_IS_BRUSH_PIXMAP (object));

  pixmap = GIMP_BRUSH_PIXMAP (object);
  
  temp_buf_free (pixmap->pixmap_mask);

  (* GTK_OBJECT_CLASS (gimp_object_class)->destroy) (object);
}

static void
gimp_brush_pixmap_class_init (GimpBrushPixmapClass *klass)
{
  GtkObjectClass *object_class;
  GimpBrushClass *brush_class;
  
  object_class = GTK_OBJECT_CLASS (klass);
  brush_class = GIMP_BRUSH_CLASS (klass);

  gimp_brush_class = gtk_type_class (gimp_brush_get_type ());

  object_class->destroy =  gimp_brush_pixmap_destroy;
  brush_class->select_brush = gimp_brush_pixmap_select_brush;
}

void
gimp_brush_pixmap_init (GimpBrushPixmap *brush)
{
  brush->pixmap_mask = NULL;
  brush->pipe = NULL;
}

GtkType
gimp_brush_pixmap_get_type (void)
{
  static GtkType type=0;
  if(!type){
    GtkTypeInfo info={
      "GimpBrushPixmap",
      sizeof (GimpBrushPixmap),
      sizeof (GimpBrushPixmapClass),
      (GtkClassInitFunc) gimp_brush_pixmap_class_init,
      (GtkObjectInitFunc) gimp_brush_pixmap_init,
     /* reserved_1 */ NULL,
     /* reserved_2 */ NULL,
    (GtkClassInitFunc) NULL};
    type = gtk_type_unique (GIMP_TYPE_BRUSH, &info);
  }
  return type;
}
105

106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
static GimpBrush *
gimp_brush_pixmap_select_brush (PaintCore *paint_core)
{
  GimpBrushPixmap *pixmap;

  g_return_val_if_fail (GIMP_IS_BRUSH_PIXMAP (paint_core->brush), NULL);

  pixmap = GIMP_BRUSH_PIXMAP (paint_core->brush);

  if (pixmap->pipe->nbrushes == 1)
    return GIMP_BRUSH (pixmap->pipe->current);

  /* Just select the next one for now. This is the place where we
   * will select the correct brush based on various parameters
   * in paint_core.
   */
  pixmap->pipe->index[0] = (pixmap->pipe->index[0] + 1) % pixmap->pipe->nbrushes;
  pixmap->pipe->current = pixmap->pipe->brushes[pixmap->pipe->index[0]];

  return GIMP_BRUSH (pixmap->pipe->current);
}
127
128
129
130

static void
gimp_brush_pipe_destroy(GtkObject *object)
{
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  GimpBrushPipe *pipe;
  int i;

  g_return_if_fail (object != NULL);
  g_return_if_fail (GIMP_IS_BRUSH_PIPE (object));

  pipe = GIMP_BRUSH_PIPE (object);

  g_free (pipe->rank);

  for (i = 1; i < pipe->nbrushes; i++)
    gimp_object_destroy (pipe->brushes[i]);

  g_free (pipe->brushes);
  g_free (pipe->select);
  g_free (pipe->index);

  if (GTK_OBJECT_CLASS (gimp_object_class)->destroy)
    (* GTK_OBJECT_CLASS (gimp_object_class)->destroy) (object);
150
151
152
153
154
155
156
}

static void
gimp_brush_pipe_class_init (GimpBrushPipeClass *klass)
{
  GtkObjectClass *object_class;
  
157
158
159
160
  object_class = GTK_OBJECT_CLASS (klass);

  gimp_object_class = gtk_type_class (GIMP_TYPE_OBJECT);
  object_class->destroy =  gimp_brush_pipe_destroy;
161
162
163
}

void
164
gimp_brush_pipe_init (GimpBrushPipe *pipe)
165
{
166
167
168
169
170
  pipe->dimension = 0;
  pipe->rank = NULL;
  pipe->nbrushes = 0;
  pipe->select = NULL;
  pipe->index = NULL;
171
172
}

173
174
GtkType
gimp_brush_pipe_get_type (void)
175
176
{
  static GtkType type=0;
177
  if (!type){
178
179
    GtkTypeInfo info={
      "GimpBrushPipe",
180
181
182
183
184
185
      sizeof (GimpBrushPipe),
      sizeof (GimpBrushPipeClass),
      (GtkClassInitFunc) gimp_brush_pipe_class_init,
      (GtkObjectInitFunc) gimp_brush_pipe_init,
     /* reserved_1 */ NULL,
     /* reserved_2 */ NULL,
186
    (GtkClassInitFunc) NULL};
187
    type = gtk_type_unique (GIMP_TYPE_BRUSH_PIXMAP, &info);
188
189
190
191
192
  }
  return type;
}

GimpBrushPipe *
193
gimp_brush_pipe_load (char *filename)
194
195
196
197
{
  GimpBrushPipe *pipe;
  GPatternP pattern;
  FILE *fp;
198
199
  guchar buf[1024];
  guchar *name;
200
  int num_of_brushes;
201
  guchar *params;
202

203
204
  if ((fp = fopen (filename, "rb")) == NULL)
    return NULL;
205

206
207
208
209
210
211
212
213
214
  /* The file format starts with a painfully simple text header
   * and we use a painfully simple way to read it
   */
  if (fgets (buf, 1024, fp) == NULL)
    {
      fclose (fp);
      return NULL;
    }
  buf[strlen (buf) - 1] = 0;
215

216
217
  pipe = GIMP_BRUSH_PIPE (gimp_type_new (GIMP_TYPE_BRUSH_PIPE));
  name = g_strdup (buf);
218
219

  /* get the number of brushes */
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  if (fgets (buf, 1024, fp) == NULL)
    {
      fclose (fp);
      gimp_object_destroy (pipe);
      return NULL;
    }
  num_of_brushes = strtol(buf, &params, 10);
  if (num_of_brushes < 1)
    {
      g_message (_("pixmap brush pipe should have at least one brush"));
      fclose (fp);
      gimp_object_destroy (pipe);
      return NULL;
    }
234

235
236
237
238
239
240
241
242
243
244
  /* Here we should parse the params to get the dimension, ranks,
   * placement options, etc. But just use defaults for now.
   */
  pipe->dimension = 1;
  pipe->rank = g_new (int, 1);
  pipe->rank[0] = num_of_brushes;
  pipe->select = g_new (PipeSelectModes, 1);
  pipe->select[0] = PIPE_SELECT_INCREMENTAL;
  pipe->index = g_new (int, 1);
  pipe->index[0] = 0;
245

246
247
248
249
  pattern = (GPatternP) g_malloc (sizeof (GPattern));
  pattern->filename = NULL;
  pattern->name = NULL;
  pattern->mask = NULL;
250

251
252
  pipe->brushes =
    (GimpBrushPixmap **) g_new0 (GimpBrushPixmap *, num_of_brushes);
253

254
255
  /* First pixmap brush in the list is the pipe itself */
  pipe->brushes[0] = GIMP_BRUSH_PIXMAP (pipe);
256

257
258
259
260
261
262
  /* Current pixmap brush is the first one. */
  pipe->current = pipe->brushes[0];

  while (pipe->nbrushes < num_of_brushes)
    {
      if (pipe->nbrushes > 0)
263
	{
264
265
266
	  pipe->brushes[pipe->nbrushes] =
	    GIMP_BRUSH_PIXMAP (gimp_type_new (GIMP_TYPE_BRUSH_PIXMAP));
	  GIMP_BRUSH (pipe->brushes[pipe->nbrushes])->name = NULL;
267
	}
268
269
      
      pipe->brushes[pipe->nbrushes]->pipe = pipe;
270

271
272
273
274
      /* load the brush */
      if (!gimp_brush_load_brush (GIMP_BRUSH (pipe->brushes[pipe->nbrushes]),
				  fp, filename)
	  || !load_pattern_pattern (pattern, fp, filename))
275
       {
276
277
278
279
	  g_message (_("failed to load one of the pixmap brushes in the pipe"));
	  fclose (fp);
	  g_free (pattern);
	  gimp_object_destroy (pipe);
280
281
	  return NULL;
       }
282
283
284
285
286
287
288
289
290

      if (pipe->nbrushes == 0)
	{
	  /* Replace name with the whole pipe's name */
	  GIMP_BRUSH (pipe)->name = name;
	}
      pipe->brushes[pipe->nbrushes]->pixmap_mask = pattern->mask;

      pipe->nbrushes++;
291
    }
292
293

  /*  Clean up  */
294
295
  fclose (fp);

296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
  g_free(pattern);
  return pipe;
}

GimpBrushPipe *
gimp_brush_pixmap_load (char *filename)
{
  GimpBrushPipe *pipe;
  GPatternP pattern;
  FILE *fp;

  if ((fp = fopen (filename, "rb")) == NULL)
    return NULL;

  pipe = GIMP_BRUSH_PIPE (gimp_type_new (GIMP_TYPE_BRUSH_PIPE));
311

312
313
314
315
316
317
318
319
  /* A (single) pixmap brush is a pixmap pipe brush with just one pixmap */
  pipe->dimension = 1;
  pipe->rank = g_new (int, 1);
  pipe->rank[0] = 1;
  pipe->select = g_new (PipeSelectModes, 1);
  pipe->select[0] = PIPE_SELECT_INCREMENTAL;
  pipe->index = g_new (int, 1);
  pipe->index[0] = 0;
320

321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
  pattern = (GPatternP) g_malloc (sizeof (GPattern));
  pattern->filename = NULL;
  pattern->name = NULL;
  pattern->mask = NULL;

  pipe->brushes = (GimpBrushPixmap **) g_new (GimpBrushPixmap *, 1);

  pipe->brushes[0] = GIMP_BRUSH_PIXMAP (pipe);
  pipe->current = pipe->brushes[0];

  pipe->brushes[0]->pipe = pipe;

  /* load the brush */
  if (!gimp_brush_load_brush (GIMP_BRUSH (pipe->brushes[0]),
			      fp, filename)
      || !load_pattern_pattern (pattern, fp, filename))
    {
      g_message (_("failed to load pixmap brush"));
      fclose (fp);
      g_free (pattern);
      gimp_object_destroy (pipe);
      return NULL;
    }
  
  pipe->brushes[0]->pixmap_mask = pattern->mask;

  pipe->nbrushes = 1;
  /*  Clean up  */
  fclose (fp);

  g_free(pattern);
352
  return pipe;
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
}

TempBuf *
gimp_brush_pixmap_pixmap (GimpBrushPixmap *brush)
{
  g_return_val_if_fail (brush != NULL, NULL);
  g_return_val_if_fail (GIMP_IS_BRUSH_PIXMAP (brush), NULL);

  return brush->pixmap_mask;
}

void
color_area_with_pixmap (PaintCore *paint_core,
			GImage *dest,
			GimpDrawable *drawable,
			TempBuf *area)
{

  PixelRegion destPR;
  void *pr;
  guchar *d;
  int ulx, uly, offsetx, offsety, y;
  GimpBrushPixmap *pixmap;
  
  g_return_if_fail (GIMP_IS_BRUSH_PIXMAP (paint_core->brush));

  pixmap = GIMP_BRUSH_PIXMAP (paint_core->brush);

  destPR.bytes = area->bytes;
  destPR.x = 0; destPR.y = 0;
  destPR.w = area->width;
  destPR.h = area->height;
  destPR.rowstride = destPR.bytes * area->width;
  destPR.data = temp_buf_data (area);
		
  pr = pixel_regions_register (1, &destPR);
389

390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
  /* Calculate upper left corner of brush as in
   * paint_core_get_paint_area.  Ugly to have to do this here, too.
   */

  ulx = (int) paint_core->curx - (paint_core->brush->mask->width >> 1);
  uly = (int) paint_core->cury - (paint_core->brush->mask->height >> 1);

  offsetx = area->x - ulx;
  offsety = area->y - uly;

  for (; pr != NULL; pr = pixel_regions_process (pr))
    {
      d = destPR.data;
      for (y = 0; y < destPR.h; y++)
	{
	  paint_line_pixmap_mask (dest, drawable, pixmap,
				  d, offsetx, y + offsety,
				  destPR.bytes, destPR.w);
	  d += destPR.rowstride;
	}
    }
}

static void
paint_line_pixmap_mask (GImage          *dest,
			GimpDrawable    *drawable,
			GimpBrushPixmap *brush,
			guchar	        *d,
			int		 x,
			int              y,
			int              bytes,
			int              width)
{
  guchar *b, *p;
424
425
426
427
428
429
  int x_index;
  gdouble alpha;
  gdouble factor = 0.00392156986;  /* 1.0/255.0 */
  gint i;
  gint j;
  guchar *mask;
430
431
432
433
434
435
436
437
438
439
440

  /*  Make sure x, y are positive  */
  while (x < 0)
    x += brush->pixmap_mask->width;
  while (y < 0)
    y += brush->pixmap_mask->height;

  /* Point to the approriate scanline */
  b = temp_buf_data (brush->pixmap_mask) +
    (y % brush->pixmap_mask->height) * brush->pixmap_mask->width * brush->pixmap_mask->bytes;
    
441
442
443
444
  /* ditto, except for the brush mask, so we can pre-multiply the alpha value */
  mask = temp_buf_data((brush->gbrush).mask) +
    (y % brush->pixmap_mask->height) * brush->pixmap_mask->width;
 
445
446
  for (i = 0; i < width; i++)
    {
447
448
449
450
451
452
453
454
455
456
457
458
      /* attempt to avoid doing this calc twice in the loop */
      x_index = ((i + x) % brush->pixmap_mask->width);
      p = b + x_index * brush->pixmap_mask->bytes;
      d[bytes-1] = mask[x_index];

      /* multiply alpha into the pixmap data */
      /* maybe we could do this at tool creation or brush switch time? */
      /* and compute it for the whole brush at once and cache it?  */
      alpha = d[bytes-1] * factor;
      d[0] *= alpha;
      d[1] *= alpha;
      d[2] *= alpha;
459
460
461
462
      /* printf("i: %i d->r: %i d->g: %i d->b: %i d->a: %i\n",i,(int)d[0], (int)d[1], (int)d[2], (int)d[3]); */
      gimage_transform_color (dest, drawable, p, d, RGB);
      d += bytes;
    }
463
}
464