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 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
}

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

114 115 116
static GimpBrush *
gimp_brush_pixmap_select_brush (PaintCore *paint_core)
{
117
  GimpBrushPipe *pipe;
118
  int i, brushix, ix;
119
  double angle;
120 121 122

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

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

125 126
  if (pipe->nbrushes == 1)
    return GIMP_BRUSH (pipe->current);
127

128 129 130 131 132 133
  brushix = 0;
  for (i = 0; i < pipe->dimension; i++)
    {
      switch (pipe->select[i])
	{
	case PIPE_SELECT_CONSTANT:
134
	  ix = pipe->index[i];
135 136
	  break;
	case PIPE_SELECT_INCREMENTAL:
137
	  ix = (pipe->index[i] + 1) % pipe->rank[i];
138 139 140 141
	  break;
	case PIPE_SELECT_ANGULAR:
	  angle = atan2 (paint_core->cury - paint_core->lasty,
			 paint_core->curx - paint_core->lastx);
142 143 144
	  /* Offset angle to be compatible with PSP tubes */
	  angle += G_PI_2;
	  /* Map it to the [0..2*G_PI) interval */
145 146
	  if (angle < 0)
	    angle += 2.*G_PI;
147 148 149
	  else if (angle > 2.*G_PI)
	    angle -= 2.*G_PI;
	  ix = RINT (angle / (2.*G_PI) * pipe->rank[i]);
150 151 152
	  break;
	case PIPE_SELECT_RANDOM:
	  /* This probably isn't the right way */
153
	  ix = rand () % pipe->rank[i];
154 155
	  break;
	case PIPE_SELECT_PRESSURE:
156
	  ix = RINT (paint_core->curpressure * (pipe->rank[i] - 1));
157 158
	  break;
	case PIPE_SELECT_TILT_X:
159
	  ix = RINT (paint_core->curxtilt / 2.0 * pipe->rank[i]) + pipe->rank[i]/2;
160 161
	  break;
	case PIPE_SELECT_TILT_Y:
162
	  ix = RINT (paint_core->curytilt / 2.0 * pipe->rank[i]) + pipe->rank[i]/2;
163 164
	  break;
	}
165 166 167
      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); */
168 169
    }

170
  /* Make sure is inside bounds */
171
  brushix = BOUNDS (brushix, 0, pipe->nbrushes-1);
172

173 174 175
  pipe->current = pipe->brushes[brushix];

  return GIMP_BRUSH (pipe->current);
176
}
177

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
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;
}

198 199 200
static void
gimp_brush_pipe_destroy(GtkObject *object)
{
201 202 203 204 205 206 207 208 209
  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);
210
  g_free (pipe->stride);
211 212 213 214 215 216 217 218 219 220

  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);
221 222 223 224 225 226 227
}

static void
gimp_brush_pipe_class_init (GimpBrushPipeClass *klass)
{
  GtkObjectClass *object_class;
  
228 229 230 231
  object_class = GTK_OBJECT_CLASS (klass);

  gimp_object_class = gtk_type_class (GIMP_TYPE_OBJECT);
  object_class->destroy =  gimp_brush_pipe_destroy;
232 233 234
}

void
235
gimp_brush_pipe_init (GimpBrushPipe *pipe)
236
{
237 238 239 240 241
  pipe->dimension = 0;
  pipe->rank = NULL;
  pipe->nbrushes = 0;
  pipe->select = NULL;
  pipe->index = NULL;
242 243
}

244 245
GtkType
gimp_brush_pipe_get_type (void)
246 247
{
  static GtkType type=0;
248
  if (!type){
249 250
    GtkTypeInfo info={
      "GimpBrushPipe",
251 252 253 254 255 256
      sizeof (GimpBrushPipe),
      sizeof (GimpBrushPipeClass),
      (GtkClassInitFunc) gimp_brush_pipe_class_init,
      (GtkObjectInitFunc) gimp_brush_pipe_init,
     /* reserved_1 */ NULL,
     /* reserved_2 */ NULL,
257
    (GtkClassInitFunc) NULL};
258
    type = gtk_type_unique (GIMP_TYPE_BRUSH_PIXMAP, &info);
259 260 261 262 263
  }
  return type;
}

GimpBrushPipe *
264
gimp_brush_pipe_load (char *filename)
265 266 267
{
  GimpBrushPipe *pipe;
  GPatternP pattern;
268
  PixPipeParams params;
269
  FILE *fp;
270 271
  guchar buf[1024];
  guchar *name;
272
  int i;
273
  int num_of_brushes;
274
  int totalcells;
275
  gchar *paramstring;
276

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

280 281 282 283 284 285 286 287 288
  /* 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;
289

290 291
  pipe = GIMP_BRUSH_PIPE (gimp_type_new (GIMP_TYPE_BRUSH_PIPE));
  name = g_strdup (buf);
292 293

  /* get the number of brushes */
294 295 296 297 298 299
  if (fgets (buf, 1024, fp) == NULL)
    {
      fclose (fp);
      gimp_object_destroy (pipe);
      return NULL;
    }
300
  num_of_brushes = strtol(buf, &paramstring, 10);
301 302 303 304 305 306 307
  if (num_of_brushes < 1)
    {
      g_message (_("pixmap brush pipe should have at least one brush"));
      fclose (fp);
      gimp_object_destroy (pipe);
      return NULL;
    }
308

309 310
  while (*paramstring && isspace(*paramstring))
    paramstring++;
311

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

366 367 368 369
  pattern = (GPatternP) g_malloc (sizeof (GPattern));
  pattern->filename = NULL;
  pattern->name = NULL;
  pattern->mask = NULL;
370

371 372
  pipe->brushes =
    (GimpBrushPixmap **) g_new0 (GimpBrushPixmap *, num_of_brushes);
373

374 375
  /* First pixmap brush in the list is the pipe itself */
  pipe->brushes[0] = GIMP_BRUSH_PIXMAP (pipe);
376

377 378 379 380 381 382
  /* Current pixmap brush is the first one. */
  pipe->current = pipe->brushes[0];

  while (pipe->nbrushes < num_of_brushes)
    {
      if (pipe->nbrushes > 0)
383
	{
384 385 386
	  pipe->brushes[pipe->nbrushes] =
	    GIMP_BRUSH_PIXMAP (gimp_type_new (GIMP_TYPE_BRUSH_PIXMAP));
	  GIMP_BRUSH (pipe->brushes[pipe->nbrushes])->name = NULL;
387
	}
388 389
      
      pipe->brushes[pipe->nbrushes]->pipe = pipe;
390

391 392 393 394
      /* load the brush */
      if (!gimp_brush_load_brush (GIMP_BRUSH (pipe->brushes[pipe->nbrushes]),
				  fp, filename)
	  || !load_pattern_pattern (pattern, fp, filename))
395
       {
396 397 398 399
	  g_message (_("failed to load one of the pixmap brushes in the pipe"));
	  fclose (fp);
	  g_free (pattern);
	  gimp_object_destroy (pipe);
400 401
	  return NULL;
       }
402 403 404 405 406 407 408 409 410

      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++;
411
    }
412 413

  /*  Clean up  */
414 415
  fclose (fp);

416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
  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));
431

432 433 434 435 436 437 438 439
  /* 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;
440

441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
  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);
472
  return pipe;
473 474 475 476 477 478 479 480 481 482 483
}

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

484