From 70fca093f3d647a454baaea76a9fa8d93804ece0 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Sat, 28 Aug 1999 01:14:42 +0000 Subject: [PATCH] Implement the selection of brush based on cursor direction, pressure, 1999-08-28 Tor Lillqvist * app/gimpbrushpipe.c: Implement the selection of brush based on cursor direction, pressure, tilt, or a random value. (Hmm, forgot velocity, later.) (In addition to just incrementally stepping.) Read the brush pipe parameters from the gih file's second line. There is no way to tune the parameters in the GIMP, they must currently be set when saving the gih file (in the gpb plug-in). * app/gimpbrushpipe.h * app/gimpbrushpipeP.h: Move the PipeSelectModes enum to the "private" header. Add a stride array to GimpBrushPipe to make indexing easier. * plug-ins/common/gpb.c: Add selection mode fields to the dialog. Attach the pipe parameters entered as a parasite, too. * docs/parasites.txt * plug-ins/common/psp.c: Use "placement", not "spacing" (which means another thing). --- ChangeLog | 21 +++ app/core/gimpbrushpipe-load.c | 236 ++++++++++++++++++++++++++++++---- app/core/gimpbrushpipe.c | 236 ++++++++++++++++++++++++++++++---- app/core/gimpbrushpipe.h | 11 -- app/gimpbrushpipe.c | 236 ++++++++++++++++++++++++++++++---- app/gimpbrushpipe.h | 11 -- app/gimpbrushpipeP.h | 16 ++- app/makefile.cygwin | 2 +- docs/parasites.txt | 14 +- plug-ins/common/gpb.c | 205 ++++++++++++++++++++++------- plug-ins/common/psp.c | 2 +- 11 files changed, 846 insertions(+), 144 deletions(-) diff --git a/ChangeLog b/ChangeLog index fad39e5b75..1499499e3f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +1999-08-28 Tor Lillqvist + + * app/gimpbrushpipe.c: Implement the selection of brush based on + cursor direction, pressure, tilt, or a random value. (Hmm, forgot + velocity, later.) (In addition to just incrementally stepping.) + Read the brush pipe parameters from the gih file's second line. + There is no way to tune the parameters in the GIMP, they must + currently be set when saving the gih file (in the gpb plug-in). + + * app/gimpbrushpipe.h + * app/gimpbrushpipeP.h: Move the PipeSelectModes enum to the + "private" header. Add a stride array to GimpBrushPipe to make + indexing easier. + + * plug-ins/common/gpb.c: Add selection mode fields to the dialog. + Attach the pipe parameters entered as a parasite, too. + + * docs/parasites.txt + * plug-ins/common/psp.c: Use "placement", not "spacing" (which + means another thing). + Fri Aug 27 18:08:55 PDT 1999 Manish Singh * app/color_display.h: just include parasiteF.h diff --git a/app/core/gimpbrushpipe-load.c b/app/core/gimpbrushpipe-load.c index 3ea9e6f2bc..5793e82271 100644 --- a/app/core/gimpbrushpipe-load.c +++ b/app/core/gimpbrushpipe-load.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "appenv.h" #include "brush_header.h" @@ -35,6 +36,26 @@ #include "gimprc.h" #include "libgimp/gimpintl.h" +/* Code duplicated from plug-ins/common/gpb.c... + * The struct, and code to parse/build it probably should be in libgimp. + */ + +/* Parameters related to one single gih file, collected in a struct + * just for clarity. + */ +#define MAXDIM 4 +static struct { + gint step; + gint ncells; + gint dim; + gint cols; + gint rows; + gchar *placement; + gint rank[MAXDIM]; + gchar *selection[MAXDIM]; +} gihparms; + + static GimpBrushClass* gimp_brush_class; static GtkObjectClass* gimp_object_class; @@ -107,23 +128,60 @@ gimp_brush_pixmap_get_type (void) static GimpBrush * gimp_brush_pixmap_select_brush (PaintCore *paint_core) { - GimpBrushPixmap *pixmap; + GimpBrushPipe *pipe; + int i, brushix, value; + double angle; g_return_val_if_fail (GIMP_IS_BRUSH_PIXMAP (paint_core->brush), NULL); - pixmap = GIMP_BRUSH_PIXMAP (paint_core->brush); + pipe = GIMP_BRUSH_PIXMAP (paint_core->brush)->pipe; - if (pixmap->pipe->nbrushes == 1) - return GIMP_BRUSH (pixmap->pipe->current); + if (pipe->nbrushes == 1) + return GIMP_BRUSH (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]]; + brushix = 0; + for (i = 0; i < pipe->dimension; i++) + { + switch (pipe->select[i]) + { + case PIPE_SELECT_CONSTANT: + /* What constant? */ + value = 0; + break; + case PIPE_SELECT_INCREMENTAL: + value = pipe->index[i] = (pipe->index[i] + 1) % pipe->rank[i]; + break; + case PIPE_SELECT_ANGULAR: + angle = atan2 (paint_core->cury - paint_core->lasty, + paint_core->curx - paint_core->lastx); + if (angle < 0) + angle += 2.*G_PI; + value = RINT (angle / (2.*G_PI) * pipe->rank[i]); + break; + case PIPE_SELECT_RANDOM: + /* This probably isn't the right way */ + value = rand () % pipe->rank[i]; + break; + case PIPE_SELECT_PRESSURE: + value = RINT (paint_core->curpressure * (pipe->rank[i] - 1)); + break; + case PIPE_SELECT_TILT_X: + value = RINT (paint_core->curxtilt / 2.0 * pipe->rank[i]) + pipe->rank[i]/2; + break; + case PIPE_SELECT_TILT_Y: + value = RINT (paint_core->curytilt / 2.0 * pipe->rank[i]) + pipe->rank[i]/2; + break; + } + brushix += pipe->stride[i] * value; + /* g_print ("value at %d: %d, brushix: %d\n", i, value, brushix); */ + } - return GIMP_BRUSH (pixmap->pipe->current); + /* If out of bounds, just select the first brush... */ + brushix = BOUNDS (brushix, 0, pipe->nbrushes-1); + + pipe->current = pipe->brushes[brushix]; + + return GIMP_BRUSH (pipe->current); } static void @@ -138,6 +196,7 @@ gimp_brush_pipe_destroy(GtkObject *object) pipe = GIMP_BRUSH_PIPE (object); g_free (pipe->rank); + g_free (pipe->stride); for (i = 1; i < pipe->nbrushes; i++) gimp_object_destroy (pipe->brushes[i]); @@ -190,6 +249,91 @@ gimp_brush_pipe_get_type (void) return type; } +static void +init_pipe_parameters () +{ + int i; + + gihparms.step = 100; + gihparms.ncells = 1; + gihparms.dim = 1; + gihparms.cols = 1; + gihparms.rows = 1; + gihparms.placement = "constant"; + for (i = 0; i < MAXDIM; i++) + gihparms.selection[i] = "random"; + gihparms.rank[0] = 1; + for (i = 1; i < MAXDIM; i++) + gihparms.rank[i] = 0; +} + +static void +parse_brush_pipe_parameters (gchar *parameters) +{ + guchar *p, *q, *r, *s; /* Don't you love single-char identifiers? */ + gint i; + + q = parameters; + while ((p = strtok (q, " \r\n")) != NULL) + { + q = NULL; + r = strchr (p, ':'); + if (r) + *r = 0; + + if (strcmp (p, "ncells") == 0) + { + if (r) + gihparms.ncells = atoi (r + 1); + } + else if (strcmp (p, "step") == 0) + { + if (r) + gihparms.step = atoi (r + 1); + } + else if (strcmp (p, "dim") == 0) + { + if (r) + gihparms.dim = atoi (r + 1); + } + else if (strcmp (p, "cols") == 0) + { + if (r) + gihparms.cols = atoi (r + 1); + } + else if (strcmp (p, "rows") == 0) + { + if (r) + gihparms.rows = atoi (r + 1); + } + else if (strcmp (p, "placement") == 0) + { + if (r) + gihparms.placement = g_strdup (r + 1); + } + else if (strncmp (p, "rank", strlen ("rank")) == 0) + { + if (r) + { + i = atoi (p + strlen ("rank")); + if (i >= 0 && i < gihparms.dim) + gihparms.rank[i] = atoi (r + 1); + } + } + else if (strncmp (p, "sel", strlen ("sel")) == 0) + { + if (r) + { + i = atoi (p + strlen ("sel")); + if (i >= 0 && i < gihparms.dim) + gihparms.selection[i] = g_strdup (r + 1); + } + } + if (r) + *r = ':'; + } +} + GimpBrushPipe * gimp_brush_pipe_load (char *filename) { @@ -198,8 +342,10 @@ gimp_brush_pipe_load (char *filename) FILE *fp; guchar buf[1024]; guchar *name; + int i; int num_of_brushes; - guchar *params; + int totalcells; + gchar *params; if ((fp = fopen (filename, "rb")) == NULL) return NULL; @@ -233,16 +379,62 @@ gimp_brush_pipe_load (char *filename) return NULL; } - /* 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; + while (*params && isspace(*params)) + params++; + + if (*params) + { + init_pipe_parameters (); + parse_brush_pipe_parameters (params); + pipe->dimension = gihparms.dim; + 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++) + { + pipe->rank[i] = gihparms.rank[i]; + if (strcmp (gihparms.selection[i], "incremental") == 0) + pipe->select[i] = PIPE_SELECT_INCREMENTAL; + else if (strcmp (gihparms.selection[i], "angular") == 0) + pipe->select[i] = PIPE_SELECT_ANGULAR; + else if (strcmp (gihparms.selection[i], "velocity") == 0) + pipe->select[i] = PIPE_SELECT_VELOCITY; + else if (strcmp (gihparms.selection[i], "random") == 0) + pipe->select[i] = PIPE_SELECT_RANDOM; + else if (strcmp (gihparms.selection[i], "pressure") == 0) + pipe->select[i] = PIPE_SELECT_PRESSURE; + else if (strcmp (gihparms.selection[i], "xtilt") == 0) + pipe->select[i] = PIPE_SELECT_TILT_X; + else if (strcmp (gihparms.selection[i], "ytilt") == 0) + 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); pattern = (GPatternP) g_malloc (sizeof (GPattern)); pattern->filename = NULL; diff --git a/app/core/gimpbrushpipe.c b/app/core/gimpbrushpipe.c index 3ea9e6f2bc..5793e82271 100644 --- a/app/core/gimpbrushpipe.c +++ b/app/core/gimpbrushpipe.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "appenv.h" #include "brush_header.h" @@ -35,6 +36,26 @@ #include "gimprc.h" #include "libgimp/gimpintl.h" +/* Code duplicated from plug-ins/common/gpb.c... + * The struct, and code to parse/build it probably should be in libgimp. + */ + +/* Parameters related to one single gih file, collected in a struct + * just for clarity. + */ +#define MAXDIM 4 +static struct { + gint step; + gint ncells; + gint dim; + gint cols; + gint rows; + gchar *placement; + gint rank[MAXDIM]; + gchar *selection[MAXDIM]; +} gihparms; + + static GimpBrushClass* gimp_brush_class; static GtkObjectClass* gimp_object_class; @@ -107,23 +128,60 @@ gimp_brush_pixmap_get_type (void) static GimpBrush * gimp_brush_pixmap_select_brush (PaintCore *paint_core) { - GimpBrushPixmap *pixmap; + GimpBrushPipe *pipe; + int i, brushix, value; + double angle; g_return_val_if_fail (GIMP_IS_BRUSH_PIXMAP (paint_core->brush), NULL); - pixmap = GIMP_BRUSH_PIXMAP (paint_core->brush); + pipe = GIMP_BRUSH_PIXMAP (paint_core->brush)->pipe; - if (pixmap->pipe->nbrushes == 1) - return GIMP_BRUSH (pixmap->pipe->current); + if (pipe->nbrushes == 1) + return GIMP_BRUSH (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]]; + brushix = 0; + for (i = 0; i < pipe->dimension; i++) + { + switch (pipe->select[i]) + { + case PIPE_SELECT_CONSTANT: + /* What constant? */ + value = 0; + break; + case PIPE_SELECT_INCREMENTAL: + value = pipe->index[i] = (pipe->index[i] + 1) % pipe->rank[i]; + break; + case PIPE_SELECT_ANGULAR: + angle = atan2 (paint_core->cury - paint_core->lasty, + paint_core->curx - paint_core->lastx); + if (angle < 0) + angle += 2.*G_PI; + value = RINT (angle / (2.*G_PI) * pipe->rank[i]); + break; + case PIPE_SELECT_RANDOM: + /* This probably isn't the right way */ + value = rand () % pipe->rank[i]; + break; + case PIPE_SELECT_PRESSURE: + value = RINT (paint_core->curpressure * (pipe->rank[i] - 1)); + break; + case PIPE_SELECT_TILT_X: + value = RINT (paint_core->curxtilt / 2.0 * pipe->rank[i]) + pipe->rank[i]/2; + break; + case PIPE_SELECT_TILT_Y: + value = RINT (paint_core->curytilt / 2.0 * pipe->rank[i]) + pipe->rank[i]/2; + break; + } + brushix += pipe->stride[i] * value; + /* g_print ("value at %d: %d, brushix: %d\n", i, value, brushix); */ + } - return GIMP_BRUSH (pixmap->pipe->current); + /* If out of bounds, just select the first brush... */ + brushix = BOUNDS (brushix, 0, pipe->nbrushes-1); + + pipe->current = pipe->brushes[brushix]; + + return GIMP_BRUSH (pipe->current); } static void @@ -138,6 +196,7 @@ gimp_brush_pipe_destroy(GtkObject *object) pipe = GIMP_BRUSH_PIPE (object); g_free (pipe->rank); + g_free (pipe->stride); for (i = 1; i < pipe->nbrushes; i++) gimp_object_destroy (pipe->brushes[i]); @@ -190,6 +249,91 @@ gimp_brush_pipe_get_type (void) return type; } +static void +init_pipe_parameters () +{ + int i; + + gihparms.step = 100; + gihparms.ncells = 1; + gihparms.dim = 1; + gihparms.cols = 1; + gihparms.rows = 1; + gihparms.placement = "constant"; + for (i = 0; i < MAXDIM; i++) + gihparms.selection[i] = "random"; + gihparms.rank[0] = 1; + for (i = 1; i < MAXDIM; i++) + gihparms.rank[i] = 0; +} + +static void +parse_brush_pipe_parameters (gchar *parameters) +{ + guchar *p, *q, *r, *s; /* Don't you love single-char identifiers? */ + gint i; + + q = parameters; + while ((p = strtok (q, " \r\n")) != NULL) + { + q = NULL; + r = strchr (p, ':'); + if (r) + *r = 0; + + if (strcmp (p, "ncells") == 0) + { + if (r) + gihparms.ncells = atoi (r + 1); + } + else if (strcmp (p, "step") == 0) + { + if (r) + gihparms.step = atoi (r + 1); + } + else if (strcmp (p, "dim") == 0) + { + if (r) + gihparms.dim = atoi (r + 1); + } + else if (strcmp (p, "cols") == 0) + { + if (r) + gihparms.cols = atoi (r + 1); + } + else if (strcmp (p, "rows") == 0) + { + if (r) + gihparms.rows = atoi (r + 1); + } + else if (strcmp (p, "placement") == 0) + { + if (r) + gihparms.placement = g_strdup (r + 1); + } + else if (strncmp (p, "rank", strlen ("rank")) == 0) + { + if (r) + { + i = atoi (p + strlen ("rank")); + if (i >= 0 && i < gihparms.dim) + gihparms.rank[i] = atoi (r + 1); + } + } + else if (strncmp (p, "sel", strlen ("sel")) == 0) + { + if (r) + { + i = atoi (p + strlen ("sel")); + if (i >= 0 && i < gihparms.dim) + gihparms.selection[i] = g_strdup (r + 1); + } + } + if (r) + *r = ':'; + } +} + GimpBrushPipe * gimp_brush_pipe_load (char *filename) { @@ -198,8 +342,10 @@ gimp_brush_pipe_load (char *filename) FILE *fp; guchar buf[1024]; guchar *name; + int i; int num_of_brushes; - guchar *params; + int totalcells; + gchar *params; if ((fp = fopen (filename, "rb")) == NULL) return NULL; @@ -233,16 +379,62 @@ gimp_brush_pipe_load (char *filename) return NULL; } - /* 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; + while (*params && isspace(*params)) + params++; + + if (*params) + { + init_pipe_parameters (); + parse_brush_pipe_parameters (params); + pipe->dimension = gihparms.dim; + 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++) + { + pipe->rank[i] = gihparms.rank[i]; + if (strcmp (gihparms.selection[i], "incremental") == 0) + pipe->select[i] = PIPE_SELECT_INCREMENTAL; + else if (strcmp (gihparms.selection[i], "angular") == 0) + pipe->select[i] = PIPE_SELECT_ANGULAR; + else if (strcmp (gihparms.selection[i], "velocity") == 0) + pipe->select[i] = PIPE_SELECT_VELOCITY; + else if (strcmp (gihparms.selection[i], "random") == 0) + pipe->select[i] = PIPE_SELECT_RANDOM; + else if (strcmp (gihparms.selection[i], "pressure") == 0) + pipe->select[i] = PIPE_SELECT_PRESSURE; + else if (strcmp (gihparms.selection[i], "xtilt") == 0) + pipe->select[i] = PIPE_SELECT_TILT_X; + else if (strcmp (gihparms.selection[i], "ytilt") == 0) + 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); pattern = (GPatternP) g_malloc (sizeof (GPattern)); pattern->filename = NULL; diff --git a/app/core/gimpbrushpipe.h b/app/core/gimpbrushpipe.h index bca9ea5d08..06e80617b9 100644 --- a/app/core/gimpbrushpipe.h +++ b/app/core/gimpbrushpipe.h @@ -25,17 +25,6 @@ #include "gimpbrush.h" #include "temp_buf.h" -typedef enum -{ - PIPE_SELECT_INCREMENTAL, - PIPE_SELECT_DIRECTION, - PIPE_SELECT_VELOCITY, - PIPE_SELECT_RANDOM, - PIPE_SELECT_PRESSURE, - PIPE_SELECT_TILT_X, - PIPE_SELECT_TILT_Y -} PipeSelectModes; - typedef struct _GimpBrushPixmap GimpBrushPixmap; typedef struct _GimpBrushPipe GimpBrushPipe; diff --git a/app/gimpbrushpipe.c b/app/gimpbrushpipe.c index 3ea9e6f2bc..5793e82271 100644 --- a/app/gimpbrushpipe.c +++ b/app/gimpbrushpipe.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "appenv.h" #include "brush_header.h" @@ -35,6 +36,26 @@ #include "gimprc.h" #include "libgimp/gimpintl.h" +/* Code duplicated from plug-ins/common/gpb.c... + * The struct, and code to parse/build it probably should be in libgimp. + */ + +/* Parameters related to one single gih file, collected in a struct + * just for clarity. + */ +#define MAXDIM 4 +static struct { + gint step; + gint ncells; + gint dim; + gint cols; + gint rows; + gchar *placement; + gint rank[MAXDIM]; + gchar *selection[MAXDIM]; +} gihparms; + + static GimpBrushClass* gimp_brush_class; static GtkObjectClass* gimp_object_class; @@ -107,23 +128,60 @@ gimp_brush_pixmap_get_type (void) static GimpBrush * gimp_brush_pixmap_select_brush (PaintCore *paint_core) { - GimpBrushPixmap *pixmap; + GimpBrushPipe *pipe; + int i, brushix, value; + double angle; g_return_val_if_fail (GIMP_IS_BRUSH_PIXMAP (paint_core->brush), NULL); - pixmap = GIMP_BRUSH_PIXMAP (paint_core->brush); + pipe = GIMP_BRUSH_PIXMAP (paint_core->brush)->pipe; - if (pixmap->pipe->nbrushes == 1) - return GIMP_BRUSH (pixmap->pipe->current); + if (pipe->nbrushes == 1) + return GIMP_BRUSH (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]]; + brushix = 0; + for (i = 0; i < pipe->dimension; i++) + { + switch (pipe->select[i]) + { + case PIPE_SELECT_CONSTANT: + /* What constant? */ + value = 0; + break; + case PIPE_SELECT_INCREMENTAL: + value = pipe->index[i] = (pipe->index[i] + 1) % pipe->rank[i]; + break; + case PIPE_SELECT_ANGULAR: + angle = atan2 (paint_core->cury - paint_core->lasty, + paint_core->curx - paint_core->lastx); + if (angle < 0) + angle += 2.*G_PI; + value = RINT (angle / (2.*G_PI) * pipe->rank[i]); + break; + case PIPE_SELECT_RANDOM: + /* This probably isn't the right way */ + value = rand () % pipe->rank[i]; + break; + case PIPE_SELECT_PRESSURE: + value = RINT (paint_core->curpressure * (pipe->rank[i] - 1)); + break; + case PIPE_SELECT_TILT_X: + value = RINT (paint_core->curxtilt / 2.0 * pipe->rank[i]) + pipe->rank[i]/2; + break; + case PIPE_SELECT_TILT_Y: + value = RINT (paint_core->curytilt / 2.0 * pipe->rank[i]) + pipe->rank[i]/2; + break; + } + brushix += pipe->stride[i] * value; + /* g_print ("value at %d: %d, brushix: %d\n", i, value, brushix); */ + } - return GIMP_BRUSH (pixmap->pipe->current); + /* If out of bounds, just select the first brush... */ + brushix = BOUNDS (brushix, 0, pipe->nbrushes-1); + + pipe->current = pipe->brushes[brushix]; + + return GIMP_BRUSH (pipe->current); } static void @@ -138,6 +196,7 @@ gimp_brush_pipe_destroy(GtkObject *object) pipe = GIMP_BRUSH_PIPE (object); g_free (pipe->rank); + g_free (pipe->stride); for (i = 1; i < pipe->nbrushes; i++) gimp_object_destroy (pipe->brushes[i]); @@ -190,6 +249,91 @@ gimp_brush_pipe_get_type (void) return type; } +static void +init_pipe_parameters () +{ + int i; + + gihparms.step = 100; + gihparms.ncells = 1; + gihparms.dim = 1; + gihparms.cols = 1; + gihparms.rows = 1; + gihparms.placement = "constant"; + for (i = 0; i < MAXDIM; i++) + gihparms.selection[i] = "random"; + gihparms.rank[0] = 1; + for (i = 1; i < MAXDIM; i++) + gihparms.rank[i] = 0; +} + +static void +parse_brush_pipe_parameters (gchar *parameters) +{ + guchar *p, *q, *r, *s; /* Don't you love single-char identifiers? */ + gint i; + + q = parameters; + while ((p = strtok (q, " \r\n")) != NULL) + { + q = NULL; + r = strchr (p, ':'); + if (r) + *r = 0; + + if (strcmp (p, "ncells") == 0) + { + if (r) + gihparms.ncells = atoi (r + 1); + } + else if (strcmp (p, "step") == 0) + { + if (r) + gihparms.step = atoi (r + 1); + } + else if (strcmp (p, "dim") == 0) + { + if (r) + gihparms.dim = atoi (r + 1); + } + else if (strcmp (p, "cols") == 0) + { + if (r) + gihparms.cols = atoi (r + 1); + } + else if (strcmp (p, "rows") == 0) + { + if (r) + gihparms.rows = atoi (r + 1); + } + else if (strcmp (p, "placement") == 0) + { + if (r) + gihparms.placement = g_strdup (r + 1); + } + else if (strncmp (p, "rank", strlen ("rank")) == 0) + { + if (r) + { + i = atoi (p + strlen ("rank")); + if (i >= 0 && i < gihparms.dim) + gihparms.rank[i] = atoi (r + 1); + } + } + else if (strncmp (p, "sel", strlen ("sel")) == 0) + { + if (r) + { + i = atoi (p + strlen ("sel")); + if (i >= 0 && i < gihparms.dim) + gihparms.selection[i] = g_strdup (r + 1); + } + } + if (r) + *r = ':'; + } +} + GimpBrushPipe * gimp_brush_pipe_load (char *filename) { @@ -198,8 +342,10 @@ gimp_brush_pipe_load (char *filename) FILE *fp; guchar buf[1024]; guchar *name; + int i; int num_of_brushes; - guchar *params; + int totalcells; + gchar *params; if ((fp = fopen (filename, "rb")) == NULL) return NULL; @@ -233,16 +379,62 @@ gimp_brush_pipe_load (char *filename) return NULL; } - /* 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; + while (*params && isspace(*params)) + params++; + + if (*params) + { + init_pipe_parameters (); + parse_brush_pipe_parameters (params); + pipe->dimension = gihparms.dim; + 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++) + { + pipe->rank[i] = gihparms.rank[i]; + if (strcmp (gihparms.selection[i], "incremental") == 0) + pipe->select[i] = PIPE_SELECT_INCREMENTAL; + else if (strcmp (gihparms.selection[i], "angular") == 0) + pipe->select[i] = PIPE_SELECT_ANGULAR; + else if (strcmp (gihparms.selection[i], "velocity") == 0) + pipe->select[i] = PIPE_SELECT_VELOCITY; + else if (strcmp (gihparms.selection[i], "random") == 0) + pipe->select[i] = PIPE_SELECT_RANDOM; + else if (strcmp (gihparms.selection[i], "pressure") == 0) + pipe->select[i] = PIPE_SELECT_PRESSURE; + else if (strcmp (gihparms.selection[i], "xtilt") == 0) + pipe->select[i] = PIPE_SELECT_TILT_X; + else if (strcmp (gihparms.selection[i], "ytilt") == 0) + 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); pattern = (GPatternP) g_malloc (sizeof (GPattern)); pattern->filename = NULL; diff --git a/app/gimpbrushpipe.h b/app/gimpbrushpipe.h index bca9ea5d08..06e80617b9 100644 --- a/app/gimpbrushpipe.h +++ b/app/gimpbrushpipe.h @@ -25,17 +25,6 @@ #include "gimpbrush.h" #include "temp_buf.h" -typedef enum -{ - PIPE_SELECT_INCREMENTAL, - PIPE_SELECT_DIRECTION, - PIPE_SELECT_VELOCITY, - PIPE_SELECT_RANDOM, - PIPE_SELECT_PRESSURE, - PIPE_SELECT_TILT_X, - PIPE_SELECT_TILT_Y -} PipeSelectModes; - typedef struct _GimpBrushPixmap GimpBrushPixmap; typedef struct _GimpBrushPipe GimpBrushPipe; diff --git a/app/gimpbrushpipeP.h b/app/gimpbrushpipeP.h index 84cec00238..99eb05ff0a 100644 --- a/app/gimpbrushpipeP.h +++ b/app/gimpbrushpipeP.h @@ -20,6 +20,18 @@ #ifndef __GIMPBRUSHPIPEP_H__ #define __GIMPBRUSHPIPEP_H__ +typedef enum +{ + PIPE_SELECT_CONSTANT, + PIPE_SELECT_INCREMENTAL, + PIPE_SELECT_ANGULAR, + PIPE_SELECT_VELOCITY, + PIPE_SELECT_RANDOM, + PIPE_SELECT_PRESSURE, + PIPE_SELECT_TILT_X, + PIPE_SELECT_TILT_Y +} PipeSelectModes; + /* A GimpBrushPixmap always exists as part in one and only one GimpBrushPipe * It contains a back-pointer to the GimpBrushPipe so that we can select * the next brush in the pipe with just a reference to the GimpBrushPipe. @@ -38,8 +50,10 @@ struct _GimpBrushPipe GimpBrushPixmap *current; /* Currently selected brush */ int dimension; int *rank; /* Size in each dimension */ + int *stride; /* Aux for indexing */ int nbrushes; /* Might be less than the product of the - * ranks in some special case */ + * ranks in some odd special case + */ GimpBrushPixmap **brushes; PipeSelectModes *select; /* One mode per dimension */ int *index; /* Current index for incremental dimensions */ diff --git a/app/makefile.cygwin b/app/makefile.cygwin index 47900f02f7..d848683bfd 100644 --- a/app/makefile.cygwin +++ b/app/makefile.cygwin @@ -261,7 +261,7 @@ gimp.exe : ../config.h $(gimp_OBJECTS) libgimpim.a gimp.def gimpres.o $(DLLTOOL) --base-file gimp.base --input-def gimp.def --output-exp gimp.exp $(CC) $(CFLAGS) -Wl,--base-file,gimp.base,gimp.exp -mwindows -o gimp.exe $(gimp_OBJECTS) -L . -lgimpim -L ../libgimp -lgimpi -L $(GTK)/gtk -lgtk-$(GTK_VER) -L $(GTK)/gdk/win32 -lgdk-$(GTK_VER) -L $(INTL) -lgnu-intl -L $(GLIB) -lglib-$(GLIB_VER) -lgmodule-$(GLIB_VER) gimpres.o -lgdi32 -luser32 $(DLLTOOL) --base-file gimp.base --input-def gimp.def --output-exp gimp.exp - $(CC) -v $(CFLAGS) -Wl,gimp.exp -mwindows -o gimp.exe $(gimp_OBJECTS) -L. -lgimpim -L ../libgimp -lgimpi -L $(GTK)/gtk -lgtk-$(GTK_VER) -L $(GTK)/gdk/win32 -lgdk-$(GTK_VER) -L $(INTL) -lgnu-intl -L $(GLIB) -lglib-$(GLIB_VER) -lgmodule-$(GLIB_VER) gimpres.o -lgdi32 -luser32 + $(CC) $(CFLAGS) -Wl,gimp.exp -mwindows -o gimp.exe $(gimp_OBJECTS) -L. -lgimpim -L ../libgimp -lgimpi -L $(GTK)/gtk -lgtk-$(GTK_VER) -L $(GTK)/gdk/win32 -lgdk-$(GTK_VER) -L $(INTL) -lgnu-intl -L $(GLIB) -lglib-$(GLIB_VER) -lgmodule-$(GLIB_VER) gimpres.o -lgdi32 -luser32 $(DLLTOOL) --dllname gimp.exe gimp.def --output-lib libgimp.a $(gimp_OBJECTS) .SUFFIXES: .c .o .i diff --git a/docs/parasites.txt b/docs/parasites.txt index 00e3e0230d..060266468c 100644 --- a/docs/parasites.txt +++ b/docs/parasites.txt @@ -65,15 +65,15 @@ gimp-brush-pipe-parameters" (IMAGE, PERSISTENT) and three-dimensional pipes, it probably is. rank0, rank1, ...: (one for each dimension): the index range for that dimension - spacing: "default", "constant" or "random". "constant" means - use the spacing in the first brush in the pipe. - "random" means perturb that with some suitable - random number function. (Hmm, would it be overdoing it - if the pipe also could specify what random function - and its parameters...?) + placement: "default", "constant" or "random". "constant" means + use the spacing in the first brush in the pipe. + "random" means perturb that with some suitable + random number function. (Hmm, would it be overdoing it + if the pipe also could specify what random function + and its parameters...?) sel0, sel1, ...: "default", "random", "incremental", "angular", "pressure", "velocity", and whatever else suitable we might - think of ;-) How one index from each dimension is + think of ;-) Determines how one index from each dimension is selected (until we have pinpointed the brush to use). "tiff-save-options" (IMAGE) diff --git a/plug-ins/common/gpb.c b/plug-ins/common/gpb.c index 1b266c7ed1..e6122ae29d 100644 --- a/plug-ins/common/gpb.c +++ b/plug-ins/common/gpb.c @@ -59,14 +59,17 @@ static gint run_flag = 0; static gint num_layers_with_alpha; /* Parameters related to one single gih file, collected in a struct - * just for clarity. */ + * just for clarity. + */ static struct { gint step; gint ncells; gint dim; gint cols; gint rows; + gchar *placement; gint rank[MAXDIM]; + gchar *selection[MAXDIM]; } gihparms; /* Declare some local functions. @@ -171,6 +174,13 @@ entry_callback (GtkWidget *widget, } } +static void +cb_callback (GtkWidget *widget, + gpointer data) +{ + *((char **) data) = gtk_entry_get_text (GTK_ENTRY (widget)); +} + static void close_callback (GtkWidget *widget, gpointer data) @@ -315,12 +325,14 @@ static gint gih_save_dialog () { GtkWidget *dlg; - GtkWidget *table; + GtkWidget *table, *dimtable; GtkWidget *label; GtkObject *adjustment; GtkWidget *spinbutton; GtkWidget *entry; GtkWidget *box; + GtkWidget *cb; + GList *cbitems = NULL; gint i; gchar **argv; gint argc; @@ -353,6 +365,36 @@ gih_save_dialog () common_save_dialog (dlg, table); + /* + * Number of cells: ___ + */ + + gtk_table_resize (GTK_TABLE (table), + GTK_TABLE (table)->nrows + 1, GTK_TABLE (table)->ncols); + + label = gtk_label_new ("Number of cells:"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, + GTK_TABLE (table)->nrows - 1, GTK_TABLE (table)->nrows, + GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + + adjustment = gtk_adjustment_new (gihparms.ncells, 1, 1000, 1, 10, 10); + spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adjustment), 1, 0); + gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinbutton), + GTK_SHADOW_NONE); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE); + gtk_widget_set_usize (spinbutton, 75, 0); + box = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (box), spinbutton, FALSE, TRUE, 0); + gtk_table_attach (GTK_TABLE (table), box, 1, 2, + GTK_TABLE (table)->nrows - 1, GTK_TABLE (table)->nrows, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", + (GtkSignalFunc) adjustment_callback, &gihparms.ncells); + gtk_widget_show (spinbutton); + gtk_widget_show (box); + /* * Display as: __ rows x __ cols */ @@ -403,36 +445,6 @@ gih_save_dialog () GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (box); - /* - * Number of cells: ___ - */ - - gtk_table_resize (GTK_TABLE (table), - GTK_TABLE (table)->nrows + 1, GTK_TABLE (table)->ncols); - - label = gtk_label_new ("Number of cells:"); - gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, - GTK_TABLE (table)->nrows - 1, GTK_TABLE (table)->nrows, - GTK_FILL, GTK_FILL, 0, 0); - gtk_widget_show (label); - - adjustment = gtk_adjustment_new (gihparms.ncells, 1, 1000, 1, 10, 10); - spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adjustment), 1, 0); - gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinbutton), - GTK_SHADOW_NONE); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE); - gtk_widget_set_usize (spinbutton, 75, 0); - box = gtk_hbox_new (FALSE, 0); - gtk_box_pack_start (GTK_BOX (box), spinbutton, FALSE, TRUE, 0); - gtk_table_attach (GTK_TABLE (table), box, 1, 2, - GTK_TABLE (table)->nrows - 1, GTK_TABLE (table)->nrows, - GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); - gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", - (GtkSignalFunc) adjustment_callback, &gihparms.ncells); - gtk_widget_show (spinbutton); - gtk_widget_show (box); - /* * Dimension: ___ */ @@ -477,7 +489,7 @@ gih_save_dialog () GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (label); - box = gtk_hbox_new (FALSE, 0); + dimtable = gtk_table_new (MAXDIM, 1, FALSE); for (i = 0; i < MAXDIM; i++) { adjustment = gtk_adjustment_new (gihparms.rank[i], 0, 100, 1, 1, 1); @@ -486,15 +498,64 @@ gih_save_dialog () GTK_SHADOW_NONE); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE); gtk_widget_set_usize (spinbutton, 75, 0); - gtk_box_pack_start (GTK_BOX (box), spinbutton, FALSE, TRUE, 2); + box = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (box), spinbutton, FALSE, TRUE, 0); + gtk_table_attach (GTK_TABLE (dimtable), box, i, i + 1, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 3, 0); gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", (GtkSignalFunc) adjustment_callback, &gihparms.rank[i]); gtk_widget_show (spinbutton); + gtk_widget_show (box); } + gtk_table_attach (GTK_TABLE (table), dimtable, 1, 2, + GTK_TABLE (table)->nrows - 1, GTK_TABLE (table)->nrows, + GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (dimtable); + + /* + * Selection: ______ ______ ______ ______ ______ + */ + + gtk_table_resize (GTK_TABLE (table), + GTK_TABLE (table)->nrows + 1, GTK_TABLE (table)->ncols); + + label = gtk_label_new ("Selection:"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, + GTK_TABLE (table)->nrows - 1, GTK_TABLE (table)->nrows, + GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + + cbitems = g_list_append (cbitems, "incremental"); + cbitems = g_list_append (cbitems, "angular"); + cbitems = g_list_append (cbitems, "random"); + cbitems = g_list_append (cbitems, "velocity"); + cbitems = g_list_append (cbitems, "pressure"); + cbitems = g_list_append (cbitems, "xtilt"); + cbitems = g_list_append (cbitems, "ytilt"); + + box = gtk_hbox_new (FALSE, 0); + for (i = 0; i < MAXDIM; i++) + { + cb = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (cb), cbitems); + if (gihparms.selection[i]) + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (cb)->entry), gihparms.selection[i]); + gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (cb)->entry), FALSE); + + gtk_box_pack_start (GTK_BOX (box), cb, FALSE, TRUE, 2); + gtk_signal_connect (GTK_OBJECT (GTK_COMBO (cb)->entry), "changed", + (GtkSignalFunc) cb_callback, &gihparms.selection[i]); + gtk_widget_show (cb); + } + + g_list_free (cbitems); + gtk_table_attach (GTK_TABLE (table), box, 1, 2, GTK_TABLE (table)->nrows - 1, GTK_TABLE (table)->nrows, GTK_SHRINK, GTK_EXPAND | GTK_FILL, 0, 0); gtk_widget_show (box); + gtk_widget_show (dlg); gtk_main (); @@ -700,6 +761,24 @@ gpb_save_image (char *filename, return TRUE; } +static void +init_pipe_parameters () +{ + int i; + + gihparms.step = 100; + gihparms.ncells = 1; + gihparms.dim = 1; + gihparms.cols = 1; + gihparms.rows = 1; + gihparms.placement = "constant"; + for (i = 0; i < MAXDIM; i++) + gihparms.selection[i] = "random"; + gihparms.rank[0] = 1; + for (i = 1; i < MAXDIM; i++) + gihparms.rank[i] = 0; +} + static void parse_brush_pipe_parameters (gchar *parameters) { @@ -741,11 +820,28 @@ parse_brush_pipe_parameters (gchar *parameters) if (r) gihparms.rows = atoi (r + 1); } - else if (strncmp (p, "rank", 4) == 0 && r) + else if (strcmp (p, "placement") == 0) { - i = atoi (p + 4); - if (i >= 0 && i < gihparms.dim) - gihparms.rank[i] = atoi (r + 1); + if (r) + gihparms.placement = g_strdup (r + 1); + } + else if (strncmp (p, "rank", strlen ("rank")) == 0 && r) + { + if (r) + { + i = atoi (p + strlen ("rank")); + if (i >= 0 && i < gihparms.dim) + gihparms.rank[i] = atoi (r + 1); + } + } + else if (strncmp (p, "sel", strlen ("sel")) == 0 && r) + { + if (r) + { + i = atoi (p + strlen ("sel")); + if (i >= 0 && i < gihparms.dim) + gihparms.selection[i] = g_strdup (r + 1); + } } if (r) *r = ':'; @@ -753,12 +849,16 @@ parse_brush_pipe_parameters (gchar *parameters) IFDBG(2) g_message ("parsed parasite: " "ncells:%d step:%d dim:%d cols:%d rows:%d " - "rank0:%d rank1:%d rank2:%d rank3:%d", + "placement:%s " + "rank0:%d rank1:%d rank2:%d rank3:%d" + "sel%d:%s sel%d:%s sel%d:%s ", gihparms.ncells, gihparms.step, - gihparms.dim, - gihparms.cols, gihparms.rows, + gihparms.dim, gihparms.cols, gihparms.rows, + gihparms.placement, gihparms.rank[0], gihparms.rank[1], - gihparms.rank[2], gihparms.rank[3]); + gihparms.rank[2], gihparms.rank[3], + gihparms.selection[0], gihparms.selection[1], + gihparms.selection[2], gihparms.selection[3]); } static gchar * @@ -769,13 +869,17 @@ build_brush_pipe_parameters () int i; - g_string_sprintf (s, "ncells:%d step:%d dim:%d cols:%d rows:%d", + g_string_sprintf (s, "ncells:%d step:%d dim:%d cols:%d rows:%d placement:%s", gihparms.ncells, gihparms.step, gihparms.dim, - gihparms.cols, gihparms.rows); + gihparms.cols, gihparms.rows, + gihparms.placement); for (i = 0; i < gihparms.dim; i++) - g_string_sprintfa (s, " rank%d:%d", i, gihparms.rank[i]); + { + g_string_sprintfa (s, " rank%d:%d", i, gihparms.rank[i]); + g_string_sprintfa (s, " sel%d:%s", i, gihparms.selection[i]); + } str = s->str; g_string_free (s, FALSE); @@ -792,6 +896,7 @@ gih_save_image (char *filename, GDrawable *drawable; GPixelRgn pixel_rgn; FILE *file; + Parasite *pipe_parasite; gchar *msg, *pars, *ncells; gint32 *layer_ID; gint nlayers, layer, row, col; @@ -826,6 +931,13 @@ gih_save_image (char *filename, g_free (ncells); return FALSE; } + + pipe_parasite = parasite_new ("gimp-brush-pipe-parameters", + PARASITE_PERSISTENT, + strlen (pars) + 1, pars); + gimp_image_attach_parasite (image_ID, pipe_parasite); + parasite_free (pipe_parasite); + g_free (pars); g_free (ncells); @@ -958,11 +1070,12 @@ run (char *name, /* Possibly retrieve data */ gimp_get_data ("file_gih_save", &info); pipe_parasite = gimp_image_find_parasite (image_ID, "gimp-brush-pipe-parameters"); + init_pipe_parameters (); if (pipe_parasite) { parse_brush_pipe_parameters (pipe_parasite->data); } - + if (!gih_save_dialog ()) return; break; diff --git a/plug-ins/common/psp.c b/plug-ins/common/psp.c index c60682c886..9303f763ba 100644 --- a/plug-ins/common/psp.c +++ b/plug-ins/common/psp.c @@ -1499,7 +1499,7 @@ read_tube_block (FILE *f, parasite_text = g_strdup_printf ("ncells:%d step:%d dim:%d cols:%d rows:%d " "rank0:%d " - "spacing:%s sel0:%s", + "placement:%s sel0:%s", cell_count, step_size, 1, column_count, row_count, cell_count, (placement_mode == tpmRandom ? "random" :