Index: app/core/Makefile.am =================================================================== --- app/core/Makefile.am (revision 24040) +++ app/core/Makefile.am (working copy) @@ -90,6 +90,12 @@ libappcore_a_sources = \ gimpcontext.h \ gimpcoords.c \ gimpcoords.h \ + gimpcurve.c \ + gimpcurve.h \ + gimpcurve-load.c \ + gimpcurve-load.h \ + gimpcurve-save.c \ + gimpcurve-save.h \ gimpdashpattern.c \ gimpdashpattern.h \ gimpdata.c \ Index: app/core/gimpcurve-save.c =================================================================== --- app/core/gimpcurve-save.c (revision 0) +++ app/core/gimpcurve-save.c (revision 0) @@ -0,0 +1,59 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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. + */ + +#include "config.h" + +#include + +#include +#include + +#include "libgimpbase/gimpbase.h" + +#include "core-types.h" + +#include "gimpcurve.h" +#include "gimpcurve-save.h" + +#include "gimp-intl.h" + + +gboolean +gimp_curve_save (GimpData *data, + GError **error) +{ + GimpCurve *curve = GIMP_CURVE (data); + FILE *file; + + file = g_fopen (data->filename, "wb"); + + if (! file) + { + g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_OPEN, + _("Could not open '%s' for writing: %s"), + gimp_filename_to_utf8 (data->filename), + g_strerror (errno)); + return FALSE; + } + + /* write curve */ + + fclose (file); + + return TRUE; +} Index: app/core/gimpcurve-save.h =================================================================== --- app/core/gimpcurve-save.h (revision 0) +++ app/core/gimpcurve-save.h (revision 0) @@ -0,0 +1,28 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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. + */ + +#ifndef __GIMP_CURVE_SAVE_H__ +#define __GIMP_CURVE_SAVE_H__ + + +/* don't call this function directly, use gimp_data_save() instead */ +gboolean gimp_curve_save (GimpData *data, + GError **error); + + +#endif /* __GIMP_CURVE_SAVE_H__ */ Index: app/core/gimpcurve-load.c =================================================================== --- app/core/gimpcurve-load.c (revision 0) +++ app/core/gimpcurve-load.c (revision 0) @@ -0,0 +1,66 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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. + */ + +#include "config.h" + +#include + +#include +#include + +#include "libgimpbase/gimpbase.h" + +#ifdef G_OS_WIN32 +#include "libgimpbase/gimpwin32-io.h" +#endif + +#include "core-types.h" + +#include "gimpcurve.h" +#include "gimpcurve-load.h" + +#include "gimp-intl.h" + + +GList * +gimp_curve_load (const gchar *filename, + GError **error) +{ + GimpCurve *curve; + FILE *file; + + g_return_val_if_fail (filename != NULL, NULL); + g_return_val_if_fail (g_path_is_absolute (filename), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + file = g_fopen (filename, "rb"); + + if (! file) + { + g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_OPEN, + _("Could not open '%s' for reading: %s"), + gimp_filename_to_utf8 (filename), g_strerror (errno)); + return NULL; + } + + /* load curves */ + + fclose (file); + + return NULL; +} Index: app/core/gimpcurve-load.h =================================================================== --- app/core/gimpcurve-load.h (revision 0) +++ app/core/gimpcurve-load.h (revision 0) @@ -0,0 +1,30 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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. + */ + +#ifndef __GIMP_CURVE_LOAD_H__ +#define __GIMP_CURVE_LOAD_H__ + + +#define GIMP_CURVE_FILE_EXTENSION ".curve" + + +GList * gimp_curve_load (const gchar *filename, + GError **error); + + +#endif /* __GIMP_CURVE_LOAD_H__ */ Index: app/core/core-types.h =================================================================== --- app/core/core-types.h (revision 24040) +++ app/core/core-types.h (working copy) @@ -95,6 +95,7 @@ typedef struct _GimpGradient Gim typedef struct _GimpPattern GimpPattern; typedef struct _GimpPatternClipboard GimpPatternClipboard; typedef struct _GimpPalette GimpPalette; +typedef struct _GimpCurve GimpCurve; /* drawable objects */ Index: app/core/gimpcurve.c =================================================================== --- app/core/gimpcurve.c (revision 0) +++ app/core/gimpcurve.c (revision 0) @@ -0,0 +1,594 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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. + */ + +#include "config.h" + +#include +#include + +#include + +#include "libgimpmath/gimpmath.h" + +#include "core-types.h" + +#include "gimpcurve.h" +#include "gimpcurve-load.h" +#include "gimpcurve-save.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_CURVE_TYPE +}; + + +/* local function prototypes */ + +static void gimp_curve_finalize (GObject *object); +static void gimp_curve_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_curve_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + +static gint64 gimp_curve_get_memsize (GimpObject *object, + gint64 *gui_size); + +static void gimp_curve_get_preview_size (GimpViewable *viewable, + gint size, + gboolean popup, + gboolean dot_for_dot, + gint *width, + gint *height); +static gboolean gimp_curve_get_popup_size (GimpViewable *viewable, + gint width, + gint height, + gboolean dot_for_dot, + gint *popup_width, + gint *popup_height); +static TempBuf * gimp_curve_get_new_preview (GimpViewable *viewable, + GimpContext *context, + gint width, + gint height); +static gchar * gimp_curve_get_description (GimpViewable *viewable, + gchar **tooltip); +static gchar * gimp_curve_get_extension (GimpData *data); +static GimpData * gimp_curve_duplicate (GimpData *data); + +static void gimp_curve_plot (GimpCurve *curve, + gint p1, + gint p2, + gint p3, + gint p4); + + +G_DEFINE_TYPE (GimpCurve, gimp_curve, GIMP_TYPE_DATA) + +#define parent_class gimp_curve_parent_class + + +static void +gimp_curve_class_init (GimpCurveClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass); + GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass); + GimpDataClass *data_class = GIMP_DATA_CLASS (klass); + + object_class->finalize = gimp_curve_finalize; + object_class->set_property = gimp_curve_set_property; + object_class->get_property = gimp_curve_get_property; + + gimp_object_class->get_memsize = gimp_curve_get_memsize; + + viewable_class->default_stock_id = "FIXME"; + viewable_class->get_preview_size = gimp_curve_get_preview_size; + viewable_class->get_popup_size = gimp_curve_get_popup_size; + viewable_class->get_new_preview = gimp_curve_get_new_preview; + viewable_class->get_description = gimp_curve_get_description; + + data_class->save = gimp_curve_save; + data_class->get_extension = gimp_curve_get_extension; + data_class->duplicate = gimp_curve_duplicate; + + g_object_class_install_property (object_class, PROP_CURVE_TYPE, + g_param_spec_enum ("curve-type", NULL, NULL, + GIMP_TYPE_CURVE_TYPE, + GIMP_CURVE_SMOOTH, + GIMP_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_curve_init (GimpCurve *curve) +{ + gimp_curve_reset (curve, TRUE); +} + +static void +gimp_curve_finalize (GObject *object) +{ + GimpCurve *curve = GIMP_CURVE (object); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_curve_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpCurve *curve = GIMP_CURVE (object); + + switch (property_id) + { + case PROP_CURVE_TYPE: + gimp_curve_set_curve_type (curve, g_value_get_enum (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_curve_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpCurve *curve = GIMP_CURVE (object); + + switch (property_id) + { + case PROP_CURVE_TYPE: + g_value_set_enum (value, curve->curve_type); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static gint64 +gimp_curve_get_memsize (GimpObject *object, + gint64 *gui_size) +{ + GimpCurve *curve = GIMP_CURVE (object); + gint64 memsize = 0; + + return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object, + gui_size); +} + +static void +gimp_curve_get_preview_size (GimpViewable *viewable, + gint size, + gboolean popup, + gboolean dot_for_dot, + gint *width, + gint *height) +{ + *width = size; + *height = size; +} + +static gboolean +gimp_curve_get_popup_size (GimpViewable *viewable, + gint width, + gint height, + gboolean dot_for_dot, + gint *popup_width, + gint *popup_height) +{ + GimpCurve *curve = GIMP_CURVE (viewable); + + *popup_width = width * 2; + *popup_height = height * 2; + + return TRUE; +} + +static TempBuf * +gimp_curve_get_new_preview (GimpViewable *viewable, + GimpContext *context, + gint width, + gint height) +{ + GimpCurve *curve = GIMP_CURVE (viewable); + + return NULL; +} + +static gchar * +gimp_curve_get_description (GimpViewable *viewable, + gchar **tooltip) +{ + GimpCurve *curve = GIMP_CURVE (viewable); + + return g_strdup_printf ("%s", GIMP_OBJECT (curve)->name); +} + + +static gchar * +gimp_curve_get_extension (GimpData *data) +{ + return GIMP_CURVE_FILE_EXTENSION; +} + +static GimpData * +gimp_curve_duplicate (GimpData *data) +{ + GimpCurve *curve = GIMP_CURVE (data); + GimpCurve *new; + + new = g_object_new (GIMP_TYPE_CURVE, + "curve-type", curve->curve_type, + NULL); + + return GIMP_DATA (new); +} + + +/* public functions */ + +GimpData * +gimp_curve_new (const gchar *name) +{ + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (*name != '\0', NULL); + + return g_object_new (GIMP_TYPE_CURVE, + "name", name, + NULL); +} + +GimpData * +gimp_curve_get_standard (void) +{ + static GimpData *standard_curve = NULL; + + if (! standard_curve) + { + standard_curve = gimp_curve_new ("Standard"); + + standard_curve->dirty = FALSE; + gimp_data_make_internal (standard_curve); + + g_object_ref (standard_curve); + } + + return standard_curve; +} + +void +gimp_curve_reset (GimpCurve *curve, + gboolean reset_type) +{ + gint i; + + g_return_if_fail (GIMP_IS_CURVE (curve)); + + if (reset_type) + curve->curve_type = GIMP_CURVE_SMOOTH; + + for (i = 0; i < 256; i++) + curve->curve[i] = i; + + for (i = 0; i < GIMP_CURVE_NUM_POINTS; i++) + { + curve->points[i][0] = -1; + curve->points[i][1] = -1; + } + + curve->points[0][0] = 0; + curve->points[0][1] = 0; + curve->points[GIMP_CURVE_NUM_POINTS - 1][0] = 255; + curve->points[GIMP_CURVE_NUM_POINTS - 1][1] = 255; + + g_object_freeze_notify (G_OBJECT (curve)); + + /* g_object_notify (G_OBJECT (curve), "points"); */ + /* g_object_notify (G_OBJECT (curve), "curve"); */ + g_object_notify (G_OBJECT (curve), "curve-type"); + + g_object_thaw_notify (G_OBJECT (curve)); +} + +void +gimp_curve_set_curve_type (GimpCurve *curve, + GimpCurveType curve_type) +{ + g_return_if_fail (GIMP_IS_CURVE (curve)); + + if (curve->curve_type != curve_type) + { + curve->curve_type = curve_type; + + if (curve_type == GIMP_CURVE_SMOOTH) + { + gint i; + gint32 index; + + /* pick representative points from the curve and make them + * control points + */ + for (i = 0; i <= 8; i++) + { + index = CLAMP0255 (i * 32); + + curve->points[i * 2][0] = index; + curve->points[i * 2][1] = curve->curve[index]; + } + } + + gimp_curve_calculate (curve); + + g_object_notify (G_OBJECT (curve), "curve-type"); + gimp_data_dirty (GIMP_DATA (curve)); + } +} + +GimpCurveType +gimp_curve_get_curve_type (GimpCurve *curve) +{ + g_return_val_if_fail (GIMP_IS_CURVE (curve), GIMP_CURVE_SMOOTH); + + return curve->curve_type; +} + +#define MIN_DISTANCE 8 + +gint +gimp_curve_get_closest_point (GimpCurve *curve, + gint x) +{ + gint closest_point = 0; + gint distance = G_MAXINT; + gint i; + + g_return_val_if_fail (GIMP_IS_CURVE (curve), 0); + + for (i = 0; i < GIMP_CURVE_NUM_POINTS; i++) + { + if (curve->points[i][0] != -1) + if (abs (x - curve->points[i][0]) < distance) + { + distance = abs (x - curve->points[i][0]); + closest_point = i; + } + } + + if (distance > MIN_DISTANCE) + closest_point = (x + 8) / 16; + + return closest_point; +} + +void +gimp_curve_set_point (GimpCurve *curve, + gint point, + gint x, + gint y) +{ + g_return_if_fail (GIMP_IS_CURVE (curve)); + + if (curve->curve_type == GIMP_CURVE_FREE) + return; + + curve->points[point][0] = x; + curve->points[point][1] = y; + + gimp_curve_calculate (curve); +} + +void +gimp_curve_move_point (GimpCurve *curve, + gint point, + gint y) +{ + g_return_if_fail (GIMP_IS_CURVE (curve)); + + if (curve->curve_type == GIMP_CURVE_FREE) + return; + + curve->points[point][1] = y; + + gimp_curve_calculate (curve); +} + +void +gimp_curve_get_uchar (GimpCurve *curve, + guchar *dest_array) +{ + g_return_if_fail (GIMP_IS_CURVE (curve)); + g_return_if_fail (dest_array != NULL); + + memcpy (dest_array, curve->curve, 256); +} + + +/* private functions */ + +void +gimp_curve_calculate (GimpCurve *curve) +{ + gint i; + gint points[GIMP_CURVE_NUM_POINTS]; + gint num_pts; + gint p1, p2, p3, p4; + + switch (curve->curve_type) + { + case GIMP_CURVE_SMOOTH: + /* cycle through the curves */ + num_pts = 0; + for (i = 0; i < GIMP_CURVE_NUM_POINTS; i++) + if (curve->points[i][0] != -1) + points[num_pts++] = i; + + /* Initialize boundary curve points */ + if (num_pts != 0) + { + for (i = 0; i < curve->points[points[0]][0]; i++) + curve->curve[i] = curve->points[points[0]][1]; + + for (i = curve->points[points[num_pts - 1]][0]; i < 256; i++) + curve->curve[i] = curve->points[points[num_pts - 1]][1]; + } + + for (i = 0; i < num_pts - 1; i++) + { + p1 = points[MAX (i - 1, 0)]; + p2 = points[i]; + p3 = points[i + 1]; + p4 = points[MIN (i + 2, num_pts - 1)]; + + gimp_curve_plot (curve, p1, p2, p3, p4); + } + + /* ensure that the control points are used exactly */ + for (i = 0; i < num_pts; i++) + { + gint x = curve->points[points[i]][0]; + gint y = curve->points[points[i]][1]; + + curve->curve[x] = y; + } + break; + + case GIMP_CURVE_FREE: + break; + } +} + +/* + * This function calculates the curve values between the control points + * p2 and p3, taking the potentially existing neighbors p1 and p4 into + * account. + * + * This function uses a cubic bezier curve for the individual segments and + * calculates the necessary intermediate control points depending on the + * neighbor curve control points. + */ +static void +gimp_curve_plot (GimpCurve *curve, + gint p1, + gint p2, + gint p3, + gint p4) +{ + gint i; + gdouble x0, x3; + gdouble y0, y1, y2, y3; + gdouble dx, dy; + gdouble y, t; + gdouble slope; + + /* the outer control points for the bezier curve. */ + x0 = curve->points[p2][0]; + y0 = curve->points[p2][1]; + x3 = curve->points[p3][0]; + y3 = curve->points[p3][1]; + + /* + * the x values of the inner control points are fixed at + * x1 = 1/3*x0 + 2/3*x3 and x2 = 2/3*x0 + 1/3*x3 + * this ensures that the x values increase linearily with the + * parameter t and enables us to skip the calculation of the x + * values altogehter - just calculate y(t) evenly spaced. + */ + + dx = x3 - x0; + dy = y3 - y0; + + g_return_if_fail (dx > 0); + + if (p1 == p2 && p3 == p4) + { + /* No information about the neighbors, + * calculate y1 and y2 to get a straight line + */ + y1 = y0 + dy / 3.0; + y2 = y0 + dy * 2.0 / 3.0; + } + else if (p1 == p2 && p3 != p4) + { + /* only the right neighbor is available. Make the tangent at the + * right endpoint parallel to the line between the left endpoint + * and the right neighbor. Then point the tangent at the left towards + * the control handle of the right tangent, to ensure that the curve + * does not have an inflection point. + */ + slope = (curve->points[p4][1] - y0) / + (curve->points[p4][0] - x0); + + y2 = y3 - slope * dx / 3.0; + y1 = y0 + (y2 - y0) / 2.0; + } + else if (p1 != p2 && p3 == p4) + { + /* see previous case */ + slope = (y3 - curve->points[p1][1]) / + (x3 - curve->points[p1][0]); + + y1 = y0 + slope * dx / 3.0; + y2 = y3 + (y1 - y3) / 2.0; + } + else /* (p1 != p2 && p3 != p4) */ + { + /* Both neighbors are available. Make the tangents at the endpoints + * parallel to the line between the opposite endpoint and the adjacent + * neighbor. + */ + slope = (y3 - curve->points[p1][1]) / + (x3 - curve->points[p1][0]); + + y1 = y0 + slope * dx / 3.0; + + slope = (curve->points[p4][1] - y0) / + (curve->points[p4][0] - x0); + + y2 = y3 - slope * dx / 3.0; + } + + /* + * finally calculate the y(t) values for the given bezier values. We can + * use homogenously distributed values for t, since x(t) increases linearily. + */ + for (i = 0; i <= dx; i++) + { + t = i / dx; + y = y0 * (1-t) * (1-t) * (1-t) + + 3 * y1 * (1-t) * (1-t) * t + + 3 * y2 * (1-t) * t * t + + y3 * t * t * t; + + curve->curve[ROUND(x0) + i] = CLAMP0255 (ROUND (y)); + } +} Index: app/core/gimpcurve.h =================================================================== --- app/core/gimpcurve.h (revision 0) +++ app/core/gimpcurve.h (revision 0) @@ -0,0 +1,84 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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. + */ + +#ifndef __GIMP_CURVE_H__ +#define __GIMP_CURVE_H__ + + +#include "gimpdata.h" + + +#define GIMP_CURVE_NUM_POINTS 17 /* TODO: get rid of this limit */ + + +#define GIMP_TYPE_CURVE (gimp_curve_get_type ()) +#define GIMP_CURVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_CURVE, GimpCurve)) +#define GIMP_CURVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_CURVE, GimpCurveClass)) +#define GIMP_IS_CURVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_CURVE)) +#define GIMP_IS_CURVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_CURVE)) +#define GIMP_CURVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_CURVE, GimpCurveClass)) + + +typedef struct _GimpCurveClass GimpCurveClass; + +struct _GimpCurve +{ + GimpData parent_instance; + + GimpCurveType curve_type; + + gint points[GIMP_CURVE_NUM_POINTS][2]; + guchar curve[256]; + +}; + +struct _GimpCurveClass +{ + GimpDataClass parent_class; +}; + + +GType gimp_curve_get_type (void) G_GNUC_CONST; + +GimpData * gimp_curve_new (const gchar *name); +GimpData * gimp_curve_get_standard (void); + +void gimp_curve_reset (GimpCurve *curve, + gboolean reset_type); + +void gimp_curve_set_curve_type (GimpCurve *curve, + GimpCurveType curve_type); +GimpCurveType gimp_curve_get_curve_type (GimpCurve *curve); + +gint gimp_curve_get_closest_point (GimpCurve *curve, + gint x); +void gimp_curve_set_point (GimpCurve *curve, + gint point, + gint x, + gint y); +void gimp_curve_move_point (GimpCurve *curve, + gint point, + gint y); + +void gimp_curve_get_uchar (GimpCurve *curve, + guchar *dest_array); + +void gimp_curve_calculate (GimpCurve *curve); + + +#endif /* __GIMP_CURVE_H__ */ Index: app/base/curves.c =================================================================== --- app/base/curves.c (revision 24040) +++ app/base/curves.c (working copy) @@ -29,17 +29,6 @@ #include "gimplut.h" - -/* local function prototypes */ - -static void curves_plot_curve (Curves *curves, - gint channel, - gint p1, - gint p2, - gint p3, - gint p4); - - /* public functions */ void @@ -53,91 +42,10 @@ curves_init (Curves *curves) channel <= GIMP_HISTOGRAM_ALPHA; channel++) { - curves->curve_type[channel] = GIMP_CURVE_SMOOTH; - - curves_channel_reset (curves, channel); - } -} - -void -curves_channel_reset (Curves *curves, - GimpHistogramChannel channel) -{ - gint j; - - g_return_if_fail (curves != NULL); - - for (j = 0; j < 256; j++) - curves->curve[channel][j] = j; - - for (j = 0; j < CURVES_NUM_POINTS; j++) - { - curves->points[channel][j][0] = -1; - curves->points[channel][j][1] = -1; - } - - curves->points[channel][0][0] = 0; - curves->points[channel][0][1] = 0; - curves->points[channel][CURVES_NUM_POINTS - 1][0] = 255; - curves->points[channel][CURVES_NUM_POINTS - 1][1] = 255; -} - -void -curves_calculate_curve (Curves *curves, - GimpHistogramChannel channel) -{ - gint i; - gint points[CURVES_NUM_POINTS]; - gint num_pts; - gint p1, p2, p3, p4; - - g_return_if_fail (curves != NULL); - - switch (curves->curve_type[channel]) - { - case GIMP_CURVE_FREE: - break; - - case GIMP_CURVE_SMOOTH: - /* cycle through the curves */ - num_pts = 0; - for (i = 0; i < CURVES_NUM_POINTS; i++) - if (curves->points[channel][i][0] != -1) - points[num_pts++] = i; - - /* Initialize boundary curve points */ - if (num_pts != 0) - { - for (i = 0; i < curves->points[channel][points[0]][0]; i++) - curves->curve[channel][i] = curves->points[channel][points[0]][1]; - - for (i = curves->points[channel][points[num_pts - 1]][0]; - i < 256; - i++) - curves->curve[channel][i] = - curves->points[channel][points[num_pts - 1]][1]; - } - - for (i = 0; i < num_pts - 1; i++) - { - p1 = points[MAX (i - 1, 0)]; - p2 = points[i]; - p3 = points[i + 1]; - p4 = points[MIN (i + 2, num_pts - 1)]; - - curves_plot_curve (curves, channel, p1, p2, p3, p4); - } - - /* ensure that the control points are used exactly */ - for (i = 0; i < num_pts; i++) - { - gint x = curves->points[channel][points[i]][0]; - gint y = curves->points[channel][points[i]][1]; - - curves->curve[channel][x] = y; - } + gint j; - break; + for (j = 0; j < 256; j++) + curves->curve[channel][j] = j; } } @@ -191,115 +99,3 @@ curves_lut_func (Curves *curves, return inten; } - - -/* private functions */ - -/* - * This function calculates the curve values between the control points - * p2 and p3, taking the potentially existing neighbors p1 and p4 into - * account. - * - * This function uses a cubic bezier curve for the individual segments and - * calculates the necessary intermediate control points depending on the - * neighbor curve control points. - */ - -static void -curves_plot_curve (Curves *curves, - gint channel, - gint p1, - gint p2, - gint p3, - gint p4) -{ - gint i; - gdouble x0, x3; - gdouble y0, y1, y2, y3; - gdouble dx, dy; - gdouble y, t; - gdouble slope; - - /* the outer control points for the bezier curve. */ - x0 = curves->points[channel][p2][0]; - y0 = curves->points[channel][p2][1]; - x3 = curves->points[channel][p3][0]; - y3 = curves->points[channel][p3][1]; - - /* - * the x values of the inner control points are fixed at - * x1 = 1/3*x0 + 2/3*x3 and x2 = 2/3*x0 + 1/3*x3 - * this ensures that the x values increase linearily with the - * parameter t and enables us to skip the calculation of the x - * values altogehter - just calculate y(t) evenly spaced. - */ - - dx = x3 - x0; - dy = y3 - y0; - - g_return_if_fail (dx > 0); - - if (p1 == p2 && p3 == p4) - { - /* No information about the neighbors, - * calculate y1 and y2 to get a straight line - */ - y1 = y0 + dy / 3.0; - y2 = y0 + dy * 2.0 / 3.0; - } - else if (p1 == p2 && p3 != p4) - { - /* only the right neighbor is available. Make the tangent at the - * right endpoint parallel to the line between the left endpoint - * and the right neighbor. Then point the tangent at the left towards - * the control handle of the right tangent, to ensure that the curve - * does not have an inflection point. - */ - slope = (curves->points[channel][p4][1] - y0) / - (curves->points[channel][p4][0] - x0); - - y2 = y3 - slope * dx / 3.0; - y1 = y0 + (y2 - y0) / 2.0; - } - else if (p1 != p2 && p3 == p4) - { - /* see previous case */ - slope = (y3 - curves->points[channel][p1][1]) / - (x3 - curves->points[channel][p1][0]); - - y1 = y0 + slope * dx / 3.0; - y2 = y3 + (y1 - y3) / 2.0; - } - else /* (p1 != p2 && p3 != p4) */ - { - /* Both neighbors are available. Make the tangents at the endpoints - * parallel to the line between the opposite endpoint and the adjacent - * neighbor. - */ - slope = (y3 - curves->points[channel][p1][1]) / - (x3 - curves->points[channel][p1][0]); - - y1 = y0 + slope * dx / 3.0; - - slope = (curves->points[channel][p4][1] - y0) / - (curves->points[channel][p4][0] - x0); - - y2 = y3 - slope * dx / 3.0; - } - - /* - * finally calculate the y(t) values for the given bezier values. We can - * use homogenously distributed values for t, since x(t) increases linearily. - */ - for (i = 0; i <= dx; i++) - { - t = i / dx; - y = y0 * (1-t) * (1-t) * (1-t) + - 3 * y1 * (1-t) * (1-t) * t + - 3 * y2 * (1-t) * t * t + - y3 * t * t * t; - - curves->curve[channel][ROUND(x0) + i] = CLAMP0255 (ROUND (y)); - } -} - Index: app/base/curves.h =================================================================== --- app/base/curves.h (revision 24040) +++ app/base/curves.h (working copy) @@ -19,25 +19,18 @@ #ifndef __CURVES_H__ #define __CURVES_H__ -#define CURVES_NUM_POINTS 17 struct _Curves { - GimpCurveType curve_type[5]; - gint points[5][CURVES_NUM_POINTS][2]; - guchar curve[5][256]; + guchar curve[5][256]; }; -void curves_init (Curves *curves); -void curves_channel_reset (Curves *curves, - GimpHistogramChannel channel); -void curves_calculate_curve (Curves *curves, - GimpHistogramChannel channel); -gfloat curves_lut_func (Curves *curves, - gint nchannels, - gint channel, - gfloat value); +void curves_init (Curves *curves); +gfloat curves_lut_func (Curves *curves, + gint nchannels, + gint channel, + gfloat value); #endif /* __CURVES_H__ */ Index: app/tools/gimpcurvestool.c =================================================================== --- app/tools/gimpcurvestool.c (revision 24040) +++ app/tools/gimpcurvestool.c (working copy) @@ -39,6 +39,7 @@ #include "base/gimplut.h" #include "core/gimp.h" +#include "core/gimpcurve.h" #include "core/gimpdrawable.h" #include "core/gimpdrawable-histogram.h" #include "core/gimpimage.h" @@ -67,7 +68,6 @@ #define GRAPH_SIZE 256 #define BAR_SIZE 12 #define RADIUS 4 -#define MIN_DISTANCE 8 /* local function prototypes */ @@ -106,8 +106,6 @@ static gboolean gimp_curves_tool_setting static gboolean gimp_curves_tool_settings_save (GimpImageMapTool *image_map_tool, gpointer fp); -static void curves_add_point (GimpCurvesTool *tool, - gint channel); static gboolean curves_key_press (GimpCurvesTool *tool, GdkEventKey *kevent); static void curves_update (GimpCurvesTool *tool, @@ -194,12 +192,12 @@ gimp_curves_tool_init (GimpCurvesTool *t { gint i; - tool->curves = g_slice_new0 (Curves); + for (i = 0; i < G_N_ELEMENTS (tool->curve); i++) + tool->curve[i] = GIMP_CURVE (gimp_curve_new ("curves tool")); + tool->lut = gimp_lut_new (); tool->channel = GIMP_HISTOGRAM_VALUE; - curves_init (tool->curves); - for (i = 0; i < G_N_ELEMENTS (tool->col_value); i++) tool->col_value[i] = -1; @@ -211,8 +209,11 @@ static void gimp_curves_tool_finalize (GObject *object) { GimpCurvesTool *tool = GIMP_CURVES_TOOL (object); + gint i; + + for (i = 0; i < G_N_ELEMENTS (tool->curve); i++) + g_object_unref (tool->curve[i]); - g_slice_free (Curves, tool->curves); gimp_lut_free (tool->lut); if (tool->hist) @@ -243,6 +244,7 @@ gimp_curves_tool_initialize (GimpTool { GimpCurvesTool *c_tool = GIMP_CURVES_TOOL (tool); GimpDrawable *drawable = gimp_image_get_active_drawable (display->image); + gint i; if (! drawable) return FALSE; @@ -254,11 +256,12 @@ gimp_curves_tool_initialize (GimpTool return FALSE; } + for (i = 0; i < G_N_ELEMENTS (c_tool->curve); i++) + gimp_curve_reset (c_tool->curve[i], TRUE); + if (! c_tool->hist) c_tool->hist = gimp_histogram_new (); - curves_init (c_tool->curves); - c_tool->channel = GIMP_HISTOGRAM_VALUE; c_tool->color = gimp_drawable_is_rgb (drawable); c_tool->alpha = gimp_drawable_has_alpha (drawable); @@ -304,8 +307,17 @@ gimp_curves_tool_button_release (GimpToo if (state & GDK_SHIFT_MASK) { - curves_add_point (c_tool, c_tool->channel); - curves_calculate_curve (c_tool->curves, c_tool->channel); + GimpCurve *curve = c_tool->curve[c_tool->channel]; + + c_tool->selected = + gimp_curve_get_closest_point (curve, + c_tool->col_value[c_tool->channel]); + + gimp_curve_set_point (curve, + c_tool->selected, + c_tool->col_value[c_tool->channel], + curve->curve[c_tool->col_value[c_tool->channel]]); + curves_update (c_tool, GRAPH | XRANGE); } else if (state & GDK_CONTROL_MASK) @@ -314,8 +326,16 @@ gimp_curves_tool_button_release (GimpToo for (i = 0; i < 5; i++) { - curves_add_point (c_tool, i); - curves_calculate_curve (c_tool->curves, c_tool->channel); + GimpCurve *curve = c_tool->curve[i]; + + c_tool->selected = + gimp_curve_get_closest_point (curve, + c_tool->col_value[i]); + + gimp_curve_set_point (curve, + c_tool->selected, + c_tool->col_value[i], + curve->curve[c_tool->col_value[i]]); } curves_update (c_tool, GRAPH | XRANGE); @@ -396,57 +416,16 @@ gimp_curves_tool_color_picked (GimpColor curves_update (tool, GRAPH); } -static void -curves_add_point (GimpCurvesTool *tool, - gint channel) -{ - Curves *curves = tool->curves; - gint closest_point = 0; - gint distance; - gint curvex; - gint i; - - switch (curves->curve_type[channel]) - { - case GIMP_CURVE_SMOOTH: - curvex = tool->col_value[channel]; - distance = G_MAXINT; - - for (i = 0; i < CURVES_NUM_POINTS; i++) - { - if (curves->points[channel][i][0] != -1) - if (abs (curvex -curves->points[channel][i][0]) < distance) - { - distance = abs (curvex - curves->points[channel][i][0]); - closest_point = i; - } - } - - if (distance > MIN_DISTANCE) - closest_point = (curvex + 8) / 16; - - curves->points[channel][closest_point][0] = curvex; - curves->points[channel][closest_point][1] = curves->curve[channel][curvex]; - - tool->selected = closest_point; - break; - - case GIMP_CURVE_FREE: - /* do nothing for free form curves */ - break; - } -} - static gboolean curves_key_press (GimpCurvesTool *tool, GdkEventKey *kevent) { - Curves *curves = tool->curves; - gint i = tool->selected; - gint y = curves->points[tool->channel][i][1]; - gboolean update = FALSE; + GimpCurve *curve = tool->curve[tool->channel]; + gint i = tool->selected; + gint y = curve->points[i][1]; + gboolean update = FALSE; - if (tool->grabbed || curves->curve_type[tool->channel] == GIMP_CURVE_FREE) + if (tool->grabbed || curve->curve_type == GIMP_CURVE_FREE) return FALSE; switch (kevent->keyval) @@ -454,7 +433,7 @@ curves_key_press (GimpCurvesTool *tool, case GDK_Left: for (i = i - 1; i >= 0 && !update; i--) { - if (curves->points[tool->channel][i][0] != -1) + if (curve->points[i][0] != -1) { tool->selected = i; update = TRUE; @@ -463,9 +442,9 @@ curves_key_press (GimpCurvesTool *tool, break; case GDK_Right: - for (i = i + 1; i < CURVES_NUM_POINTS && !update; i++) + for (i = i + 1; i < GIMP_CURVE_NUM_POINTS && !update; i++) { - if (curves->points[tool->channel][i][0] != -1) + if (curve->points[i][0] != -1) { tool->selected = i; update = TRUE; @@ -477,8 +456,8 @@ curves_key_press (GimpCurvesTool *tool, if (y < 255) { y = y + (kevent->state & GDK_SHIFT_MASK ? 16 : 1); - curves->points[tool->channel][i][1] = MIN (y, 255); - curves_calculate_curve (curves, tool->channel); + + gimp_curve_move_point (curve, i, CLAMP0255 (y)); update = TRUE; } break; @@ -487,8 +466,8 @@ curves_key_press (GimpCurvesTool *tool, if (y > 0) { y = y - (kevent->state & GDK_SHIFT_MASK ? 16 : 1); - curves->points[tool->channel][i][1] = MAX (y, 0); - curves_calculate_curve (curves, tool->channel); + + gimp_curve_move_point (curve, i, CLAMP0255 (y)); update = TRUE; } break; @@ -510,10 +489,15 @@ static void gimp_curves_tool_map (GimpImageMapTool *image_map_tool) { GimpCurvesTool *tool = GIMP_CURVES_TOOL (image_map_tool); + Curves curves; + gint i; + + for (i = 0; i < G_N_ELEMENTS (tool->curve); i++) + gimp_curve_get_uchar (tool->curve[i], curves.curve[i]); gimp_lut_setup (tool->lut, (GimpLutFunc) curves_lut_func, - tool->curves, + &curves, gimp_drawable_bytes (image_map_tool->drawable)); gimp_image_map_apply (image_map_tool->image_map, @@ -727,7 +711,9 @@ gimp_curves_tool_reset (GimpImageMapTool for (channel = GIMP_HISTOGRAM_VALUE; channel <= GIMP_HISTOGRAM_ALPHA; channel++) - curves_channel_reset (tool->curves, channel); + { + gimp_curve_reset (tool->curve[channel], FALSE); + } curves_update (tool, XRANGE | GRAPH); } @@ -737,26 +723,25 @@ gimp_curves_tool_settings_load (GimpImag gpointer fp, GError **error) { - GimpCurvesTool *tool = GIMP_CURVES_TOOL (image_map_tool); - Curves *curves = tool->curves; - FILE *file = fp; + GimpCurvesTool *tool = GIMP_CURVES_TOOL (image_map_tool); + FILE *file = fp; gint i, j; gint fields; gchar buf[50]; - gint index[5][CURVES_NUM_POINTS]; - gint value[5][CURVES_NUM_POINTS]; + gint index[5][GIMP_CURVE_NUM_POINTS]; + gint value[5][GIMP_CURVE_NUM_POINTS]; if (! fgets (buf, sizeof (buf), file) || strcmp (buf, "# GIMP Curves File\n") != 0) { g_set_error (error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_PARSE, - _("not a GIMP Levels file")); + _("not a GIMP Curves file")); return FALSE; } for (i = 0; i < 5; i++) { - for (j = 0; j < CURVES_NUM_POINTS; j++) + for (j = 0; j < GIMP_CURVE_NUM_POINTS; j++) { fields = fscanf (file, "%d %d ", &index[i][j], &value[i][j]); if (fields != 2) @@ -772,17 +757,18 @@ gimp_curves_tool_settings_load (GimpImag for (i = 0; i < 5; i++) { - curves->curve_type[i] = GIMP_CURVE_SMOOTH; + GimpCurve *curve = tool->curve[i]; + + curve->curve_type = GIMP_CURVE_SMOOTH; - for (j = 0; j < CURVES_NUM_POINTS; j++) + for (j = 0; j < GIMP_CURVE_NUM_POINTS; j++) { - curves->points[i][j][0] = index[i][j]; - curves->points[i][j][1] = value[i][j]; + curve->points[j][0] = index[i][j]; + curve->points[j][1] = value[i][j]; } - } - for (i = 0; i < 5; i++) - curves_calculate_curve (curves, i); + gimp_curve_calculate (curve); + } curves_update (tool, ALL); @@ -796,33 +782,35 @@ static gboolean gimp_curves_tool_settings_save (GimpImageMapTool *image_map_tool, gpointer fp) { - GimpCurvesTool *tool = GIMP_CURVES_TOOL (image_map_tool); - Curves *curves = tool->curves; - FILE *file = fp; + GimpCurvesTool *tool = GIMP_CURVES_TOOL (image_map_tool); + FILE *file = fp; gint i, j; gint32 index; - for (i = 0; i < 5; i++) - if (curves->curve_type[i] == GIMP_CURVE_FREE) - { - /* pick representative points from the curve - and make them control points */ - for (j = 0; j <= 8; j++) - { - index = CLAMP0255 (j * 32); - curves->points[i][j * 2][0] = index; - curves->points[i][j * 2][1] = curves->curve[i][index]; - } - } - fprintf (file, "# GIMP Curves File\n"); for (i = 0; i < 5; i++) { - for (j = 0; j < CURVES_NUM_POINTS; j++) + GimpCurve *curve = tool->curve[i]; + + if (curve->curve_type == GIMP_CURVE_FREE) + { + /* pick representative points from the curve and make them + * control points + */ + for (j = 0; j <= 8; j++) + { + index = CLAMP0255 (j * 32); + + curve->points[j * 2][0] = index; + curve->points[j * 2][1] = curve->curve[index]; + } + } + + for (j = 0; j < GIMP_CURVE_NUM_POINTS; j++) fprintf (file, "%d %d ", - curves->points[i][j][0], - curves->points[i][j][1]); + curve->points[j][0], + curve->points[j][1]); fprintf (file, "\n"); } @@ -835,8 +823,7 @@ static void curves_update (GimpCurvesTool *tool, gint update) { - GimpHistogramChannel channel; - Curves *curves = tool->curves; + GimpHistogramChannel channel; if (tool->color) { @@ -862,18 +849,18 @@ curves_update (GimpCurvesTool *tool, case GIMP_HISTOGRAM_ALPHA: case GIMP_HISTOGRAM_RGB: gimp_color_bar_set_buffers (GIMP_COLOR_BAR (tool->xrange), - curves->curve[tool->channel], - curves->curve[tool->channel], - curves->curve[tool->channel]); + tool->curve[tool->channel]->curve, + tool->curve[tool->channel]->curve, + tool->curve[tool->channel]->curve); break; case GIMP_HISTOGRAM_RED: case GIMP_HISTOGRAM_GREEN: case GIMP_HISTOGRAM_BLUE: gimp_color_bar_set_buffers (GIMP_COLOR_BAR (tool->xrange), - curves->curve[GIMP_HISTOGRAM_RED], - curves->curve[GIMP_HISTOGRAM_GREEN], - curves->curve[GIMP_HISTOGRAM_BLUE]); + tool->curve[GIMP_HISTOGRAM_RED]->curve, + tool->curve[GIMP_HISTOGRAM_GREEN]->curve, + tool->curve[GIMP_HISTOGRAM_BLUE]->curve); break; } } @@ -901,7 +888,7 @@ curves_channel_callback (GtkWidget tool->channel = (tool->channel == GIMP_HISTOGRAM_ALPHA) ? 1 : 0; gimp_int_radio_group_set_active (GTK_RADIO_BUTTON (tool->curve_type), - tool->curves->curve_type[tool->channel]); + tool->curve[tool->channel]->curve_type); curves_update (tool, ALL); } @@ -913,7 +900,7 @@ curves_channel_reset_callback (GtkWidget { tool->grabbed = FALSE; - curves_channel_reset (tool->curves, tool->channel); + gimp_curve_reset (tool->curve[tool->channel], FALSE); curves_update (tool, XRANGE | GRAPH); @@ -951,32 +938,13 @@ static void curves_curve_type_callback (GtkWidget *widget, GimpCurvesTool *tool) { - GimpCurveType curve_type; - Curves *curves = tool->curves; + GimpCurveType curve_type; gimp_radio_button_update (widget, &curve_type); - if (curves->curve_type[tool->channel] != curve_type) + if (tool->curve[tool->channel]->curve_type != curve_type) { - curves->curve_type[tool->channel] = curve_type; - - if (curve_type == GIMP_CURVE_SMOOTH) - { - gint i; - gint32 index; - - /* pick representative points from the curve - * and make them control points - */ - for (i = 0; i <= 8; i++) - { - index = CLAMP0255 (i * 32); - curves->points[tool->channel][i * 2][0] = index; - curves->points[tool->channel][i * 2][1] = curves->curve[tool->channel][index]; - } - } - - curves_calculate_curve (curves, tool->channel); + gimp_curve_set_curve_type (tool->curve[tool->channel], curve_type); curves_update (tool, XRANGE | GRAPH); @@ -1009,16 +977,13 @@ curves_graph_events (GtkWidget *wid GdkEvent *event, GimpCurvesTool *tool) { - Curves *curves = tool->curves; - GdkEventButton *bevent; - GdkEventMotion *mevent; + GimpCurve *curve = tool->curve[tool->channel]; GimpCursorType new_cursor = GDK_X_CURSOR; gint i; gint tx, ty; gint x, y; gint width, height; gint closest_point; - gint distance; gint x1, x2, y1, y2; width = widget->allocation.width - 2 * RADIUS; @@ -1033,173 +998,163 @@ curves_graph_events (GtkWidget *wid x = CLAMP0255 (x); y = CLAMP0255 (y); - distance = G_MAXINT; - for (i = 0, closest_point = 0; i < CURVES_NUM_POINTS; i++) - { - if (curves->points[tool->channel][i][0] != -1) - if (abs (x - curves->points[tool->channel][i][0]) < distance) - { - distance = abs (x - curves->points[tool->channel][i][0]); - closest_point = i; - } - } - - if (distance > MIN_DISTANCE) - closest_point = (x + 8) / 16; + closest_point = gimp_curve_get_closest_point (curve, x); switch (event->type) { case GDK_BUTTON_PRESS: - bevent = (GdkEventButton *) event; + { + GdkEventButton *bevent = (GdkEventButton *) event; - if (bevent->button != 1) - return TRUE; + if (bevent->button != 1) + return TRUE; - tool->grabbed = TRUE; + tool->grabbed = TRUE; - curves_set_cursor (tool, GDK_TCROSS); + curves_set_cursor (tool, GDK_TCROSS); - switch (curves->curve_type[tool->channel]) - { - case GIMP_CURVE_SMOOTH: - /* determine the leftmost and rightmost points */ - tool->leftmost = -1; - for (i = closest_point - 1; i >= 0; i--) - if (curves->points[tool->channel][i][0] != -1) - { - tool->leftmost = curves->points[tool->channel][i][0]; - break; - } + switch (curve->curve_type) + { + case GIMP_CURVE_SMOOTH: + /* determine the leftmost and rightmost points */ + tool->leftmost = -1; + for (i = closest_point - 1; i >= 0; i--) + if (curve->points[i][0] != -1) + { + tool->leftmost = curve->points[i][0]; + break; + } - tool->rightmost = 256; - for (i = closest_point + 1; i < CURVES_NUM_POINTS; i++) - if (curves->points[tool->channel][i][0] != -1) - { - tool->rightmost = curves->points[tool->channel][i][0]; - break; - } + tool->rightmost = 256; + for (i = closest_point + 1; i < GIMP_CURVE_NUM_POINTS; i++) + if (curve->points[i][0] != -1) + { + tool->rightmost = curve->points[i][0]; + break; + } - tool->selected = closest_point; - curves->points[tool->channel][tool->selected][0] = x; - curves->points[tool->channel][tool->selected][1] = 255 - y; + tool->selected = closest_point; - gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (tool)); - break; + gimp_curve_set_point (curve, tool->selected, x, 255 - y); - case GIMP_CURVE_FREE: - curves->curve[tool->channel][x] = 255 - y; - tool->selected = x; - tool->last = y; - break; - } + gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (tool)); + break; - curves_calculate_curve (curves, tool->channel); - curves_update (tool, XRANGE | GRAPH); + case GIMP_CURVE_FREE: + curve->curve[x] = 255 - y; + tool->selected = x; + tool->last = y; + break; + } + + curves_update (tool, XRANGE | GRAPH); - if (! GTK_WIDGET_HAS_FOCUS (widget)) - gtk_widget_grab_focus (widget); + if (! GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); + } return TRUE; case GDK_BUTTON_RELEASE: - bevent = (GdkEventButton *) event; + { + GdkEventButton *bevent = (GdkEventButton *) event; - if (bevent->button != 1) - return TRUE; + if (bevent->button != 1) + return TRUE; - tool->grabbed = FALSE; + tool->grabbed = FALSE; - curves_set_cursor (tool, GDK_FLEUR); + curves_set_cursor (tool, GDK_FLEUR); - if (curves->curve_type[tool->channel] == GIMP_CURVE_FREE) - gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (tool)); + if (curve->curve_type == GIMP_CURVE_FREE) + gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (tool)); + } return TRUE; case GDK_MOTION_NOTIFY: - mevent = (GdkEventMotion *) event; + { + GdkEventMotion *mevent = (GdkEventMotion *) event; - switch (curves->curve_type[tool->channel]) - { - case GIMP_CURVE_SMOOTH: - /* If no point is grabbed... */ - if (! tool->grabbed) - { - if (curves->points[tool->channel][closest_point][0] != -1) - new_cursor = GDK_FLEUR; - else + switch (curve->curve_type) + { + case GIMP_CURVE_SMOOTH: + /* If no point is grabbed... */ + if (! tool->grabbed) + { + if (curve->points[closest_point][0] != -1) + new_cursor = GDK_FLEUR; + else + new_cursor = GDK_TCROSS; + } + /* Else, drag the grabbed point */ + else + { new_cursor = GDK_TCROSS; - } - /* Else, drag the grabbed point */ - else - { - new_cursor = GDK_TCROSS; - - curves->points[tool->channel][tool->selected][0] = -1; - - if (x > tool->leftmost && x < tool->rightmost) - { - closest_point = (x + 8) / 16; - if (curves->points[tool->channel][closest_point][0] == -1) - tool->selected = closest_point; - curves->points[tool->channel][tool->selected][0] = x; - curves->points[tool->channel][tool->selected][1] = 255 - y; - } + gimp_curve_set_point (curve, tool->selected, -1, -1); - curves_calculate_curve (curves, tool->channel); + if (x > tool->leftmost && x < tool->rightmost) + { + closest_point = (x + 8) / 16; + if (curve->points[closest_point][0] == -1) + tool->selected = closest_point; - gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (tool)); - } - break; + gimp_curve_set_point (curve, tool->selected, x, 255 - y); + } - case GIMP_CURVE_FREE: - if (tool->grabbed) - { - if (tool->selected > x) - { - x1 = x; - x2 = tool->selected; - y1 = y; - y2 = tool->last; - } - else - { - x1 = tool->selected; - x2 = x; - y1 = tool->last; - y2 = y; - } + gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (tool)); + } + break; - if (x2 != x1) - { - for (i = x1; i <= x2; i++) - curves->curve[tool->channel][i] = - 255 - (y1 + ((y2 - y1) * (i - x1)) / (x2 - x1)); - } - else - { - curves->curve[tool->channel][x] = 255 - y; - } + case GIMP_CURVE_FREE: + if (tool->grabbed) + { + if (tool->selected > x) + { + x1 = x; + x2 = tool->selected; + y1 = y; + y2 = tool->last; + } + else + { + x1 = tool->selected; + x2 = x; + y1 = tool->last; + y2 = y; + } + + if (x2 != x1) + { + for (i = x1; i <= x2; i++) + curve->curve[i] = + 255 - (y1 + ((y2 - y1) * (i - x1)) / (x2 - x1)); + } + else + { + curve->curve[x] = 255 - y; + } - tool->selected = x; - tool->last = y; - } + tool->selected = x; + tool->last = y; + } - if (mevent->state & GDK_BUTTON1_MASK) - new_cursor = GDK_TCROSS; - else - new_cursor = GDK_PENCIL; + if (mevent->state & GDK_BUTTON1_MASK) + new_cursor = GDK_TCROSS; + else + new_cursor = GDK_PENCIL; - break; - } + break; + } - curves_set_cursor (tool, new_cursor); + curves_set_cursor (tool, new_cursor); - tool->cursor_x = x; - tool->cursor_y = y; + tool->cursor_x = x; + tool->cursor_y = y; - curves_update (tool, XRANGE | GRAPH); + curves_update (tool, XRANGE | GRAPH); + } return TRUE; case GDK_KEY_PRESS: @@ -1272,7 +1227,7 @@ curves_graph_expose (GtkWidget *wid GdkEventExpose *eevent, GimpCurvesTool *tool) { - Curves *curves = tool->curves; + GimpCurve *curve = tool->curve[tool->channel]; GimpHistogramChannel channel; gint width; gint height; @@ -1322,7 +1277,7 @@ curves_graph_expose (GtkWidget *wid for (i = 0; i < 256; i++) { x = i; - y = 255 - curves->curve[tool->channel][x]; + y = 255 - curve->curve[x]; points[i].x = RADIUS + ROUND ((gdouble) width * x / 256.0); points[i].y = RADIUS + ROUND ((gdouble) height * y / 256.0); @@ -1330,16 +1285,16 @@ curves_graph_expose (GtkWidget *wid gdk_draw_lines (widget->window, graph_gc, points, 256); - if (curves->curve_type[tool->channel] == GIMP_CURVE_SMOOTH) + if (curve->curve_type == GIMP_CURVE_SMOOTH) { /* Draw the points */ - for (i = 0; i < CURVES_NUM_POINTS; i++) + for (i = 0; i < GIMP_CURVE_NUM_POINTS; i++) { - x = curves->points[tool->channel][i][0]; + x = curve->points[i][0]; if (x < 0) continue; - y = 255 - curves->points[tool->channel][i][1]; + y = 255 - curve->points[i][1]; gdk_draw_arc (widget->window, graph_gc, TRUE, Index: app/tools/gimpcurvestool.h =================================================================== --- app/tools/gimpcurvestool.h (revision 24040) +++ app/tools/gimpcurvestool.h (working copy) @@ -37,7 +37,7 @@ struct _GimpCurvesTool { GimpImageMapTool parent_instance; - Curves *curves; + GimpCurve *curve[5]; GimpLut *lut; /* dialog */ Index: app/pdb/color_cmds.c =================================================================== --- app/pdb/color_cmds.c (revision 24040) +++ app/pdb/color_cmds.c (working copy) @@ -40,6 +40,7 @@ #include "base/pixel-region.h" #include "base/threshold.h" #include "core/gimp.h" +#include "core/gimpcurve.h" #include "core/gimpdrawable-desaturate.h" #include "core/gimpdrawable-equalize.h" #include "core/gimpdrawable-histogram.h" @@ -394,6 +395,7 @@ curves_spline_invoker (GimpProcedure /* The application should occur only within selection bounds */ if (gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height)) { + GimpCurve *curve; Curves c; gint j; PixelRegion srcPR, destPR; @@ -408,17 +410,23 @@ curves_spline_invoker (GimpProcedure curves_init (&c); + curve = GIMP_CURVE (gimp_curve_new ("curves_spline")); + /* unset the last point */ - c.points[channel][CURVES_NUM_POINTS - 1][0] = -1; - c.points[channel][CURVES_NUM_POINTS - 1][1] = -1; + curve->points[GIMP_CURVE_NUM_POINTS - 1][0] = -1; + curve->points[GIMP_CURVE_NUM_POINTS - 1][1] = -1; for (j = 0; j < num_points / 2; j++) { - c.points[channel][j][0] = control_pts[j * 2]; - c.points[channel][j][1] = control_pts[j * 2 + 1]; + curve->points[j][0] = control_pts[j * 2]; + curve->points[j][1] = control_pts[j * 2 + 1]; } - curves_calculate_curve (&c, channel); + gimp_curve_calculate (curve); + + gimp_curve_get_uchar (curve, c.curve[channel]); + + g_object_unref (curve); gimp_lut_setup (lut, (GimpLutFunc) curves_lut_func, Index: tools/pdbgen/pdb/color.pdb =================================================================== --- tools/pdbgen/pdb/color.pdb (revision 24040) +++ tools/pdbgen/pdb/color.pdb (working copy) @@ -422,7 +422,7 @@ HELP ); %invoke = ( - headers => [ qw("base/curves.h") ], + headers => [ qw("base/curves.h" "core/gimpcurve.h") ], code => <<'CODE' { if (! gimp_item_is_attached (GIMP_ITEM (drawable)) || @@ -440,6 +440,7 @@ HELP /* The application should occur only within selection bounds */ if (gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height)) { + GimpCurve *curve; Curves c; gint j; PixelRegion srcPR, destPR; @@ -454,17 +455,23 @@ HELP curves_init (&c); + curve = GIMP_CURVE (gimp_curve_new ("curves_spline")); + /* unset the last point */ - c.points[channel][CURVES_NUM_POINTS - 1][0] = -1; - c.points[channel][CURVES_NUM_POINTS - 1][1] = -1; + curve->points[GIMP_CURVE_NUM_POINTS - 1][0] = -1; + curve->points[GIMP_CURVE_NUM_POINTS - 1][1] = -1; for (j = 0; j < num_points / 2; j++) { - c.points[channel][j][0] = control_pts[j * 2]; - c.points[channel][j][1] = control_pts[j * 2 + 1]; + curve->points[j][0] = control_pts[j * 2]; + curve->points[j][1] = control_pts[j * 2 + 1]; } - curves_calculate_curve (&c, channel); + gimp_curve_calculate (curve); + + gimp_curve_get_uchar (curve, c.curve[channel]); + + g_object_unref (curve); gimp_lut_setup (lut, (GimpLutFunc) curves_lut_func,