gimpbrushpipe.c 12.3 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
#include "config.h"

#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include <ctype.h>
26

27
#include "apptypes.h"
28 29 30 31 32
#include "appenv.h"
#include "brush_header.h"
#include "pattern_header.h"
#include "patterns.h"
#include "gimpbrush.h"
33 34
#include "gimpbrushpipe.h"
#include "gimpbrushpipeP.h"
35 36
#include "paint_core.h"
#include "gimprc.h"
37

38
#include "libgimp/gimpintl.h"
39
#include "libgimp/gimpmath.h"
40
#include "libgimp/parasiteio.h"
41

42 43 44 45
static GimpBrushClass* gimp_brush_class;
static GtkObjectClass* gimp_object_class;

static GimpBrush *gimp_brush_pixmap_select_brush (PaintCore *paint_core);
46
static gboolean gimp_brush_pixmap_want_null_motion (PaintCore *paint_core);
47 48 49 50 51 52 53 54

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

58
static void
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
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;
85
  brush_class->want_null_motion = gimp_brush_pixmap_want_null_motion;
86 87 88 89 90 91 92 93 94 95 96 97
}

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

GtkType
gimp_brush_pixmap_get_type (void)
{
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
  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);
    }

117 118
  return type;
}
119

120 121 122
static GimpBrush *
gimp_brush_pixmap_select_brush (PaintCore *paint_core)
{
123
  GimpBrushPipe *pipe;
124
  int i, brushix, ix;
125
  double angle;
126 127 128

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

129
  pipe = GIMP_BRUSH_PIXMAP (paint_core->brush)->pipe;
130

131 132
  if (pipe->nbrushes == 1)
    return GIMP_BRUSH (pipe->current);
133

134 135 136 137 138 139
  brushix = 0;
  for (i = 0; i < pipe->dimension; i++)
    {
      switch (pipe->select[i])
	{
	case PIPE_SELECT_INCREMENTAL:
140
	  ix = (pipe->index[i] + 1) % pipe->rank[i];
141 142 143 144
	  break;
	case PIPE_SELECT_ANGULAR:
	  angle = atan2 (paint_core->cury - paint_core->lasty,
			 paint_core->curx - paint_core->lastx);
145 146 147
	  /* Offset angle to be compatible with PSP tubes */
	  angle += G_PI_2;
	  /* Map it to the [0..2*G_PI) interval */
148 149
	  if (angle < 0)
	    angle += 2.*G_PI;
150 151 152
	  else if (angle > 2.*G_PI)
	    angle -= 2.*G_PI;
	  ix = RINT (angle / (2.*G_PI) * pipe->rank[i]);
153 154 155
	  break;
	case PIPE_SELECT_RANDOM:
	  /* This probably isn't the right way */
156
	  ix = rand () % pipe->rank[i];
157 158
	  break;
	case PIPE_SELECT_PRESSURE:
159
	  ix = RINT (paint_core->curpressure * (pipe->rank[i] - 1));
160 161
	  break;
	case PIPE_SELECT_TILT_X:
162
	  ix = RINT (paint_core->curxtilt / 2.0 * pipe->rank[i]) + pipe->rank[i]/2;
163 164
	  break;
	case PIPE_SELECT_TILT_Y:
165
	  ix = RINT (paint_core->curytilt / 2.0 * pipe->rank[i]) + pipe->rank[i]/2;
166
	  break;
Adam D. Moss's avatar
Adam D. Moss committed
167 168 169 170
	case PIPE_SELECT_CONSTANT:
	default:
	  ix = pipe->index[i];
	  break;
171
	}
172 173 174
      pipe->index[i] = BOUNDS (ix, 0, pipe->rank[i]-1);
      brushix += pipe->stride[i] * pipe->index[i];
      /* g_print ("ix at %d: %d, brushix: %d\n", i, ix, brushix); */
175 176
    }

177
  /* Make sure is inside bounds */
178
  brushix = BOUNDS (brushix, 0, pipe->nbrushes-1);
179

180 181 182
  pipe->current = pipe->brushes[brushix];

  return GIMP_BRUSH (pipe->current);
183
}
184

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
static gboolean
gimp_brush_pixmap_want_null_motion (PaintCore *paint_core)
{
  GimpBrushPipe *pipe;
  int i;

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

  pipe = GIMP_BRUSH_PIXMAP (paint_core->brush)->pipe;

  if (pipe->nbrushes == 1)
    return TRUE;

  for (i = 0; i < pipe->dimension; i++)
    if (pipe->select[i] == PIPE_SELECT_ANGULAR)
      return FALSE;

  return TRUE;
}

