Implement the selection of brush based on cursor direction, pressure,

1999-08-28  Tor Lillqvist  <tml@iki.fi>

* 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).
This commit is contained in:
Tor Lillqvist 1999-08-28 01:14:42 +00:00 committed by Tor Lillqvist
parent 58d782985a
commit 70fca093f3
11 changed files with 846 additions and 144 deletions

View file

@ -1,3 +1,24 @@
1999-08-28 Tor Lillqvist <tml@iki.fi>
* 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 <yosh@gimp.org>
* app/color_display.h: just include parasiteF.h

View file

@ -23,6 +23,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#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;

View file

@ -23,6 +23,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#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;

View file

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

View file

@ -23,6 +23,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#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;

View file

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

View file

@ -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 */

View file

@ -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

View file

@ -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)

View file

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

View file

@ -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" :