2001-07-07 Michael Natterer <mitch@gimp.org> * app/Makefile.am * app/context_manager.[ch]: removed. * app/app_procs.c: call tool_mananger instead of context_manager functions, pass "the_gimp" to some more functions. * app/drawable.[ch]: pass a GimpContext to drawable_fill(). * app/errors.c: behave according to "stack_trace_mode" when using the debugging signal handler. * app/gimprc.[ch]: removed the core/ config variables. * app/selection.c: set the selection's state to INVISIBLE in selection_pause(). * app/core/Makefile.am * app/core/gimpcoreconfig.[ch]: new files (the configuration variables used by core/). * app/core/gimpcontext.[ch]: removed the global contexts (user, default, ...) and their functions. It's no longer possible to pass NULL to the context functions to manipulate the current context (gimpcontext.c doesn't know the current context any more). * app/core/gimp.[ch]: added them here. The functions are now called gimp_[set|get]_*_context(). Added gimp_create_context() which is the only function to create contexts now. * app/gui/dialogs.[ch] * app/gui/gui.[ch]: pass "gimp" to all functions. * app/tools/tool_manager.[ch] * app/tools/tools.[ch]: pass "gimp" to lots of functions. Added the "global_tool_context" logic and the global/non-global paint options switching from the context_manager. Pass "gimp" to all tools' "register" functions. * app/tools/*: changed accordingly. * app/devices.c * app/disp_callbacks.c * app/file-open.[ch] * app/file-save.c * app/gdisplay.c * app/gimage.c * app/libgimp_glue.c * app/module_db.c * app/nav_window.c * app/plug_in.c * app/qmask.c * app/undo.c * app/base/base-config.c * app/core/gimpbrushpipe.c * app/core/gimpdrawable-offset.c * app/core/gimpgradient.c * app/core/gimpimage-duplicate.c * app/core/gimpimage-mask.c * app/core/gimpimage-new.c * app/core/gimpimage.c * app/core/gimppalette.c * app/core/gimptoolinfo.[ch] * app/core/gimpundo.c * app/gui/brush-select.c * app/gui/channels-commands.c * app/gui/color-area.c * app/gui/dialogs-constructors.c * app/gui/file-new-dialog.c * app/gui/file-open-dialog.c * app/gui/gradient-editor.c * app/gui/gradient-select.c * app/gui/info-window.c * app/gui/layers-commands.c * app/gui/menus.c * app/gui/palette-editor.c * app/gui/palette-import-dialog.c * app/gui/palette-select.c * app/gui/paths-dialog.c * app/gui/pattern-select.c * app/gui/preferences-dialog.c * app/gui/resize-dialog.c * app/gui/test-commands.c * app/gui/tool-options-dialog.c * app/gui/toolbox.c * app/gui/tools-commands.c * app/xcf/xcf-load.c * app/xcf/xcf-save.c * app/widgets/gimpchannellistview.c * app/widgets/gimpdnd.c * app/widgets/gimpdrawablelistview.[ch] * app/widgets/gimpimagedock.c * app/widgets/gimplayerlistview.c * app/pdb/brushes_cmds.c * app/pdb/drawable_cmds.c * app/pdb/gradient_select_cmds.c * app/pdb/gradients_cmds.c * app/pdb/palette_cmds.c * app/pdb/patterns_cmds.c * app/pdb/procedural_db.c * tools/pdbgen/pdb/brushes.pdb * tools/pdbgen/pdb/drawable.pdb * tools/pdbgen/pdb/gradient_select.pdb * tools/pdbgen/pdb/gradients.pdb * tools/pdbgen/pdb/palette.pdb * tools/pdbgen/pdb/patterns.pdb: changed accordingly: remove usage of gimp_context_[get|set]_*(NULL), create contexts with gimp_create_context(). Get the user/current context with gimp_get_[user|current]_context(). Added/removed access to the global "the_gimp" variable in some places. Get the core's config variables from "core_config".
771 lines
17 KiB
C
771 lines
17 KiB
C
/* The GIMP -- an 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "libgimpcolor/gimpcolor.h"
|
|
#include "libgimpmath/gimpmath.h"
|
|
#include "libgimpbase/gimpbase.h"
|
|
|
|
#include "core-types.h"
|
|
|
|
#include "base/temp-buf.h"
|
|
|
|
#include "gimpimage.h"
|
|
#include "gimpgradient.h"
|
|
|
|
#include "errors.h"
|
|
|
|
#include "libgimp/gimpintl.h"
|
|
|
|
|
|
#define EPSILON 1e-10
|
|
|
|
|
|
static void gimp_gradient_class_init (GimpGradientClass *klass);
|
|
static void gimp_gradient_init (GimpGradient *gradient);
|
|
static void gimp_gradient_destroy (GtkObject *object);
|
|
static TempBuf * gimp_gradient_get_new_preview (GimpViewable *viewable,
|
|
gint width,
|
|
gint height);
|
|
static void gimp_gradient_dirty (GimpData *data);
|
|
static gboolean gimp_gradient_save (GimpData *data);
|
|
static gchar * gimp_gradient_get_extension (GimpData *data);
|
|
static GimpData * gimp_gradient_duplicate (GimpData *data);
|
|
|
|
static gdouble gimp_gradient_calc_linear_factor (gdouble middle,
|
|
gdouble pos);
|
|
static gdouble gimp_gradient_calc_curved_factor (gdouble middle,
|
|
gdouble pos);
|
|
static gdouble gimp_gradient_calc_sine_factor (gdouble middle,
|
|
gdouble pos);
|
|
static gdouble gimp_gradient_calc_sphere_increasing_factor (gdouble middle,
|
|
gdouble pos);
|
|
static gdouble gimp_gradient_calc_sphere_decreasing_factor (gdouble middle,
|
|
gdouble pos);
|
|
|
|
|
|
static GimpDataClass *parent_class = NULL;
|
|
|
|
|
|
GtkType
|
|
gimp_gradient_get_type (void)
|
|
{
|
|
static GtkType gradient_type = 0;
|
|
|
|
if (! gradient_type)
|
|
{
|
|
static const GtkTypeInfo gradient_info =
|
|
{
|
|
"GimpGradient",
|
|
sizeof (GimpGradient),
|
|
sizeof (GimpGradientClass),
|
|
(GtkClassInitFunc) gimp_gradient_class_init,
|
|
(GtkObjectInitFunc) gimp_gradient_init,
|
|
/* reserved_1 */ NULL,
|
|
/* reserved_2 */ NULL,
|
|
(GtkClassInitFunc) NULL
|
|
};
|
|
|
|
gradient_type = gtk_type_unique (GIMP_TYPE_DATA, &gradient_info);
|
|
}
|
|
|
|
return gradient_type;
|
|
}
|
|
|
|
static void
|
|
gimp_gradient_class_init (GimpGradientClass *klass)
|
|
{
|
|
GtkObjectClass *object_class;
|
|
GimpViewableClass *viewable_class;
|
|
GimpDataClass *data_class;
|
|
|
|
object_class = (GtkObjectClass *) klass;
|
|
viewable_class = (GimpViewableClass *) klass;
|
|
data_class = (GimpDataClass *) klass;
|
|
|
|
parent_class = gtk_type_class (GIMP_TYPE_DATA);
|
|
|
|
object_class->destroy = gimp_gradient_destroy;
|
|
|
|
viewable_class->get_new_preview = gimp_gradient_get_new_preview;
|
|
|
|
data_class->dirty = gimp_gradient_dirty;
|
|
data_class->save = gimp_gradient_save;
|
|
data_class->get_extension = gimp_gradient_get_extension;
|
|
data_class->duplicate = gimp_gradient_duplicate;
|
|
}
|
|
|
|
static void
|
|
gimp_gradient_init (GimpGradient *gradient)
|
|
{
|
|
gradient->segments = NULL;
|
|
gradient->last_visited = NULL;
|
|
}
|
|
|
|
static void
|
|
gimp_gradient_destroy (GtkObject *object)
|
|
{
|
|
GimpGradient *gradient;
|
|
|
|
gradient = GIMP_GRADIENT (object);
|
|
|
|
if (gradient->segments)
|
|
gimp_gradient_segments_free (gradient->segments);
|
|
|
|
if (GTK_OBJECT_CLASS (parent_class)->destroy)
|
|
GTK_OBJECT_CLASS (parent_class)->destroy (object);
|
|
}
|
|
|
|
static TempBuf *
|
|
gimp_gradient_get_new_preview (GimpViewable *viewable,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
GimpGradient *gradient;
|
|
TempBuf *temp_buf;
|
|
guchar *buf;
|
|
guchar *p0, *p1;
|
|
guchar *even, *odd;
|
|
gint x, y;
|
|
gdouble dx, cur_x;
|
|
GimpRGB color;
|
|
gdouble c0, c1;
|
|
|
|
gradient = GIMP_GRADIENT (viewable);
|
|
|
|
dx = 1.0 / (width - 1);
|
|
cur_x = 0.0;
|
|
p0 = even = g_malloc (width * 3);
|
|
p1 = odd = g_malloc (width * 3);
|
|
|
|
/* Create lines to fill the image */
|
|
|
|
for (x = 0; x < width; x++)
|
|
{
|
|
gimp_gradient_get_color_at (gradient, cur_x, &color);
|
|
|
|
if ((x / GIMP_CHECK_SIZE_SM) & 1)
|
|
{
|
|
c0 = GIMP_CHECK_LIGHT;
|
|
c1 = GIMP_CHECK_DARK;
|
|
}
|
|
else
|
|
{
|
|
c0 = GIMP_CHECK_DARK;
|
|
c1 = GIMP_CHECK_LIGHT;
|
|
}
|
|
|
|
*p0++ = (c0 + (color.r - c0) * color.a) * 255.0;
|
|
*p0++ = (c0 + (color.g - c0) * color.a) * 255.0;
|
|
*p0++ = (c0 + (color.b - c0) * color.a) * 255.0;
|
|
|
|
*p1++ = (c1 + (color.r - c1) * color.a) * 255.0;
|
|
*p1++ = (c1 + (color.g - c1) * color.a) * 255.0;
|
|
*p1++ = (c1 + (color.b - c1) * color.a) * 255.0;
|
|
|
|
cur_x += dx;
|
|
}
|
|
|
|
temp_buf = temp_buf_new (width, height,
|
|
3,
|
|
0, 0,
|
|
NULL);
|
|
|
|
buf = temp_buf_data (temp_buf);
|
|
|
|
for (y = 0; y < height; y++)
|
|
{
|
|
if ((y / GIMP_CHECK_SIZE_SM) & 1)
|
|
{
|
|
memcpy (buf + (width * y * 3), odd, width * 3);
|
|
}
|
|
else
|
|
{
|
|
memcpy (buf + (width * y * 3), even, width * 3);
|
|
}
|
|
}
|
|
|
|
g_free (even);
|
|
g_free (odd);
|
|
|
|
return temp_buf;
|
|
}
|
|
|
|
static GimpData *
|
|
gimp_gradient_duplicate (GimpData *data)
|
|
{
|
|
GimpGradient *gradient;
|
|
GimpGradientSegment *head, *prev, *cur, *orig;
|
|
|
|
gradient = GIMP_GRADIENT (gtk_type_new (GIMP_TYPE_GRADIENT));
|
|
|
|
gimp_data_dirty (GIMP_DATA (gradient));
|
|
|
|
prev = NULL;
|
|
orig = GIMP_GRADIENT (data)->segments;
|
|
head = NULL;
|
|
|
|
while (orig)
|
|
{
|
|
cur = gimp_gradient_segment_new ();
|
|
|
|
*cur = *orig; /* Copy everything */
|
|
|
|
cur->prev = prev;
|
|
cur->next = NULL;
|
|
|
|
if (prev)
|
|
prev->next = cur;
|
|
else
|
|
head = cur; /* Remember head */
|
|
|
|
prev = cur;
|
|
orig = orig->next;
|
|
}
|
|
|
|
gradient->segments = head;
|
|
|
|
return GIMP_DATA (gradient);
|
|
}
|
|
|
|
GimpData *
|
|
gimp_gradient_new (const gchar *name)
|
|
{
|
|
GimpGradient *gradient;
|
|
|
|
g_return_val_if_fail (name != NULL, NULL);
|
|
|
|
gradient = GIMP_GRADIENT (gtk_type_new (GIMP_TYPE_GRADIENT));
|
|
|
|
gimp_object_set_name (GIMP_OBJECT (gradient), name);
|
|
|
|
gradient->segments = gimp_gradient_segment_new ();
|
|
|
|
return GIMP_DATA (gradient);
|
|
}
|
|
|
|
GimpData *
|
|
gimp_gradient_get_standard (void)
|
|
{
|
|
static GimpGradient *standard_gradient = NULL;
|
|
|
|
if (! standard_gradient)
|
|
{
|
|
standard_gradient = GIMP_GRADIENT (gimp_gradient_new ("Standard"));
|
|
|
|
gtk_object_ref (GTK_OBJECT (standard_gradient));
|
|
gtk_object_sink (GTK_OBJECT (standard_gradient));
|
|
}
|
|
|
|
return GIMP_DATA (standard_gradient);
|
|
}
|
|
|
|
GimpData *
|
|
gimp_gradient_load (const gchar *filename)
|
|
{
|
|
GimpGradient *gradient;
|
|
GimpGradientSegment *seg;
|
|
GimpGradientSegment *prev;
|
|
gint num_segments;
|
|
gint i;
|
|
gint type, color;
|
|
FILE *file;
|
|
gchar line[1024];
|
|
|
|
g_return_val_if_fail (filename != NULL, NULL);
|
|
|
|
file = fopen (filename, "rb");
|
|
if (!file)
|
|
return NULL;
|
|
|
|
fgets (line, 1024, file);
|
|
if (strcmp (line, "GIMP Gradient\n") != 0)
|
|
{
|
|
fclose (file);
|
|
return NULL;
|
|
}
|
|
|
|
gradient = GIMP_GRADIENT (gtk_type_new (GIMP_TYPE_GRADIENT));
|
|
|
|
gimp_data_set_filename (GIMP_DATA (gradient), filename);
|
|
|
|
fgets (line, 1024, file);
|
|
if (! strncmp (line, "Name: ", strlen ("Name: ")))
|
|
{
|
|
gimp_object_set_name (GIMP_OBJECT (gradient),
|
|
g_strstrip (&line[strlen ("Name: ")]));
|
|
|
|
fgets (line, 1024, file);
|
|
}
|
|
else /* old gradient format */
|
|
{
|
|
gimp_object_set_name (GIMP_OBJECT (gradient), g_basename (filename));
|
|
}
|
|
|
|
num_segments = atoi (line);
|
|
|
|
if (num_segments < 1)
|
|
{
|
|
g_message ("%s(): invalid number of segments in \"%s\"",
|
|
G_GNUC_FUNCTION, filename);
|
|
gtk_object_sink (GTK_OBJECT (gradient));
|
|
fclose (file);
|
|
return NULL;
|
|
}
|
|
|
|
prev = NULL;
|
|
|
|
for (i = 0; i < num_segments; i++)
|
|
{
|
|
seg = gimp_gradient_segment_new ();
|
|
|
|
seg->prev = prev;
|
|
|
|
if (prev)
|
|
prev->next = seg;
|
|
else
|
|
gradient->segments = seg;
|
|
|
|
fgets (line, 1024, file);
|
|
|
|
if (sscanf (line, "%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%d%d",
|
|
&(seg->left), &(seg->middle), &(seg->right),
|
|
&(seg->left_color.r),
|
|
&(seg->left_color.g),
|
|
&(seg->left_color.b),
|
|
&(seg->left_color.a),
|
|
&(seg->right_color.r),
|
|
&(seg->right_color.g),
|
|
&(seg->right_color.b),
|
|
&(seg->right_color.a),
|
|
&type, &color) != 13)
|
|
{
|
|
g_message ("%s(): badly formatted gradient segment %d in \"%s\" --- "
|
|
"bad things may happen soon",
|
|
G_GNUC_FUNCTION, i, filename);
|
|
}
|
|
else
|
|
{
|
|
seg->type = (GimpGradientSegmentType) type;
|
|
seg->color = (GimpGradientSegmentColor) color;
|
|
}
|
|
|
|
prev = seg;
|
|
}
|
|
|
|
fclose (file);
|
|
|
|
GIMP_DATA (gradient)->dirty = FALSE;
|
|
|
|
return GIMP_DATA (gradient);
|
|
}
|
|
|
|
static void
|
|
gimp_gradient_dirty (GimpData *data)
|
|
{
|
|
GimpGradient *gradient;
|
|
|
|
gradient = GIMP_GRADIENT (data);
|
|
|
|
gradient->last_visited = NULL;
|
|
|
|
if (GIMP_DATA_CLASS (parent_class)->dirty)
|
|
GIMP_DATA_CLASS (parent_class)->dirty (data);
|
|
}
|
|
|
|
static gboolean
|
|
gimp_gradient_save (GimpData *data)
|
|
{
|
|
GimpGradient *gradient;
|
|
GimpGradientSegment *seg;
|
|
gint num_segments;
|
|
FILE *file;
|
|
|
|
gradient = GIMP_GRADIENT (data);
|
|
|
|
file = fopen (data->filename, "wb");
|
|
if (! file)
|
|
{
|
|
g_message ("%s(): can't open \"%s\"",
|
|
G_GNUC_FUNCTION, data->filename);
|
|
return FALSE;
|
|
}
|
|
|
|
/* File format is:
|
|
*
|
|
* GIMP Gradient
|
|
* Name: name
|
|
* number_of_segments
|
|
* left middle right r0 g0 b0 a0 r1 g1 b1 a1 type coloring
|
|
* left middle right r0 g0 b0 a0 r1 g1 b1 a1 type coloring
|
|
* ...
|
|
*/
|
|
|
|
fprintf (file, "GIMP Gradient\n");
|
|
|
|
fprintf (file, "Name: %s\n", GIMP_OBJECT (gradient)->name);
|
|
|
|
/* Count number of segments */
|
|
num_segments = 0;
|
|
seg = gradient->segments;
|
|
|
|
while (seg)
|
|
{
|
|
num_segments++;
|
|
seg = seg->next;
|
|
}
|
|
|
|
/* Write rest of file */
|
|
fprintf (file, "%d\n", num_segments);
|
|
|
|
for (seg = gradient->segments; seg; seg = seg->next)
|
|
{
|
|
fprintf (file, "%f %f %f %f %f %f %f %f %f %f %f %d %d\n",
|
|
seg->left, seg->middle, seg->right,
|
|
seg->left_color.r,
|
|
seg->left_color.g,
|
|
seg->left_color.b,
|
|
seg->left_color.a,
|
|
seg->right_color.r,
|
|
seg->right_color.g,
|
|
seg->right_color.b,
|
|
seg->right_color.a,
|
|
(gint) seg->type,
|
|
(gint) seg->color);
|
|
}
|
|
|
|
fclose (file);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gchar *
|
|
gimp_gradient_get_extension (GimpData *data)
|
|
{
|
|
return GIMP_GRADIENT_FILE_EXTENSION;
|
|
}
|
|
|
|
void
|
|
gimp_gradient_get_color_at (GimpGradient *gradient,
|
|
gdouble pos,
|
|
GimpRGB *color)
|
|
{
|
|
gdouble factor = 0.0;
|
|
GimpGradientSegment *seg;
|
|
gdouble seg_len;
|
|
gdouble middle;
|
|
GimpRGB rgb;
|
|
|
|
g_return_if_fail (gradient != NULL);
|
|
g_return_if_fail (GIMP_IS_GRADIENT (gradient));
|
|
g_return_if_fail (color != NULL);
|
|
|
|
/* if there is no gradient return a totally transparent black */
|
|
if (gradient == NULL)
|
|
{
|
|
gimp_rgba_set (color, 0.0, 0.0, 0.0, 0.0);
|
|
return;
|
|
}
|
|
|
|
if (pos < 0.0)
|
|
pos = 0.0;
|
|
else if (pos > 1.0)
|
|
pos = 1.0;
|
|
|
|
seg = gimp_gradient_get_segment_at (gradient, pos);
|
|
|
|
seg_len = seg->right - seg->left;
|
|
|
|
if (seg_len < EPSILON)
|
|
{
|
|
middle = 0.5;
|
|
pos = 0.5;
|
|
}
|
|
else
|
|
{
|
|
middle = (seg->middle - seg->left) / seg_len;
|
|
pos = (pos - seg->left) / seg_len;
|
|
}
|
|
|
|
switch (seg->type)
|
|
{
|
|
case GRAD_LINEAR:
|
|
factor = gimp_gradient_calc_linear_factor (middle, pos);
|
|
break;
|
|
|
|
case GRAD_CURVED:
|
|
factor = gimp_gradient_calc_curved_factor (middle, pos);
|
|
break;
|
|
|
|
case GRAD_SINE:
|
|
factor = gimp_gradient_calc_sine_factor (middle, pos);
|
|
break;
|
|
|
|
case GRAD_SPHERE_INCREASING:
|
|
factor = gimp_gradient_calc_sphere_increasing_factor (middle, pos);
|
|
break;
|
|
|
|
case GRAD_SPHERE_DECREASING:
|
|
factor = gimp_gradient_calc_sphere_decreasing_factor (middle, pos);
|
|
break;
|
|
|
|
default:
|
|
gimp_fatal_error ("%s(): Unknown gradient type %d",
|
|
G_GNUC_FUNCTION, (gint) seg->type);
|
|
break;
|
|
}
|
|
|
|
/* Calculate color components */
|
|
|
|
rgb.a = seg->left_color.a + (seg->right_color.a - seg->left_color.a) * factor;
|
|
|
|
if (seg->color == GRAD_RGB)
|
|
{
|
|
rgb.r
|
|
= seg->left_color.r + (seg->right_color.r - seg->left_color.r) * factor;
|
|
|
|
rgb.g =
|
|
seg->left_color.g + (seg->right_color.g - seg->left_color.g) * factor;
|
|
|
|
rgb.b =
|
|
seg->left_color.b + (seg->right_color.b - seg->left_color.b) * factor;
|
|
}
|
|
else
|
|
{
|
|
GimpHSV left_hsv;
|
|
GimpHSV right_hsv;
|
|
|
|
gimp_rgb_to_hsv (&seg->left_color, &left_hsv);
|
|
gimp_rgb_to_hsv (&seg->right_color, &right_hsv);
|
|
|
|
left_hsv.s = left_hsv.s + (right_hsv.s - left_hsv.s) * factor;
|
|
left_hsv.v = left_hsv.v + (right_hsv.v - left_hsv.v) * factor;
|
|
|
|
switch (seg->color)
|
|
{
|
|
case GRAD_HSV_CCW:
|
|
if (left_hsv.h < right_hsv.h)
|
|
{
|
|
left_hsv.h += (right_hsv.h - left_hsv.h) * factor;
|
|
}
|
|
else
|
|
{
|
|
left_hsv.h += (1.0 - (left_hsv.h - right_hsv.h)) * factor;
|
|
|
|
if (left_hsv.h > 1.0)
|
|
left_hsv.h -= 1.0;
|
|
}
|
|
break;
|
|
|
|
case GRAD_HSV_CW:
|
|
if (right_hsv.h < left_hsv.h)
|
|
{
|
|
left_hsv.h -= (left_hsv.h - right_hsv.h) * factor;
|
|
}
|
|
else
|
|
{
|
|
left_hsv.h -= (1.0 - (right_hsv.h - left_hsv.h)) * factor;
|
|
|
|
if (left_hsv.h < 0.0)
|
|
left_hsv.h += 1.0;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
gimp_fatal_error ("%s(): Unknown coloring mode %d",
|
|
G_GNUC_FUNCTION, (gint) seg->color);
|
|
break;
|
|
}
|
|
|
|
gimp_hsv_to_rgb (&left_hsv, &rgb);
|
|
}
|
|
|
|
*color = rgb;
|
|
}
|
|
|
|
GimpGradientSegment *
|
|
gimp_gradient_get_segment_at (GimpGradient *gradient,
|
|
gdouble pos)
|
|
{
|
|
GimpGradientSegment *seg;
|
|
|
|
g_return_val_if_fail (gradient != NULL, NULL);
|
|
g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), NULL);
|
|
|
|
/* handle FP imprecision at the edges of the gradient */
|
|
pos = CLAMP (pos, 0.0, 1.0);
|
|
|
|
if (gradient->last_visited)
|
|
seg = gradient->last_visited;
|
|
else
|
|
seg = gradient->segments;
|
|
|
|
while (seg)
|
|
{
|
|
if (pos >= seg->left)
|
|
{
|
|
if (pos <= seg->right)
|
|
{
|
|
gradient->last_visited = seg; /* for speed */
|
|
return seg;
|
|
}
|
|
else
|
|
{
|
|
seg = seg->next;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
seg = seg->prev;
|
|
}
|
|
}
|
|
|
|
/* Oops: we should have found a segment, but we didn't */
|
|
gimp_fatal_error ("%s(): no matching segment for position %0.15f",
|
|
G_GNUC_FUNCTION, pos);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static gdouble
|
|
gimp_gradient_calc_linear_factor (gdouble middle,
|
|
gdouble pos)
|
|
{
|
|
if (pos <= middle)
|
|
{
|
|
if (middle < EPSILON)
|
|
return 0.0;
|
|
else
|
|
return 0.5 * pos / middle;
|
|
}
|
|
else
|
|
{
|
|
pos -= middle;
|
|
middle = 1.0 - middle;
|
|
|
|
if (middle < EPSILON)
|
|
return 1.0;
|
|
else
|
|
return 0.5 + 0.5 * pos / middle;
|
|
}
|
|
}
|
|
|
|
static gdouble
|
|
gimp_gradient_calc_curved_factor (gdouble middle,
|
|
gdouble pos)
|
|
{
|
|
if (middle < EPSILON)
|
|
middle = EPSILON;
|
|
|
|
return pow(pos, log (0.5) / log (middle));
|
|
}
|
|
|
|
static gdouble
|
|
gimp_gradient_calc_sine_factor (gdouble middle,
|
|
gdouble pos)
|
|
{
|
|
pos = gimp_gradient_calc_linear_factor (middle, pos);
|
|
|
|
return (sin ((-G_PI / 2.0) + G_PI * pos) + 1.0) / 2.0;
|
|
}
|
|
|
|
static gdouble
|
|
gimp_gradient_calc_sphere_increasing_factor (gdouble middle,
|
|
gdouble pos)
|
|
{
|
|
pos = gimp_gradient_calc_linear_factor (middle, pos) - 1.0;
|
|
|
|
return sqrt (1.0 - pos * pos); /* Works for convex increasing and concave decreasing */
|
|
}
|
|
|
|
static gdouble
|
|
gimp_gradient_calc_sphere_decreasing_factor (gdouble middle,
|
|
gdouble pos)
|
|
{
|
|
pos = gimp_gradient_calc_linear_factor (middle, pos);
|
|
|
|
return 1.0 - sqrt(1.0 - pos * pos); /* Works for convex decreasing and concave increasing */
|
|
}
|
|
|
|
|
|
/* gradient segment functions */
|
|
|
|
GimpGradientSegment *
|
|
gimp_gradient_segment_new (void)
|
|
{
|
|
GimpGradientSegment *seg;
|
|
|
|
seg = g_new (GimpGradientSegment, 1);
|
|
|
|
seg->left = 0.0;
|
|
seg->middle = 0.5;
|
|
seg->right = 1.0;
|
|
|
|
gimp_rgba_set (&seg->left_color, 0.0, 0.0, 0.0, 1.0);
|
|
gimp_rgba_set (&seg->right_color, 1.0, 1.0, 1.0, 1.0);
|
|
|
|
seg->type = GRAD_LINEAR;
|
|
seg->color = GRAD_RGB;
|
|
|
|
seg->prev = seg->next = NULL;
|
|
|
|
return seg;
|
|
}
|
|
|
|
|
|
void
|
|
gimp_gradient_segment_free (GimpGradientSegment *seg)
|
|
{
|
|
g_return_if_fail (seg != NULL);
|
|
|
|
g_free (seg);
|
|
}
|
|
|
|
void
|
|
gimp_gradient_segments_free (GimpGradientSegment *seg)
|
|
{
|
|
GimpGradientSegment *tmp;
|
|
|
|
g_return_if_fail (seg != NULL);
|
|
|
|
while (seg)
|
|
{
|
|
tmp = seg->next;
|
|
gimp_gradient_segment_free (seg);
|
|
seg = tmp;
|
|
}
|
|
}
|
|
|
|
GimpGradientSegment *
|
|
gimp_gradient_segment_get_last (GimpGradientSegment *seg)
|
|
{
|
|
if (!seg)
|
|
return NULL;
|
|
|
|
while (seg->next)
|
|
seg = seg->next;
|
|
|
|
return seg;
|
|
}
|