205 206 207
static void
gimp_brush_pipe_destroy(GtkObject *object)
{
208 209 210 211 212 213 214 215 216
  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);
217
  g_free (pipe->stride);
218 219 220 221 222 223 224 225 226 227

  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);
228 229 230 231 232 233 234
}

static void
gimp_brush_pipe_class_init (GimpBrushPipeClass *klass)
{
  GtkObjectClass *object_class;
  
235 236 237 238
  object_class = GTK_OBJECT_CLASS (klass);

  gimp_object_class = gtk_type_class (GIMP_TYPE_OBJECT);
  object_class->destroy =  gimp_brush_pipe_destroy;
239 240 241
}

void
242
gimp_brush_pipe_init (GimpBrushPipe *pipe)
243
{
244 245 246 247 248
  pipe->dimension = 0;
  pipe->rank = NULL;
  pipe->nbrushes = 0;
  pipe->select = NULL;
  pipe->index = NULL;
249 250
}

251 252
GtkType
gimp_brush_pipe_get_type (void)
253 254
{
  static GtkType type=0;
255
  if (!type){
256 257
    GtkTypeInfo info={
      "GimpBrushPipe",
258 259 260 261 262 263
      sizeof (GimpBrushPipe),
      sizeof (GimpBrushPipeClass),
      (GtkClassInitFunc) gimp_brush_pipe_class_init,
      (GtkObjectInitFunc) gimp_brush_pipe_init,
     /* reserved_1 */ NULL,
     /* reserved_2 */ NULL,
264
    (GtkClassInitFunc) NULL};
265
    type = gtk_type_unique (GIMP_TYPE_BRUSH_PIXMAP, &info);
266 267 268 269 270
  }
  return type;
}

GimpBrushPipe *
271
gimp_brush_pipe_load (char *filename)
272 273 274
{
  GimpBrushPipe *pipe;
  GPatternP pattern;
275
  PixPipeParams params;
276
  FILE *fp;
277 278
  guchar buf[1024];
  guchar *name;
279
  int i;
280
  int num_of_brushes;
281
  int totalcells;
282
  gchar *paramstring;
283

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

287 288 289 290 291 292 293 294 295
  /* 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;
296

297 298
  pipe = GIMP_BRUSH_PIPE (gimp_type_new (GIMP_TYPE_BRUSH_PIPE));
  name = g_strdup (buf);
299 300

  /* get the number of brushes */
301 302 303 304 305 306
  if (fgets (buf, 1024, fp) == NULL)
    {
      fclose (fp);
      gimp_object_destroy (pipe);
      return NULL;
    }
307
  num_of_brushes = strtol(buf, &paramstring, 10);
308 309 310 311 312 313 314
  if (num_of_brushes < 1)
    {
      g_message (_("pixmap brush pipe should have at least one brush"));
      fclose (fp);
      gimp_object_destroy (pipe);
      return NULL;
    }
315

316 317
  while (*paramstring && isspace(*paramstring))
    paramstring++;
318

319
  if (*paramstring)
320
    {
321 322 323
      pixpipeparams_init (&params);
      pixpipeparams_parse (paramstring, &params);
      pipe->dimension = params.dim;
324 325 326 327 328
      pipe->rank = g_new (int, pipe->dimension);
      pipe->select = g_new (PipeSelectModes, pipe->dimension);
      pipe->index = g_new (int, pipe->dimension);
      for (i = 0; i < pipe->dimension; i++)
	{
329 330
	  pipe->rank[i] = params.rank[i];
	  if (strcmp (params.selection[i], "incremental") == 0)
331
	    pipe->select[i] = PIPE_SELECT_INCREMENTAL;
332
	  else if (strcmp (params.selection[i], "angular") == 0)
333
	    pipe->select[i] = PIPE_SELECT_ANGULAR;
334
	  else if (strcmp (params.selection[i], "velocity") == 0)
335
	    pipe->select[i] = PIPE_SELECT_VELOCITY;
336
	  else if (strcmp (params.selection[i], "random") == 0)
337
	    pipe->select[i] = PIPE_SELECT_RANDOM;
338
	  else if (strcmp (params.selection[i], "pressure") == 0)
339
	    pipe->select[i] = PIPE_SELECT_PRESSURE;
340
	  else if (strcmp (params.selection[i], "xtilt") == 0)
341
	    pipe->select[i] = PIPE_SELECT_TILT_X;
342
	  else if (strcmp (params.selection[i], "ytilt") == 0)
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
	    pipe->select[i] = PIPE_SELECT_TILT_Y;
	  else
	    pipe->select[i] = PIPE_SELECT_CONSTANT;
	  pipe->index[i] = 0;
	}
    }
  else
    {
      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;
    }

  totalcells = 1;		/* Not all necessarily present, maybe */
  for (i = 0; i < pipe->dimension; i++)
    totalcells *= pipe->rank[i];
  pipe->stride = g_new (int, pipe->dimension);
  for (i = 0; i < pipe->dimension; i++)
    {
      if (i == 0)
	pipe->stride[i] = totalcells / pipe->rank[i];
      else
	pipe->stride[i] = pipe->stride[i-1] / pipe->rank[i];
    }
  g_assert (pipe->stride[pipe->dimension-1] == 1);
372

Sven Neumann's avatar
Sven Neumann committed
373
  pattern = (GPattern*) g_malloc0 (sizeof (GPattern));
374

375 376
  pipe->brushes =
    (GimpBrushPixmap **) g_new0 (GimpBrushPixmap *, num_of_brushes);
377

378 379
  /* First pixmap brush in the list is the pipe itself */
  pipe->brushes[0] = GIMP_BRUSH_PIXMAP (pipe);
380

381 382 383 384 385 386
  /* Current pixmap brush is the first one. */
  pipe->current = pipe->brushes[0];

  while (pipe->nbrushes < num_of_brushes)
    {
      if (pipe->nbrushes > 0)
387
	{
388 389
	  pipe->brushes[pipe->nbrushes] =
	    GIMP_BRUSH_PIXMAP (gimp_type_new (GIMP_TYPE_BRUSH_PIXMAP));
Sven Neumann's avatar
Sven Neumann committed
390
	  g_free (GIMP_BRUSH (pipe->brushes[pipe->nbrushes])->name);
391
	  GIMP_BRUSH (pipe->brushes[pipe->nbrushes])->name = NULL;
392
	}
393 394
      
      pipe->brushes[pipe->nbrushes]->pipe = pipe;
395

396 397 398
      /* load the brush */
      if (!gimp_brush_load_brush (GIMP_BRUSH (pipe->brushes[pipe->nbrushes]),
				  fp, filename)
399
	  || !pattern_load (pattern, fp, filename))
400
       {
401 402
	  g_message (_("failed to load one of the pixmap brushes in the pipe"));
	  fclose (fp);
Sven Neumann's avatar
Sven Neumann committed
403
	  pattern_free (pattern);
404
	  gimp_object_destroy (pipe);
405 406
	  return NULL;
       }
407 408 409 410

      if (pipe->nbrushes == 0)
	{
	  /* Replace name with the whole pipe's name */
Sven Neumann's avatar
Sven Neumann committed
411
	  g_free (GIMP_BRUSH (pipe)->name);
412 413 414
	  GIMP_BRUSH (pipe)->name = name;
	}
      pipe->brushes[pipe->nbrushes]->pixmap_mask = pattern->mask;
Sven Neumann's avatar
Sven Neumann committed
415
      g_free (pattern->name);
416
      pipe->nbrushes++;
417
    }
418 419

  /*  Clean up  */
420 421
  fclose (fp);

422
  g_free (pattern);
423 424 425 426 427 428 429 430 431 432 433 434 435 436
  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));
437

438 439 440 441 442 443 444 445
  /* 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;
446

Sven Neumann's avatar
Sven Neumann committed
447
  pattern = (GPatternP) g_malloc0 (sizeof (GPattern));
448 449 450 451 452 453 454 455 456 457 458

  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)
459
      || !pattern_load (pattern, fp, filename))
460 461 462
    {
      g_message (_("failed to load pixmap brush"));
      fclose (fp);
Sven Neumann's avatar
Sven Neumann committed
463
      pattern_free (pattern);
464 465 466 467 468 469 470 471 472 473
      gimp_object_destroy (pipe);
      return NULL;
    }
  
  pipe->brushes[0]->pixmap_mask = pattern->mask;

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

Sven Neumann's avatar
Sven Neumann committed
474 475
  g_free (pattern->name);
  g_free (pattern);
476
  return pipe;
477 478 479 480 481 482 483 484 485 486
}

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;
}