diff -uNr gimp-2.4.1/app/core/gimp-modules.c gimp-2.4.1-work/app/core/gimp-modules.c --- gimp-2.4.1/app/core/gimp-modules.c 2007-01-23 19:13:46.000000000 +0900 +++ gimp-2.4.1-work/app/core/gimp-modules.c 2008-01-14 00:22:41.000000000 +0900 @@ -71,6 +71,8 @@ g_return_if_fail (GIMP_IS_GIMP (gimp)); + g_print("[Trace]:Start:gimp_modules_load\n"); + if (gimp->no_interface) return; @@ -154,6 +156,7 @@ path = gimp_config_path_expand (gimp->config->module_path, TRUE, NULL); gimp_module_db_load (gimp->module_db, path); g_free (path); + g_print("[Trace]:End :gimp_modules_load\n"); } static void diff -uNr gimp-2.4.1/app/paint/Makefile.am gimp-2.4.1-work/app/paint/Makefile.am --- gimp-2.4.1/app/paint/Makefile.am 2007-06-27 18:50:25.000000000 +0900 +++ gimp-2.4.1-work/app/paint/Makefile.am 2007-11-04 19:40:41.000000000 +0900 @@ -77,7 +77,17 @@ gimpsourcecore.c \ gimpsourcecore.h \ gimpsourceoptions.c \ - gimpsourceoptions.h + gimpsourceoptions.h \ + gimpink2.c \ + gimpink2.h \ + gimpink2undo.c \ + gimpink2undo.h \ + gimpink2options.c \ + gimpink2options.h \ + gimpmixbrush.c \ + gimpmixbrush.h \ + gimpmixbrushoptions.c \ + gimpmixbrushoptions.h libapppaint_a_built_sources = paint-enums.c diff -uNr gimp-2.4.1/app/paint/Makefile.in gimp-2.4.1-work/app/paint/Makefile.in --- gimp-2.4.1/app/paint/Makefile.in 2007-10-31 17:09:07.000000000 +0900 +++ gimp-2.4.1-work/app/paint/Makefile.in 2007-11-04 19:40:41.000000000 +0900 @@ -70,7 +70,9 @@ gimppaintbrush.$(OBJEXT) gimpperspectiveclone.$(OBJEXT) \ gimpperspectivecloneoptions.$(OBJEXT) gimpsmudge.$(OBJEXT) \ gimpsmudgeoptions.$(OBJEXT) gimpsourcecore.$(OBJEXT) \ - gimpsourceoptions.$(OBJEXT) + gimpsourceoptions.$(OBJEXT) \ + gimpink2.$(OBJEXT) gimpink2options.$(OBJEXT) gimpink2undo.$(OBJEXT) \ + gimpmixbrush.$(OBJEXT) gimpmixbrushoptions.$(OBJEXT) am_libapppaint_a_OBJECTS = $(am__objects_1) $(am__objects_2) libapppaint_a_OBJECTS = $(am_libapppaint_a_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) @@ -535,7 +537,17 @@ gimpsourcecore.c \ gimpsourcecore.h \ gimpsourceoptions.c \ - gimpsourceoptions.h + gimpsourceoptions.h \ + gimpink2.c \ + gimpink2.h \ + gimpink2options.c \ + gimpink2options.h \ + gimpink2undo.c \ + gimpink2undo.h \ + gimpmixbrush.c \ + gimpmixbrush.h \ + gimpmixbrushoptions.c \ + gimpmixbrushoptions.h libapppaint_a_built_sources = paint-enums.c libapppaint_a_SOURCES = $(libapppaint_a_built_sources) $(libapppaint_a_sources) @@ -625,6 +637,11 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpsourcecore.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpsourceoptions.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/paint-enums.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpink2.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpink2options.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpink2undo.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpmixbrush.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpmixbrushoptions.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ diff -uNr gimp-2.4.1/app/paint/gimp-paint.c gimp-2.4.1-work/app/paint/gimp-paint.c --- gimp-2.4.1/app/paint/gimp-paint.c 2007-07-25 03:45:42.000000000 +0900 +++ gimp-2.4.1-work/app/paint/gimp-paint.c 2008-01-14 00:19:59.000000000 +0900 @@ -39,6 +39,8 @@ #include "gimppencil.h" #include "gimpperspectiveclone.h" #include "gimpsmudge.h" +#include "gimpink2.h" +#include "gimpmixbrush.h" /* local function prototypes */ @@ -68,12 +70,15 @@ gimp_airbrush_register, gimp_eraser_register, gimp_paintbrush_register, - gimp_pencil_register + gimp_pencil_register, + gimp_ink2_register, + gimp_mixbrush_register }; gint i; g_return_if_fail (GIMP_IS_GIMP (gimp)); + g_print("[Trace]:gimp_paint_init\n"); gimp->paint_info_list = gimp_list_new (GIMP_TYPE_PAINT_INFO, FALSE); gimp_object_set_static_name (GIMP_OBJECT (gimp->paint_info_list), diff -uNr gimp-2.4.1/app/paint/gimpbrushcore.c gimp-2.4.1-work/app/paint/gimpbrushcore.c --- gimp-2.4.1/app/paint/gimpbrushcore.c 2007-08-16 06:56:50.000000000 +0900 +++ gimp-2.4.1-work/app/paint/gimpbrushcore.c 2008-01-15 00:29:58.000000000 +0900 @@ -41,6 +41,9 @@ #include "gimp-intl.h" +// Temporary needed! +#include "paint-funcs/paint-funcs.h" +#include "gimpairbrush.h" #define EPSILON 0.00001 @@ -810,13 +813,195 @@ GimpBrushApplicationMode brush_hardness, GimpPaintApplicationMode mode) { + PixelRegion brush_maskPR; + if (gimp_brush_core_get_brush_maskPR(core, brush_hardness, &brush_maskPR)) + { + gimp_paint_core_paste (GIMP_PAINT_CORE(core), &brush_maskPR, drawable, + brush_opacity, + image_opacity, paint_mode, + mode); + } +} + + +struct _GimpBrushCorePasteCanvasInternal +{ + GimpPaintMaskInfo info; + GimpBrushCorePasteCanvasInfo *pcinfo; + GimpBrushCore *core; + GimpDrawable *drawable; +}; +typedef struct _GimpBrushCorePasteCanvasInternal GimpBrushCorePasteCanvasInternal; + +static GimpBrushCorePasteCanvasInternal* +brush_core_create_internal_list (gint num_items, + GimpBrushCore *core, + GimpDrawable *drawable) +{ + GimpBrushCorePasteCanvasInternal *mask_info_list, *cur_mask_info; + gint i; + + cur_mask_info = + mask_info_list = + (GimpBrushCorePasteCanvasInternal*)g_malloc0(num_items * sizeof(GimpBrushCorePasteCanvasInternal)); + if (!mask_info_list) + return NULL; + + for (i = 0; i < num_items; i ++) + { + if (i == num_items - 1) + cur_mask_info->info.next = NULL; + else + cur_mask_info->info.next = &(cur_mask_info + 1)->info; + + cur_mask_info->info.delegator_data = cur_mask_info; + cur_mask_info->core = core; + cur_mask_info->drawable = drawable; + cur_mask_info ++; + } + + return mask_info_list; +} + + + +static gint +gimp_brush_core_process_paste_canvas_pre_paint (GimpPaintMaskInfo *info, + GimpPaintCore *core, + GimpDrawable *drawable, + GimpPaintApplicationMode mode) +{ + GimpBrushCorePasteCanvasInternal *internal = (GimpBrushCorePasteCanvasInternal*)info->delegator_data; + internal->pcinfo->pre_paint(internal->pcinfo, GIMP_BRUSH_CORE(core), drawable); + + return 0; +} + + + +static gint +gimp_brush_core_process_paste_canvas_paint (GimpPaintMaskInfo *info, + GimpPaintCore *core, + GimpDrawable *drawable, + GimpPaintApplicationMode mode, + PixelRegion *srcPR) +{ + GimpBrushCorePasteCanvasInternal *internal = (GimpBrushCorePasteCanvasInternal*)info->delegator_data; + if (!gimp_brush_core_get_brush_maskPR(GIMP_BRUSH_CORE(core), + internal->pcinfo->brush_hardness, + info->paint_maskPR)) + return -1; + { + PixelRegion paint_maskPR_copy = *info->paint_maskPR; + + if (internal->pcinfo->paint_operation) + return internal->pcinfo->paint_operation(internal->pcinfo, GIMP_BRUSH_CORE(core), + drawable, srcPR, &paint_maskPR_copy); + else if (mode == GIMP_PAINT_CONSTANT) + /* combine the mask to the canvas tiles */ + combine_mask_and_region (srcPR, &paint_maskPR_copy, + info->paint_opacity * 255.999, GIMP_IS_AIRBRUSH (core)); + else + /* apply the mask */ + apply_mask_to_region (srcPR, &paint_maskPR_copy, info->paint_opacity * 255.999); + } + return 0; +} + + + +static gint +gimp_brush_core_process_paste_canvas_post_paint (GimpPaintMaskInfo *info, + GimpPaintCore *core, + GimpDrawable *drawable, + GimpPaintApplicationMode mode) +{ + GimpBrushCorePasteCanvasInternal *internal = (GimpBrushCorePasteCanvasInternal*)info->delegator_data; + /* This function is called only if pcinfo->post_paint != NULL */ + return internal->pcinfo->post_paint(internal->pcinfo, GIMP_BRUSH_CORE(core), drawable); + + return 0; +} + + + +static gint +gimp_brush_core_process_paste_canvas_apply (GimpPaintMaskInfo *info, + GimpPaintCore *core, + GimpDrawable *drawable, + GimpPaintApplicationMode mode, + PixelRegion *srcPR, + TileManager *undo_tiles) +{ + GimpBrushCorePasteCanvasInternal *internal = (GimpBrushCorePasteCanvasInternal*)info->delegator_data; + PixelRegion paint_maskPR_copy = *info->paint_maskPR; + /* This function is called only if pcinfo->apply_operation != NULL */ + return internal->pcinfo->apply_operation(internal->pcinfo, GIMP_BRUSH_CORE(core), + drawable, srcPR, &paint_maskPR_copy, undo_tiles); +} + + +void +gimp_brush_core_process_paste_canvas (GimpBrushCore *core, + GimpDrawable *drawable, + GimpBrushCorePasteCanvasInfo *info, + GimpPaintApplicationMode mode) +{ + PixelRegion brush_maskPR; + GimpBrushCorePasteCanvasInternal *mask_info_list, *cur_mask_info; + gint info_num = 0; + GimpBrushCorePasteCanvasInfo *cur_info = info; + + /* Create GimpPaintMask Info list */ + while (cur_info) + { + cur_info = cur_info->next; + info_num ++; + } + + cur_mask_info = + mask_info_list = + brush_core_create_internal_list (info_num, core, drawable); + + /* Setup info parameters */ + while (info) + { + cur_mask_info->info.paint_maskPR = &brush_maskPR; + cur_mask_info->info.paint_opacity = info->brush_opacity; + cur_mask_info->info.image_opacity = info->image_opacity; + cur_mask_info->info.apply = info->apply; + cur_mask_info->info.paint_mode = info->paint_mode; + cur_mask_info->pcinfo = info; + cur_mask_info->info.paint_operation = gimp_brush_core_process_paste_canvas_paint; + if (info->pre_paint) + cur_mask_info->info.pre_paint = gimp_brush_core_process_paste_canvas_pre_paint; + if (info->post_paint) + cur_mask_info->info.post_paint = gimp_brush_core_process_paste_canvas_post_paint; + if (info->apply_operation) + cur_mask_info->info.apply_operation = gimp_brush_core_process_paste_canvas_apply; + + cur_mask_info ++; + info = info->next; + } + + /* Execute paste processing */ + gimp_paint_core_paste_mask_list (GIMP_PAINT_CORE(core), drawable, + &mask_info_list->info, + mode); + g_free (mask_info_list); +} + +gboolean +gimp_brush_core_get_brush_maskPR (GimpBrushCore *core, + GimpBrushApplicationMode brush_hardness, + PixelRegion *brush_maskPR) +{ TempBuf *brush_mask = gimp_brush_core_get_brush_mask (core, brush_hardness); if (brush_mask) { GimpPaintCore *paint_core = GIMP_PAINT_CORE (core); - PixelRegion brush_maskPR; gint x; gint y; gint off_x; @@ -828,16 +1013,14 @@ off_x = (x < 0) ? -x : 0; off_y = (y < 0) ? -y : 0; - pixel_region_init_temp_buf (&brush_maskPR, brush_mask, + pixel_region_init_temp_buf (brush_maskPR, brush_mask, off_x, off_y, paint_core->canvas_buf->width, paint_core->canvas_buf->height); - - gimp_paint_core_paste (paint_core, &brush_maskPR, drawable, - brush_opacity, - image_opacity, paint_mode, - mode); + return TRUE; } + else + return FALSE; } /* Similar to gimp_brush_core_paste_canvas, but replaces the alpha channel diff -uNr gimp-2.4.1/app/paint/gimpbrushcore.h gimp-2.4.1-work/app/paint/gimpbrushcore.h --- gimp-2.4.1/app/paint/gimpbrushcore.h 2007-07-25 03:45:42.000000000 +0900 +++ gimp-2.4.1-work/app/paint/gimpbrushcore.h 2008-01-14 23:28:11.000000000 +0900 @@ -98,6 +98,46 @@ GimpBrush *brush); }; +typedef struct _GimpBrushCorePasteCanvasInfo GimpBrushCorePasteCanvasInfo; +typedef gint (*GimpBrushCorePasteCanvasInfoEventCallback) + (GimpBrushCorePasteCanvasInfo *info, + GimpBrushCore *core, + GimpDrawable *drawable); + +typedef gint (*GimpBrushCorePasteCanvasInfoPaintDelegator) + (GimpBrushCorePasteCanvasInfo *info, + GimpBrushCore *core, + GimpDrawable *drawable, + PixelRegion *srcPR, + PixelRegion *brush_maskPR); + +typedef gint (*GimpBrushCorePasteCanvasInfoApplicationDelegator) + (GimpBrushCorePasteCanvasInfo *info, + GimpBrushCore *core, + GimpDrawable *drawable, + PixelRegion *srcPR, + PixelRegion *maskPR, + TileManager *undo_tiles); + + +struct _GimpBrushCorePasteCanvasInfo +{ + TempBuf *gimp_brush_area; + gdouble brush_opacity; + gdouble image_opacity; + GimpLayerModeEffects paint_mode; + GimpBrushApplicationMode brush_hardness; + GimpPaintApplicationMode mode; + GimpBrushCorePasteCanvasInfoPaintDelegator paint_operation; + GimpBrushCorePasteCanvasInfoEventCallback pre_paint; + GimpBrushCorePasteCanvasInfoEventCallback post_paint; + GimpBrushCorePasteCanvasInfoApplicationDelegator apply_operation; + gboolean apply; + void *user_data; + GimpBrushCorePasteCanvasInfo *next; +}; + + GType gimp_brush_core_get_type (void) G_GNUC_CONST; @@ -113,6 +153,11 @@ GimpLayerModeEffects paint_mode, GimpBrushApplicationMode brush_hardness, GimpPaintApplicationMode mode); +void gimp_brush_core_process_paste_canvas + (GimpBrushCore *core, + GimpDrawable *drawable, + GimpBrushCorePasteCanvasInfo *info, + GimpPaintApplicationMode mode); void gimp_brush_core_replace_canvas (GimpBrushCore *core, GimpDrawable *drawable, gdouble brush_opacity, @@ -126,5 +171,9 @@ TempBuf *area, GimpBrushApplicationMode mode); +gboolean +gimp_brush_core_get_brush_maskPR (GimpBrushCore *core, + GimpBrushApplicationMode brush_hardness, + PixelRegion *brush_maskPR); #endif /* __GIMP_BRUSH_CORE_H__ */ diff -uNr gimp-2.4.1/app/paint/gimpink2.c gimp-2.4.1-work/app/paint/gimpink2.c --- gimp-2.4.1/app/paint/gimpink2.c 1970-01-01 09:00:00.000000000 +0900 +++ gimp-2.4.1-work/app/paint/gimpink2.c 2007-11-04 19:40:41.000000000 +0900 @@ -0,0 +1,915 @@ +/* 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 "libgimpmath/gimpmath.h" + +#include "paint-types.h" + +#include "base/pixel-region.h" +#include "base/temp-buf.h" +#include "base/tile.h" +#include "base/tile-manager.h" + +#include "paint-funcs/paint-funcs.h" + +#include "core/gimpdrawable.h" +#include "core/gimpimage.h" +#include "core/gimpimage-undo.h" + +#include "gimpink2options.h" +#include "gimpink2.h" +#include "gimpink-blob.h" +#include "gimpink2undo.h" + +#include "gimp-intl.h" + + +#define SUBSAMPLE 8 + + +/* local function prototypes */ + +static void gimp_ink2_finalize (GObject *object); + +static void gimp_ink2_paint (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *paint_options, + GimpPaintState paint_state, + guint32 time); +static TempBuf * gimp_ink2_get_paint_area (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *paint_options); +static GimpUndo* gimp_ink2_push_undo (GimpPaintCore *core, + GimpImage *image, + const gchar *undo_desc); + +static void gimp_ink2_motion (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *paint_options, + guint32 time, + gboolean at_last); + +static Blob * ink2_pen_ellipse (GimpInk2Options *options, + gdouble x_center, + gdouble y_center, + gdouble pressure, + gdouble xtilt, + gdouble ytilt, + gdouble velocity); + +static void time_smoother_add (GimpInk2 *ink, + guint32 value); +static guint32 time_smoother_result (GimpInk2 *ink); +static void time_smoother_init (GimpInk2 *ink, + guint32 initval); + +static void dist_smoother_add (GimpInk2 *ink, + gdouble value); +static gdouble dist_smoother_result (GimpInk2 *ink); +static void dist_smoother_init (GimpInk2 *ink, + gdouble initval); + +static void render_blob (Blob *blob, + PixelRegion *dest); + +/* Ink2 additional functions */ +static void hist_init (GimpInk2 *ink, GimpCoords* coords); +static void hist_add (GimpInk2 *ink, GimpCoords* coords, gdouble speed); +static GimpCoords hist_result (GimpInk2 *ink, GimpInk2Options *options); +static GimpCoords hist_result_velocity (GimpInk2 *ink, GimpInk2Options *options); + +static gdouble PI; +/* */ + + +G_DEFINE_TYPE (GimpInk2, gimp_ink2, GIMP_TYPE_PAINT_CORE) + +#define parent_class gimp_ink2_parent_class + + +void +gimp_ink2_register (Gimp *gimp, + GimpPaintRegisterCallback callback) +{ + (* callback) (gimp, + GIMP_TYPE_INK2, + GIMP_TYPE_INK2_OPTIONS, + "gimp-ink2", + _("G-pen"), + "gimp-tool-ink2"); +} + +static void +gimp_ink2_class_init (GimpInk2Class *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpPaintCoreClass *paint_core_class = GIMP_PAINT_CORE_CLASS (klass); + + object_class->finalize = gimp_ink2_finalize; + + paint_core_class->paint = gimp_ink2_paint; + paint_core_class->get_paint_area = gimp_ink2_get_paint_area; + paint_core_class->push_undo = gimp_ink2_push_undo; + + /* initialize internal variables */ + PI = 4 * atan(1); +} + +static void +gimp_ink2_init (GimpInk2 *ink) +{ +} + +static void +gimp_ink2_finalize (GObject *object) +{ + GimpInk2 *ink = GIMP_INK2 (object); + + if (ink->start_blob) + { + g_free (ink->start_blob); + ink->start_blob = NULL; + } + + if (ink->last_blob) + { + g_free (ink->last_blob); + ink->last_blob = NULL; + } + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_ink2_paint (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *paint_options, + GimpPaintState paint_state, + guint32 time) +{ + GimpInk2 *ink = GIMP_INK2 (paint_core); + + switch (paint_state) + { + case GIMP_PAINT_STATE_INIT: + if (paint_core->cur_coords.x == paint_core->last_coords.x && + paint_core->cur_coords.y == paint_core->last_coords.y) + { + /* start with new blobs if we're not interpolating */ + + if (ink->start_blob) + { + g_free (ink->start_blob); + ink->start_blob = NULL; + } + + if (ink->last_blob) + { + g_free (ink->last_blob); + ink->last_blob = NULL; + } + } + else if (ink->last_blob) + { + /* save the start blob of the line for undo otherwise */ + + if (ink->start_blob) + g_free (ink->start_blob); + + ink->start_blob = blob_duplicate (ink->last_blob); + } + break; + + case GIMP_PAINT_STATE_MOTION: + gimp_ink2_motion (paint_core, drawable, paint_options, time, FALSE); + break; + + case GIMP_PAINT_STATE_FINISH: + gimp_ink2_motion (paint_core, drawable, paint_options, time, TRUE); + /*g_printf("\n");*/ + break; + } +} + +static TempBuf * +gimp_ink2_get_paint_area (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *paint_options) +{ + GimpInk2 *ink = GIMP_INK2 (paint_core); + gint x, y; + gint width, height; + gint dwidth, dheight; + gint x1, y1, x2, y2; + gint bytes; + + bytes = gimp_drawable_bytes_with_alpha (drawable); + + blob_bounds (ink->cur_blob, &x, &y, &width, &height); + + dwidth = gimp_item_width (GIMP_ITEM (drawable)); + dheight = gimp_item_height (GIMP_ITEM (drawable)); + + x1 = CLAMP (x / SUBSAMPLE - 1, 0, dwidth); + y1 = CLAMP (y / SUBSAMPLE - 1, 0, dheight); + x2 = CLAMP ((x + width) / SUBSAMPLE + 2, 0, dwidth); + y2 = CLAMP ((y + height) / SUBSAMPLE + 2, 0, dheight); + + /* configure the canvas buffer */ + if ((x2 - x1) && (y2 - y1)) + paint_core->canvas_buf = temp_buf_resize (paint_core->canvas_buf, bytes, + x1, y1, + (x2 - x1), (y2 - y1)); + else + return NULL; + + return paint_core->canvas_buf; +} + +static GimpUndo * +gimp_ink2_push_undo (GimpPaintCore *core, + GimpImage *image, + const gchar *undo_desc) +{ + return gimp_image_undo_push (image, GIMP_TYPE_INK2_UNDO, + GIMP_UNDO_INK, undo_desc, + 0, + "paint-core", core, + NULL); +} + +static void +gimp_ink2_motion (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *paint_options, + guint32 time, + gboolean at_last) +{ + GimpInk2 *ink = GIMP_INK2 (paint_core); + GimpInk2Options *options = GIMP_INK2_OPTIONS (paint_options); + GimpContext *context = GIMP_CONTEXT (paint_options); + GimpImage *image; + Blob *blob_union = NULL; + Blob *blob_to_render; + TempBuf *area; + guchar col[MAX_CHANNELS]; + PixelRegion blob_maskPR; + + if (at_last && !options->compensate_at_last) + return; + + image = gimp_item_get_image (GIMP_ITEM (drawable)); + + if (! ink->last_blob) + { + ink->last_blob = ink2_pen_ellipse (options, + paint_core->cur_coords.x, + paint_core->cur_coords.y, + paint_core->cur_coords.pressure, + paint_core->cur_coords.xtilt, + paint_core->cur_coords.ytilt, + 10.0); + + if (ink->start_blob) + g_free (ink->start_blob); + + ink->start_blob = blob_duplicate (ink->last_blob); + + time_smoother_init (ink, time); + ink->last_time = time; + + dist_smoother_init (ink, 0.0); + ink->init_velocity = TRUE; + + hist_init (ink, &paint_core->cur_coords); + + blob_to_render = ink->last_blob; + } + else + { + Blob *blob; + gdouble dist; + gdouble velocity; + guint32 lasttime = ink->last_time; + guint32 thistime; + GimpCoords average_hist; + GimpCoords average_velocity; + + time_smoother_add (ink, time); + thistime = ink->last_time = time_smoother_result (ink); + + /* The time resolution on X-based GDK motion events is bloody + * awful, hence the use of the smoothing function. Sadly this + * also means that there is always the chance of having an + * indeterminite velocity since this event and the previous + * several may still appear to issue at the same + * instant. -ADM + */ + if (thistime == lasttime) + thistime = lasttime + 1; + + dist = sqrt ((paint_core->last_coords.x - paint_core->cur_coords.x) * + (paint_core->last_coords.x - paint_core->cur_coords.x) + + (paint_core->last_coords.y - paint_core->cur_coords.y) * + (paint_core->last_coords.y - paint_core->cur_coords.y)); + + if (ink->init_velocity) + { + dist_smoother_init (ink, dist); + ink->init_velocity = FALSE; + } + else + { + dist_smoother_add (ink, dist); + dist = dist_smoother_result (ink); + } + + velocity = 10.0 * sqrt ((dist) / (gdouble) (thistime - lasttime)); + + /* g_printf("%f, %f, %f\n", paint_core->cur_coords.x, paint_core->cur_coords.y, velocity); */ + + if (!at_last && options->compensation_hist_size > 1) + { + hist_add(ink, &paint_core->cur_coords, velocity); + average_hist = hist_result(ink, options); + blob = ink2_pen_ellipse (options, + average_hist.x, + average_hist.y, + paint_core->cur_coords.pressure, + paint_core->cur_coords.xtilt, + paint_core->cur_coords.ytilt, + velocity); + ink->last_point = average_hist; + } + else + { + blob = ink2_pen_ellipse (options, + paint_core->cur_coords.x, + paint_core->cur_coords.y, + paint_core->cur_coords.pressure, + paint_core->cur_coords.xtilt, + paint_core->cur_coords.ytilt, + velocity); + } + + blob_union = blob_convex_union (ink->last_blob, blob); + g_free (ink->last_blob); + ink->last_blob = blob; + + blob_to_render = blob_union; + } + + /* Get the buffer */ + ink->cur_blob = blob_to_render; + area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options); + ink->cur_blob = NULL; + + if (! area) + return; + + gimp_image_get_foreground (image, context, gimp_drawable_type (drawable), col); + + /* set the alpha channel */ + col[paint_core->canvas_buf->bytes - 1] = OPAQUE_OPACITY; + + /* color the pixels */ + color_pixels (temp_buf_data (paint_core->canvas_buf), col, + area->width * area->height, area->bytes); + + gimp_paint_core_validate_canvas_tiles (paint_core, + paint_core->canvas_buf->x, + paint_core->canvas_buf->y, + paint_core->canvas_buf->width, + paint_core->canvas_buf->height); + + /* draw the blob directly to the canvas_tiles */ + pixel_region_init (&blob_maskPR, paint_core->canvas_tiles, + paint_core->canvas_buf->x, + paint_core->canvas_buf->y, + paint_core->canvas_buf->width, + paint_core->canvas_buf->height, + TRUE); + + render_blob (blob_to_render, &blob_maskPR); + + /* draw the canvas_buf using the just rendered canvas_tiles as mask */ + pixel_region_init (&blob_maskPR, paint_core->canvas_tiles, + paint_core->canvas_buf->x, + paint_core->canvas_buf->y, + paint_core->canvas_buf->width, + paint_core->canvas_buf->height, + FALSE); + + gimp_paint_core_paste (paint_core, &blob_maskPR, drawable, + GIMP_OPACITY_OPAQUE, + gimp_context_get_opacity (context), + gimp_context_get_paint_mode (context), + GIMP_PAINT_CONSTANT); + + if (blob_union) + g_free (blob_union); +} + +static Blob * +ink2_pen_ellipse (GimpInk2Options *options, + gdouble x_center, + gdouble y_center, + gdouble pressure, + gdouble xtilt, + gdouble ytilt, + gdouble velocity) +{ + BlobFunc blob_function; + gdouble size; + gdouble tsin, tcos; + gdouble aspect, radmin; + gdouble x,y; + gdouble tscale; + gdouble tscale_c; + gdouble tscale_s; + + /* Adjust the size depending on pressure. */ + + size = options->size * (1.0 + options->size_sensitivity * + (2.0 * pressure - 1.0)); + + /* Adjust the size further depending on pointer velocity and + * velocity-sensitivity. These 'magic constants' are 'feels + * natural' tigert-approved. --ADM + */ + + if (velocity < 3.0) + velocity = 3.0; + +#ifdef VERBOSE + g_printerr ("%g (%g) -> ", size, velocity); +#endif + + size = (options->vel_sensitivity * + ((4.5 * size) / (1.0 + options->vel_sensitivity * (2.0 * velocity))) + + (1.0 - options->vel_sensitivity) * size); + +#ifdef VERBOSE + g_printerr ("%g\n", (gfloat) size); +#endif + + /* Clamp resulting size to sane limits */ + + if (size > options->size * (1.0 + options->size_sensitivity)) + size = options->size * (1.0 + options->size_sensitivity); + + if (size * SUBSAMPLE < 1.0) + size = 1.0 / SUBSAMPLE; + + /* Add brush angle/aspect to tilt vectorially */ + + /* I'm not happy with the way the brush widget info is combined with + * tilt info from the brush. My personal feeling is that + * representing both as affine transforms would make the most + * sense. -RLL + */ + + tscale = options->tilt_sensitivity * 10.0; + tscale_c = tscale * cos (gimp_deg_to_rad (options->tilt_angle)); + tscale_s = tscale * sin (gimp_deg_to_rad (options->tilt_angle)); + + x = (options->blob_aspect * cos (options->blob_angle) + + xtilt * tscale_c - ytilt * tscale_s); + y = (options->blob_aspect * sin (options->blob_angle) + + ytilt * tscale_c + xtilt * tscale_s); + +#ifdef VERBOSE + g_printerr ("angle %g aspect %g; %g %g; %g %g\n", + options->blob_angle, options->blob_aspect, + tscale_c, tscale_s, x, y); +#endif + + aspect = sqrt (x * x + y * y); + + if (aspect != 0) + { + tcos = x / aspect; + tsin = y / aspect; + } + else + { + tsin = sin (options->blob_angle); + tcos = cos (options->blob_angle); + } + + aspect = CLAMP (aspect, 1.0, 10.0); + + radmin = MAX (1.0, SUBSAMPLE * size / aspect); + + switch (options->blob_type) + { + case GIMP_INK_BLOB_TYPE_ELLIPSE: + blob_function = blob_ellipse; + break; + + case GIMP_INK_BLOB_TYPE_SQUARE: + blob_function = blob_square; + break; + + case GIMP_INK_BLOB_TYPE_DIAMOND: + blob_function = blob_diamond; + break; + + default: + g_return_val_if_reached (NULL); + break; + } + + return (* blob_function) (x_center * SUBSAMPLE, + y_center * SUBSAMPLE, + radmin * aspect * tcos, + radmin * aspect * tsin, + -radmin * tsin, + radmin * tcos); +} + + +static void +time_smoother_init (GimpInk2 *ink, + guint32 initval) +{ + gint i; + + ink->ts_index = 0; + + for (i = 0; i < INK2_TIME_SMOOTHER_BUFFER; i++) + ink->ts_buffer[i] = initval; +} + +static guint32 +time_smoother_result (GimpInk2 *ink) +{ + gint i; + guint64 result = 0; + + for (i = 0; i < INK2_TIME_SMOOTHER_BUFFER; i++) + result += ink->ts_buffer[i]; + + return (result / (guint64) INK2_TIME_SMOOTHER_BUFFER); +} + +static void +time_smoother_add (GimpInk2 *ink, + guint32 value) +{ + guint64 long_value = (guint64) value; + + /* handle wrap-around of time values */ + if (long_value < ink->ts_buffer[ink->ts_index]) + long_value += (guint64) + G_MAXUINT32; + + ink->ts_buffer[ink->ts_index++] = long_value; + + ink->ts_buffer[ink->ts_index++] = value; + + if (ink->ts_index == INK2_TIME_SMOOTHER_BUFFER) + ink->ts_index = 0; +} + + +static void +dist_smoother_init (GimpInk2 *ink, + gdouble initval) +{ + gint i; + + ink->dt_index = 0; + + for (i = 0; i < INK2_DIST_SMOOTHER_BUFFER; i++) + ink->dt_buffer[i] = initval; +} + +static gdouble +dist_smoother_result (GimpInk2 *ink) +{ + gint i; + gdouble result = 0.0; + + for (i = 0; i < INK2_DIST_SMOOTHER_BUFFER; i++) + result += ink->dt_buffer[i]; + + return (result / (gdouble) INK2_DIST_SMOOTHER_BUFFER); +} + +static void +dist_smoother_add (GimpInk2 *ink, + gdouble value) +{ + ink->dt_buffer[ink->dt_index++] = value; + + if (ink->dt_index == INK2_DIST_SMOOTHER_BUFFER) + ink->dt_index = 0; +} + +/**************************************************************/ + +static void +hist_init(GimpInk2 * ink, GimpCoords* coords) +{ + ink->hist_index = 0; + ink->hist_count = 0; + if (coords) + hist_add(ink, coords, 0); +} + +#define HIST_IGNORE_THRESHOULD 0.0001 + +static void +hist_add(GimpInk2 *ink, GimpCoords* coords, gdouble speed) +{ + gdouble dist = 0; + if (coords) { + if (ink->hist_count > 0) { + gint prev_index = (ink->hist_index + INK2_HISTORY_BUFFER - 1) % INK2_HISTORY_BUFFER; + gdouble dist_x = coords->x - ink->hist_buffer[prev_index].x; + gdouble dist_y = coords->y - ink->hist_buffer[prev_index].y; + dist = sqrt(dist_x * dist_x + dist_y * dist_y); + if (dist < HIST_IGNORE_THRESHOULD) + return; + } + ink->hist_buffer[ink->hist_index] = *coords; + ink->hist_dist_buffer[ink->hist_index] = speed; + ink->hist_index ++; + + if (ink->hist_count < INK2_HISTORY_BUFFER) + ink->hist_count ++; + + if (ink->hist_index == INK2_HISTORY_BUFFER) + ink->hist_index = 0; + } +} + +static GimpCoords +hist_result(GimpInk2 *ink, GimpInk2Options* options) +{ + gint i; + GimpCoords result; + result.x = result.y = 0.0; + gdouble scale_sum = 0.0; + if (ink->hist_count > 0) { + gint max_hist_count = MIN(ink->hist_count , options->compensation_hist_size); + gint cur_index = (ink->hist_index + INK2_HISTORY_BUFFER - 1) % INK2_HISTORY_BUFFER; + + gdouble gaussian_weight = 0.0; + gdouble gaussian_weight2 = options->compensation_rate_temperature * options->compensation_rate_temperature; + gdouble velocity_sum = 0.0; + if (gaussian_weight2 != 0.0) + gaussian_weight = 1 / (sqrt(2 * PI) * options->compensation_rate_temperature); + + for (i = 0; i < max_hist_count; i ++, cur_index --) + { + gdouble rate = 0; + if (cur_index == -1) + cur_index = INK2_HISTORY_BUFFER - 1; + + if (gaussian_weight2 != 0) + { + /* We use gaussian function with velocity as a window function */ + velocity_sum += ink->hist_dist_buffer[cur_index]; + rate = gaussian_weight * exp(-velocity_sum*velocity_sum / (2*gaussian_weight2)); + /* If i == 0 && rate == 0.0, resulting value becomes zero. + * To avoid this, we treat this as a special case. + */ + if (i == 0 && rate == 0.0) + rate = 1.0; + } + else + { + rate = (i == 0) ? 1.0: 0.0; + } + scale_sum += rate; + result.x += rate * ink->hist_buffer[cur_index].x; + result.y += rate * ink->hist_buffer[cur_index].y; + } + + if (scale_sum != 0.0) + { + result.x /= scale_sum; + result.y /= scale_sum; + } + } + return result; +} + +/**************************************************************/ + +/*********************************/ +/* Rendering functions */ +/*********************************/ + +/* Some of this stuff should probably be combined with the + * code it was copied from in paint_core.c; but I wanted + * to learn this stuff, so I've kept it simple. + * + * The following only supports CONSTANT mode. Incremental + * would, I think, interact strangely with the way we + * do things. But it wouldn't be hard to implement at all. + */ + +enum { ROW_START, ROW_STOP }; + +/* The insertion sort here, for SUBSAMPLE = 8, tends to beat out + * qsort() by 4x with CFLAGS=-O2, 2x with CFLAGS=-g + */ +static void +insert_sort (gint *data, + gint n) +{ + gint i, j, k; + gint tmp1, tmp2; + + for (i = 2; i < 2 * n; i += 2) + { + tmp1 = data[i]; + tmp2 = data[i + 1]; + j = 0; + while (data[j] < tmp1) + j += 2; + + for (k = i; k > j; k -= 2) + { + data[k] = data[k - 2]; + data[k + 1] = data[k - 1]; + } + + data[j] = tmp1; + data[j + 1] = tmp2; + } +} + +static void +fill_run (guchar *dest, + guchar alpha, + gint w) +{ + if (alpha == 255) + { + memset (dest, 255, w); + } + else + { + while (w--) + { + *dest = MAX (*dest, alpha); + dest++; + } + } +} + +static void +render_blob_line (Blob *blob, + guchar *dest, + gint x, + gint y, + gint width) +{ + gint buf[4 * SUBSAMPLE]; + gint *data = buf; + gint n = 0; + gint i, j; + gint current = 0; /* number of filled rows at this point + * in the scan line + */ + gint last_x; + + /* Sort start and ends for all lines */ + + j = y * SUBSAMPLE - blob->y; + for (i = 0; i < SUBSAMPLE; i++) + { + if (j >= blob->height) + break; + + if ((j > 0) && (blob->data[j].left <= blob->data[j].right)) + { + data[2 * n] = blob->data[j].left; + data[2 * n + 1] = ROW_START; + data[2 * SUBSAMPLE + 2 * n] = blob->data[j].right; + data[2 * SUBSAMPLE + 2 * n + 1] = ROW_STOP; + n++; + } + j++; + } + + /* If we have less than SUBSAMPLE rows, compress */ + if (n < SUBSAMPLE) + { + for (i = 0; i < 2 * n; i++) + data[2 * n + i] = data[2 * SUBSAMPLE + i]; + } + + /* Now count start and end separately */ + n *= 2; + + insert_sort (data, n); + + /* Discard portions outside of tile */ + + while ((n > 0) && (data[0] < SUBSAMPLE*x)) + { + if (data[1] == ROW_START) + current++; + else + current--; + data += 2; + n--; + } + + while ((n > 0) && (data[2*(n-1)] >= SUBSAMPLE*(x+width))) + n--; + + /* Render the row */ + + last_x = 0; + for (i = 0; i < n;) + { + gint cur_x = data[2 * i] / SUBSAMPLE - x; + gint pixel; + + /* Fill in portion leading up to this pixel */ + if (current && cur_x != last_x) + fill_run (dest + last_x, (255 * current) / SUBSAMPLE, cur_x - last_x); + + /* Compute the value for this pixel */ + pixel = current * SUBSAMPLE; + + while (ih; + s = dest->data; + + for (i=0; ix, dest->y + i, dest->w); + s += dest->rowstride; + } + } +} diff -uNr gimp-2.4.1/app/paint/gimpink2.h gimp-2.4.1-work/app/paint/gimpink2.h --- gimp-2.4.1/app/paint/gimpink2.h 1970-01-01 09:00:00.000000000 +0900 +++ gimp-2.4.1-work/app/paint/gimpink2.h 2007-11-04 19:40:41.000000000 +0900 @@ -0,0 +1,83 @@ +/* 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_INK2_H__ +#define __GIMP_INK2_H__ + + +#include "gimppaintcore.h" +#include "gimpink-blob.h" + + +#define INK2_DIST_SMOOTHER_BUFFER 10 +#define INK2_TIME_SMOOTHER_BUFFER 10 +#define INK2_HISTORY_BUFFER 20 + + +#define GIMP_TYPE_INK2 (gimp_ink2_get_type ()) +#define GIMP_INK2(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_INK2, GimpInk2)) +#define GIMP_INK2_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_INK2, GimpInk2Class)) +#define GIMP_IS_INK2(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_INK2)) +#define GIMP_IS_INK2_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_INK2)) +#define GIMP_INK2_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_INK2, GimpInk2Class)) + + +typedef struct _GimpInk2Class GimpInk2Class; + +struct _GimpInk2 +{ + GimpPaintCore parent_instance; + + Blob *start_blob; /* starting blob (for undo) */ + + Blob *cur_blob; /* current blob */ + Blob *last_blob; /* blob for last cursor position */ + + /* circular distance history buffer */ + gdouble dt_buffer[INK2_DIST_SMOOTHER_BUFFER]; + gint dt_index; + + /* circular timing history buffer */ + guint32 ts_buffer[INK2_TIME_SMOOTHER_BUFFER]; + gint ts_index; + + GimpCoords hist_buffer[INK2_HISTORY_BUFFER]; + gdouble hist_dist_buffer[INK2_HISTORY_BUFFER]; + gint hist_index; + gint hist_count; + + guint32 last_time; /* previous time of a motion event */ + + GimpCoords last_point; /* last compensated position */ + + gboolean init_velocity; +}; + +struct _GimpInk2Class +{ + GimpPaintCoreClass parent_class; +}; + + +void gimp_ink2_register (Gimp *gimp, + GimpPaintRegisterCallback callback); + +GType gimp_ink2_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_INK2_H__ */ diff -uNr gimp-2.4.1/app/paint/gimpink2options.c gimp-2.4.1-work/app/paint/gimpink2options.c --- gimp-2.4.1/app/paint/gimpink2options.c 1970-01-01 09:00:00.000000000 +0900 +++ gimp-2.4.1-work/app/paint/gimpink2options.c 2007-11-04 19:40:41.000000000 +0900 @@ -0,0 +1,225 @@ +/* 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 "libgimpconfig/gimpconfig.h" + +#include "paint-types.h" + +#include "core/gimp.h" +#include "core/gimpdrawable.h" +#include "core/gimppaintinfo.h" + +#include "gimpink2.h" +#include "gimpink2options.h" +#include "gimpink-blob.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_SIZE, + PROP_TILT_ANGLE, + PROP_SIZE_SENSITIVITY, + PROP_VEL_SENSITIVITY, + PROP_TILT_SENSITIVITY, + PROP_BLOB_TYPE, + PROP_BLOB_ASPECT, + PROP_BLOB_ANGLE, + PROP_COMPENSATION_HIST_SIZE, + PROP_COMPENSATE_AT_LAST, + PROP_COMPENSATION_RATE_TEMPERATURE +}; + + +static void gimp_ink2_options_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_ink2_options_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + + +G_DEFINE_TYPE (GimpInk2Options, gimp_ink2_options, GIMP_TYPE_PAINT_OPTIONS) + + +static void +gimp_ink2_options_class_init (GimpInk2OptionsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = gimp_ink2_options_set_property; + object_class->get_property = gimp_ink2_options_get_property; + + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_SIZE, + "size", NULL, + 0.0, 200.0, 16.0, + GIMP_PARAM_STATIC_STRINGS); + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_TILT_ANGLE, + "tilt-angle", NULL, + -90.0, 90.0, 0.0, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_SIZE_SENSITIVITY, + "size-sensitivity", NULL, + 0.0, 1.0, 1.0, + GIMP_PARAM_STATIC_STRINGS); + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_VEL_SENSITIVITY, + "vel-sensitivity", NULL, + 0.0, 1.0, 0.8, + GIMP_PARAM_STATIC_STRINGS); + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_TILT_SENSITIVITY, + "tilt-sensitivity", NULL, + 0.0, 1.0, 0.4, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_BLOB_TYPE, + "blob-type", NULL, + GIMP_TYPE_INK_BLOB_TYPE, + GIMP_INK_BLOB_TYPE_ELLIPSE, + GIMP_PARAM_STATIC_STRINGS); + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_BLOB_ASPECT, + "blob-aspect", NULL, + 1.0, 10.0, 1.0, + GIMP_PARAM_STATIC_STRINGS); + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_BLOB_ANGLE, + "blob-angle", NULL, + -90.0, 90.0, 0.0, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_COMPENSATION_HIST_SIZE, + "compensation-history-size", NULL, + 1, INK2_HISTORY_BUFFER, MIN(20, INK2_HISTORY_BUFFER), 0); + GIMP_CONFIG_INSTALL_PROP_BOOLEAN(object_class, PROP_COMPENSATE_AT_LAST, + "compensate-at-last", NULL, + FALSE, 0); + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_COMPENSATION_RATE_TEMPERATURE, + "compensation-rate-temperature", NULL, + 0.0, 1000, 25, + 0); +} + +static void +gimp_ink2_options_init (GimpInk2Options *options) +{ +} + +static void +gimp_ink2_options_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpInk2Options *options = GIMP_INK2_OPTIONS (object); + + switch (property_id) + { + case PROP_SIZE: + options->size = g_value_get_double (value); + break; + case PROP_TILT_ANGLE: + options->tilt_angle = g_value_get_double (value); + break; + case PROP_SIZE_SENSITIVITY: + options->size_sensitivity = g_value_get_double (value); + break; + case PROP_VEL_SENSITIVITY: + options->vel_sensitivity = g_value_get_double (value); + break; + case PROP_TILT_SENSITIVITY: + options->tilt_sensitivity = g_value_get_double (value); + break; + case PROP_BLOB_TYPE: + options->blob_type = g_value_get_enum (value); + break; + case PROP_BLOB_ASPECT: + options->blob_aspect = g_value_get_double (value); + break; + case PROP_BLOB_ANGLE: + options->blob_angle = g_value_get_double (value); + break; + case PROP_COMPENSATION_HIST_SIZE: + options->compensation_hist_size = g_value_get_int (value); + break; + case PROP_COMPENSATE_AT_LAST: + options->compensate_at_last = g_value_get_boolean (value); + break; + case PROP_COMPENSATION_RATE_TEMPERATURE: + options->compensation_rate_temperature = g_value_get_double (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_ink2_options_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpInk2Options *options = GIMP_INK2_OPTIONS (object); + + switch (property_id) + { + case PROP_SIZE: + g_value_set_double (value, options->size); + break; + case PROP_TILT_ANGLE: + g_value_set_double (value, options->tilt_angle); + break; + case PROP_SIZE_SENSITIVITY: + g_value_set_double (value, options->size_sensitivity); + break; + case PROP_VEL_SENSITIVITY: + g_value_set_double (value, options->vel_sensitivity); + break; + case PROP_TILT_SENSITIVITY: + g_value_set_double (value, options->tilt_sensitivity); + break; + case PROP_BLOB_TYPE: + g_value_set_enum (value, options->blob_type); + break; + case PROP_BLOB_ASPECT: + g_value_set_double (value, options->blob_aspect); + break; + case PROP_BLOB_ANGLE: + g_value_set_double (value, options->blob_angle); + break; + case PROP_COMPENSATION_HIST_SIZE: + g_value_set_int (value, options->compensation_hist_size); + break; + case PROP_COMPENSATE_AT_LAST: + g_value_set_boolean (value, options->compensate_at_last); + break; + case PROP_COMPENSATION_RATE_TEMPERATURE: + g_value_set_double (value, options->compensation_rate_temperature); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} diff -uNr gimp-2.4.1/app/paint/gimpink2options.h gimp-2.4.1-work/app/paint/gimpink2options.h --- gimp-2.4.1/app/paint/gimpink2options.h 1970-01-01 09:00:00.000000000 +0900 +++ gimp-2.4.1-work/app/paint/gimpink2options.h 2007-11-04 19:40:41.000000000 +0900 @@ -0,0 +1,65 @@ +/* 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_INK2_OPTIONS_H__ +#define __GIMP_INK2_OPTIONS_H__ + + +#include "gimppaintoptions.h" + + +#define GIMP_TYPE_INK2_OPTIONS (gimp_ink2_options_get_type ()) +#define GIMP_INK2_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_INK2_OPTIONS, GimpInk2Options)) +#define GIMP_INK2_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_INK2_OPTIONS, GimpInk2OptionsClass)) +#define GIMP_IS_INK2_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_INK2_OPTIONS)) +#define GIMP_IS_INK2_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_INK2_OPTIONS)) +#define GIMP_INK2_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_INK2_OPTIONS, GimpInk2OptionsClass)) + + +typedef struct _GimpInk2OptionsClass GimpInk2OptionsClass; + +struct _GimpInk2Options +{ + GimpPaintOptions parent_instance; + + gdouble size; + gdouble tilt_angle; + + gdouble size_sensitivity; + gdouble vel_sensitivity; + gdouble tilt_sensitivity; + + GimpInkBlobType blob_type; + gdouble blob_aspect; + gdouble blob_angle; + + gint compensation_hist_size; + gboolean compensate_at_last; + gdouble compensation_rate_temperature; +}; + +struct _GimpInk2OptionsClass +{ + GimpPaintOptionsClass parent_instance; +}; + + +GType gimp_ink2_options_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_INK2_OPTIONS_H__ */ diff -uNr gimp-2.4.1/app/paint/gimpink2undo.c gimp-2.4.1-work/app/paint/gimpink2undo.c --- gimp-2.4.1/app/paint/gimpink2undo.c 1970-01-01 09:00:00.000000000 +0900 +++ gimp-2.4.1-work/app/paint/gimpink2undo.c 2007-11-04 19:40:41.000000000 +0900 @@ -0,0 +1,169 @@ +/* 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 "paint-types.h" + +#include "gimpink2.h" +#include "gimpink-blob.h" +#include "gimpink2undo.h" + + +static GObject * gimp_ink2_undo_constructor (GType type, + guint n_params, + GObjectConstructParam *params); + +static void gimp_ink2_undo_pop (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum); +static void gimp_ink2_undo_free (GimpUndo *undo, + GimpUndoMode undo_mode); + + +G_DEFINE_TYPE (GimpInk2Undo, gimp_ink2_undo, GIMP_TYPE_PAINT_CORE_UNDO) + +#define parent_class gimp_ink2_undo_parent_class + + +static void +gimp_ink2_undo_class_init (GimpInk2UndoClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpUndoClass *undo_class = GIMP_UNDO_CLASS (klass); + + object_class->constructor = gimp_ink2_undo_constructor; + + undo_class->pop = gimp_ink2_undo_pop; + undo_class->free = gimp_ink2_undo_free; +} + +static void +gimp_ink2_undo_init (GimpInk2Undo *undo) +{ +} + +static GObject * +gimp_ink2_undo_constructor (GType type, + guint n_params, + GObjectConstructParam *params) +{ + GObject *object; + GimpInk2Undo *ink_undo; + GimpInk2 *ink; + + object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params); + + ink_undo = GIMP_INK2_UNDO (object); + + g_assert (GIMP_IS_INK2 (GIMP_PAINT_CORE_UNDO (ink_undo)->paint_core)); + + ink = GIMP_INK2 (GIMP_PAINT_CORE_UNDO (ink_undo)->paint_core); + + if (ink->start_blob) + ink_undo->last_blob = blob_duplicate (ink->start_blob); + + memcpy (ink_undo->dt_buffer, ink->dt_buffer, + sizeof (ink_undo->dt_buffer)); + + ink_undo->dt_index = ink->dt_index; + + memcpy (ink_undo->ts_buffer, ink->ts_buffer, + sizeof (ink_undo->ts_buffer)); + + ink_undo->ts_index = ink->ts_index; + + ink_undo->last_time = ink->last_time; + + ink_undo->init_velocity = ink->init_velocity; + + return object; +} + +static void +gimp_ink2_undo_pop (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum) +{ + GimpInk2Undo *ink_undo = GIMP_INK2_UNDO (undo); + + GIMP_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum); + + if (GIMP_PAINT_CORE_UNDO (ink_undo)->paint_core) + { + GimpInk2 *ink = GIMP_INK2 (GIMP_PAINT_CORE_UNDO (ink_undo)->paint_core); + Blob *tmp_blob; + gint tmp_int; + gdouble tmp_double; + guint32 tmp_int_buf[INK2_DIST_SMOOTHER_BUFFER]; + gdouble tmp_double_buf[INK2_DIST_SMOOTHER_BUFFER]; + + tmp_blob = ink->last_blob; + ink->last_blob = ink_undo->last_blob; + ink_undo->last_blob = tmp_blob; + + memcpy (tmp_double_buf, ink->dt_buffer, + sizeof (tmp_double_buf)); + memcpy (ink->dt_buffer, ink_undo->dt_buffer, + sizeof (tmp_double_buf)); + memcpy (ink_undo->dt_buffer, tmp_double_buf, + sizeof (tmp_double_buf)); + + tmp_int = ink->dt_index; + ink->dt_index = ink_undo->dt_index; + ink_undo->dt_index = tmp_int; + + memcpy (tmp_int_buf, ink->ts_buffer, + sizeof (tmp_int_buf)); + memcpy (ink->ts_buffer, ink_undo->ts_buffer, + sizeof (tmp_int_buf)); + memcpy (ink_undo->ts_buffer, tmp_int_buf, + sizeof (tmp_int_buf)); + + tmp_int = ink->ts_index; + ink->ts_index = ink_undo->ts_index; + ink_undo->ts_index = tmp_int; + + tmp_double = ink->last_time; + ink->last_time = ink_undo->last_time; + ink_undo->last_time = tmp_double; + + tmp_int = ink->init_velocity; + ink->init_velocity = ink_undo->init_velocity; + ink_undo->init_velocity = tmp_int; + } +} + +static void +gimp_ink2_undo_free (GimpUndo *undo, + GimpUndoMode undo_mode) +{ + GimpInk2Undo *ink_undo = GIMP_INK2_UNDO (undo); + + if (ink_undo->last_blob) + { + g_free (ink_undo->last_blob); + ink_undo->last_blob = NULL; + } + + GIMP_UNDO_CLASS (parent_class)->free (undo, undo_mode); +} diff -uNr gimp-2.4.1/app/paint/gimpink2undo.h gimp-2.4.1-work/app/paint/gimpink2undo.h --- gimp-2.4.1/app/paint/gimpink2undo.h 1970-01-01 09:00:00.000000000 +0900 +++ gimp-2.4.1-work/app/paint/gimpink2undo.h 2007-11-04 19:40:41.000000000 +0900 @@ -0,0 +1,63 @@ +/* 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_INK2_UNDO_H__ +#define __GIMP_INK2_UNDO_H__ + + +#include "gimppaintcoreundo.h" +#include "gimpink2.h" + + +#define GIMP_TYPE_INK2_UNDO (gimp_ink2_undo_get_type ()) +#define GIMP_INK2_UNDO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_INK2_UNDO, GimpInk2Undo)) +#define GIMP_INK2_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_INK2_UNDO, GimpInk2UndoClass)) +#define GIMP_IS_INK2_UNDO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_INK2_UNDO)) +#define GIMP_IS_INK2_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_INK2_UNDO)) +#define GIMP_INK2_UNDO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_INK2_UNDO, GimpInk2UndoClass)) + + +typedef struct _GimpInk2UndoClass GimpInk2UndoClass; + +struct _GimpInk2Undo +{ + GimpPaintCoreUndo parent_instance; + + Blob *last_blob; + + gdouble dt_buffer[INK2_DIST_SMOOTHER_BUFFER]; + gint dt_index; + + guint32 ts_buffer[INK2_TIME_SMOOTHER_BUFFER]; + gint ts_index; + + gdouble last_time; + + gboolean init_velocity; +}; + +struct _GimpInk2UndoClass +{ + GimpPaintCoreUndoClass parent_class; +}; + + +GType gimp_ink2_undo_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_INK2_UNDO_H__ */ diff -uNr gimp-2.4.1/app/paint/gimpmixbrush.c gimp-2.4.1-work/app/paint/gimpmixbrush.c --- gimp-2.4.1/app/paint/gimpmixbrush.c 1970-01-01 09:00:00.000000000 +0900 +++ gimp-2.4.1-work/app/paint/gimpmixbrush.c 2008-01-15 10:54:36.000000000 +0900 @@ -0,0 +1,784 @@ +/* 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 "libgimpcolor/gimpcolor.h" +#include "libgimpmath/gimpmath.h" +#include "libgimpbase/gimpbase.h" + +#include "paint-types.h" + +#include "base/temp-buf.h" + +#include "paint-funcs/paint-funcs.h" + +#include "core/gimp.h" +#include "core/gimpbrush.h" +#include "core/gimpdrawable.h" +#include "core/gimplayer.h" +#include "core/gimpgradient.h" +#include "core/gimpimage.h" +#include "core/gimppickable.h" +#include "core/gimpprojection.h" +#include "base/pixel-region.h" + +#include "gimpmixbrush.h" +#include "gimpmixbrushoptions.h" + +#include "gimp-intl.h" + + +/* Debug option */ +//#define GIMP_MIXBRUSH_DEBUG_MIXING + + + + +/* Coords history */ + +static void gimp_mixbrush_finalize (GObject *object); + +static void gimp_mixbrush_start (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *paint_options); +#if 0 +static void gimp_mixbrush_finish (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *paint_options); +#endif + +static void gimp_mixbrush_paint (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *paint_options, + GimpPaintState paint_state, + guint32 time); + +static void gimp_mixbrush_motion (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *paint_options); + +static inline gboolean +mixbrush_get_image_color_at (GimpImage *image, + GimpDrawable *drawable, + GimpMixbrushOptions *mixbrush_options, + gint x, + gint y, + GimpRGB *color_at_pos); + +static inline void +gimp_mixbrush_paste_canvas (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *paint_options, + gdouble opacity); + +static gboolean +blend_colors (GimpRGB *dest, + int num_colors, + ...); + + +G_DEFINE_TYPE (GimpMixbrush, gimp_mixbrush, GIMP_TYPE_PAINTBRUSH) + +#define parent_class gimp_mixbrush_parent_class + + +void +gimp_mixbrush_register (Gimp *gimp, + GimpPaintRegisterCallback callback) +{ + (* callback) (gimp, + GIMP_TYPE_MIXBRUSH, + GIMP_TYPE_MIXBRUSH_OPTIONS, + "gimp-mixbrush", + _("Mixbrush"), + "gimp-tool-mixbrush"); +} + +static void +gimp_mixbrush_class_init (GimpMixbrushClass *klass) +{ + GimpPaintCoreClass *paint_core_class = GIMP_PAINT_CORE_CLASS (klass); + GimpBrushCoreClass *brush_core_class = GIMP_BRUSH_CORE_CLASS (klass); + + paint_core_class->paint = gimp_mixbrush_paint; + G_OBJECT_CLASS (klass)->finalize = gimp_mixbrush_finalize; + + brush_core_class->handles_changing_brush = TRUE; +} + +static void +gimp_mixbrush_init (GimpMixbrush *mixbrush) +{ +} + + +static void +gimp_mixbrush_finalize (GObject *object) +{ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + + +/* [Memo] + * paint_history_* functions should be moved into GimpPaintCore in the future + * because G-pen patch can share the code. + */ +static inline void +paint_history_init (GimpPaintCore *paint_core) +{ + GimpMixbrush *mixbrush = GIMP_MIXBRUSH(paint_core); + mixbrush->history_head = mixbrush->history_tail = 0; +} + + +static inline gint +paint_history_get_length (GimpPaintCore *paint_core) +{ + GimpMixbrush *mixbrush = GIMP_MIXBRUSH(paint_core); + return (mixbrush->history_tail > (GIMP_MIXBRUSH_MAX_HISTORY + 1) )? + GIMP_MIXBRUSH_MAX_HISTORY + 1 : + mixbrush->history_tail; +} + + +static inline void +paint_history_add (GimpPaintCore *paint_core, + GimpCoords *cur_coords, + GimpCoords *last_coords, // same as cur_coords of last item? + gdouble pixel_dist, + GimpRGB *color) +{ + GimpMixbrush *mixbrush = GIMP_MIXBRUSH(paint_core); + gint index; + + index = (mixbrush->history_tail ++) % (GIMP_MIXBRUSH_MAX_HISTORY + 1); + mixbrush->history[index].cur_coords = *cur_coords; + mixbrush->history[index].last_coords = *last_coords; + mixbrush->history[index].pixel_dist = pixel_dist; + mixbrush->history[index].color = *color; +} + + +static inline GimpMixbrushCoordsHistory* +paint_history_peek_stack_at (GimpPaintCore *paint_core, + gint stack_index) +{ + GimpMixbrush *mixbrush = GIMP_MIXBRUSH(paint_core); + gint index = (mixbrush->history_tail - stack_index - 1); + return (index < 0)? + NULL : + &mixbrush->history[index % (GIMP_MIXBRUSH_MAX_HISTORY + 1)]; +} + + +static void +gimp_mixbrush_paint (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *paint_options, + GimpPaintState paint_state, + guint32 time) +{ + switch (paint_state) + { + case GIMP_PAINT_STATE_INIT: + gimp_mixbrush_start (paint_core, drawable, paint_options); + GIMP_PAINT_CORE_CLASS (parent_class)->paint (paint_core, drawable, + paint_options, + paint_state, time); + break; + + case GIMP_PAINT_STATE_MOTION: + gimp_mixbrush_motion (paint_core, drawable, paint_options); + break; + + case GIMP_PAINT_STATE_FINISH: + GIMP_PAINT_CORE_CLASS (parent_class)->paint (paint_core, drawable, + paint_options, + paint_state, time); + break; + + default: + break; + } +} + + +static void +gimp_mixbrush_start (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *paint_options) +{ + GimpContext *context = GIMP_CONTEXT (paint_options); + GimpImage *image; + guchar color[MAX_CHANNELS]; + GimpRGB *next_color = &GIMP_MIXBRUSH(paint_core)->next_color; + GimpRGB *foreground_color = &GIMP_MIXBRUSH(paint_core)->foreground_color; + + image = gimp_item_get_image (GIMP_ITEM (drawable)); + gimp_image_get_foreground (image, context, + gimp_drawable_type (drawable), + color); + + color[ALPHA_PIX] = OPAQUE_OPACITY; + gimp_rgba_set_uchar(next_color, color[0], color[1], color[2], color[3]); + *foreground_color = *next_color; + + GIMP_MIXBRUSH(paint_core)->current_orig_color_rate = + GIMP_MIXBRUSH_OPTIONS (paint_options)->original_color_rate; + + paint_history_init(paint_core); +} + + +static void +gimp_mixbrush_motion (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *paint_options) +{ + GimpImage *image; + GimpMixbrushOptions *mixbrush_options = GIMP_MIXBRUSH_OPTIONS (paint_options); + + image = gimp_item_get_image (GIMP_ITEM (drawable)); + + if (mixbrush_options->delay > 0) { + GimpRGB color_at_pos; + if (mixbrush_get_image_color_at(image, drawable, + mixbrush_options, + (gint)paint_core->cur_coords.x, + (gint)paint_core->cur_coords.y, + &color_at_pos)) + { + paint_history_add(paint_core, + &paint_core->cur_coords, + &paint_core->last_coords, + paint_core->pixel_dist, + &color_at_pos); + } + } + if (mixbrush_options->delay == 0 || + paint_history_get_length(paint_core) > mixbrush_options->delay) + gimp_mixbrush_paste_canvas (paint_core, drawable, + paint_options, GIMP_OPACITY_OPAQUE); +} + + +/* Pick up color from Canvas or Projection */ +static inline gboolean +mixbrush_get_image_color_at (GimpImage *image, + GimpDrawable *drawable, + GimpMixbrushOptions *mixbrush_options, + gint x, + gint y, + GimpRGB *color_at_pos) +{ + GimpPickable *pickable; + + x = CLAMP (x, 0, gimp_item_width (GIMP_ITEM (drawable)) - 1); + y = CLAMP (y, 0, gimp_item_height (GIMP_ITEM (drawable)) - 1); + + if (mixbrush_options->merged) + { + gint item_offset_x, item_offset_y; + gimp_item_offsets (GIMP_ITEM (drawable), &item_offset_x, &item_offset_y); + x += item_offset_x; + y += item_offset_y; + + pickable = GIMP_PICKABLE (image->projection); + // g_print ("pickable=%x\n", pickable); + gimp_pickable_flush (pickable); + } + else + pickable = GIMP_PICKABLE (drawable); + + /* Pickup color from current drawable */ + if (!gimp_pickable_get_color_at (pickable, + x, y, color_at_pos)) + { + g_print ("Failed: pick up color\n"); + return FALSE; + } + return TRUE; +} + + +/* + * Pickup color from Canvas or Projection, and + * merge the color with delayed and hidden color. + */ +static inline gboolean +mixbrush_get_mixed_image_color_at (GimpMixbrush* mixbrush, + GimpImage* image, + GimpContext* context, + GimpDrawable* drawable, + GimpMixbrushOptions* mixbrush_options, + GimpRGB* delayed_color, + gint x, gint y, + GimpRGB* result) +{ + gboolean use_hidden_color = FALSE; + guchar hidden_color_uchar[MAX_CHANNELS]; + GimpRGB color_at_pos; + GimpRGB hidden_color; + + /* Pickup color from current drawable */ + if (!mixbrush_get_image_color_at (image, drawable, + mixbrush_options, + x, y, &color_at_pos)) + { + g_print ("Failed: pick up color\n"); + return FALSE; + } + +#ifdef GIMP_MIXBRUSH_DEBUG_MIXING + g_print ("Pickup(raw ):%lf,%lf,%lf,%lf|%d\n", + color_at_pos.r, + color_at_pos.g, + color_at_pos.b, + color_at_pos.a, + OPAQUE_OPACITY); +#endif + + /* Merge picked-up color with the delayed color */ + if (mixbrush_options->delayed_color_rate > 0.0 && + mixbrush_options->delay > 0 && + delayed_color) + { + color_at_pos.r = + mixbrush_options->delayed_color_rate * delayed_color->r + + (1 - mixbrush_options->delayed_color_rate) * color_at_pos.r; + color_at_pos.g = + mixbrush_options->delayed_color_rate * delayed_color->g + + (1 - mixbrush_options->delayed_color_rate) * color_at_pos.g; + color_at_pos.b = + mixbrush_options->delayed_color_rate * delayed_color->b + + (1 - mixbrush_options->delayed_color_rate) * color_at_pos.b; + color_at_pos.a = + mixbrush_options->delayed_color_rate * delayed_color->a + + (1 - mixbrush_options->delayed_color_rate) * color_at_pos.a; +#ifdef GIMP_MIXBRUSH_DEBUG_MIXING + g_print ("Delayed Color:%lf,%lf,%lf,%lf\n", + delayed_color->r, + delayed_color->g, + delayed_color->b, + delayed_color->a); +#endif + } +#ifdef GIMP_MIXBRUSH_DEBUG_MIXING + g_print ("Pickup(+delay):%lf,%lf,%lf,%lf\n", + color_at_pos.r, + color_at_pos.g, + color_at_pos.b, + color_at_pos.a); +#endif + + + switch (mixbrush_options->hidden_color) + { + case GIMP_HIDDEN_COLOR_BACKGROUND: + /* pickup hidden color from current background color */ + gimp_image_get_background (image, context, + gimp_drawable_type (drawable), + hidden_color_uchar); + hidden_color_uchar[ALPHA_PIX] = OPAQUE_OPACITY; + use_hidden_color = TRUE; + break; + + case GIMP_HIDDEN_COLOR_WHITE: + /* select white as a hidden color */ + hidden_color_uchar[0] = + hidden_color_uchar[1] = + hidden_color_uchar[2] = + hidden_color_uchar[3] = OPAQUE_OPACITY; + use_hidden_color = TRUE; + break; + + default: + break; + } + + if (use_hidden_color) + { + gdouble a; + gimp_rgba_set_uchar(&hidden_color, + hidden_color_uchar[0], + hidden_color_uchar[1], + hidden_color_uchar[2], + hidden_color_uchar[3]); + a = color_at_pos.a; + result->r = color_at_pos.r * a + (1 - a) * hidden_color.r; + result->g = color_at_pos.g * a + (1 - a) * hidden_color.g; + result->b = color_at_pos.b * a + (1 - a) * hidden_color.b; + result->a = 1.0; +#ifdef GIMP_MIXBRUSH_DEBUG_MIXING + g_print ("Hidden Color:%lf,%lf,%lf,%lf\n", + hidden_color.r, + hidden_color.g, + hidden_color.b, + hidden_color.a); +#endif + } + else + { + *result = color_at_pos; + } + +#ifdef GIMP_MIXBRUSH_DEBUG_MIXNIG + g_print ("Pickup(final ):%lf,%lf,%lf,%lf\n", + result->r, + result->g, + result->b, + result->a); +#endif + + return TRUE; +} + + +static gint +mixbrush_prepare_maskPR_for_brush (GimpBrushCorePasteCanvasInfo *info, + GimpBrushCore *core, + GimpDrawable *drawable) +{ + GimpMixbrush *mixbrush = GIMP_MIXBRUSH (core); + TempBuf *area = info->gimp_brush_area; + guchar color[MAX_CHANNELS]; + + gimp_rgba_get_uchar(&mixbrush->next_color, + &color[0], &color[1], &color[2], &color[3]); + + color_pixels (temp_buf_data (area), color, + area->width * area->height, + area->bytes); + return 0; +} + + +static gint +mixbrush_paste_canvas_paint(GimpBrushCorePasteCanvasInfo *info, + GimpBrushCore *core, + GimpDrawable *drawable, + PixelRegion *canvasPR, + PixelRegion *maskPR) +{ + GimpMixbrush *mixbrush = GIMP_MIXBRUSH (core); + GimpPaintCore *paintcore = GIMP_PAINT_CORE (core); + + TempBuf *area = info->gimp_brush_area; + gdouble paint_opacity = *(gdouble*)info->user_data; + + PixelRegion canvasPR1; + PixelRegion srcPR1; + + guchar color[MAX_CHANNELS]; + gimp_rgba_get_uchar(&mixbrush->next_color, + &color[0], &color[1], &color[2], &color[3]); + + /* srcPR will be the pixels under the current painthit from the drawable */ + pixel_region_init (&srcPR1, gimp_drawable_get_tiles (drawable), + area->x, area->y, area->width, area->height, FALSE); + + canvasPR1 = *canvasPR; + + /* + * New pixel is: + * P = brush * image_opacity * brush_opacity * paint_opacity + + * src * (image_opacity) * (1 - paint_opacity) + + * src * (1 - image_opacity) + * = image_opacity * + * ((brush * brush_opacity) * paint_opacity + (1-paint_opacity) * src) + + * (1-image_opacity) * src + * = replace( src, shade( src, brush with opacity, paint_opacity), image_opacity) + */ + shade_region(&srcPR1, &canvasPR1, color, CLAMP(paint_opacity * 255.0, 0, 255)); + + return 0; +} + +static gint +mixbrush_paste_canvas_apply(GimpBrushCorePasteCanvasInfo *info, + GimpBrushCore *core, + GimpDrawable *drawable, + PixelRegion *srcPR, + PixelRegion *maskPR, + TileManager *undo_tiles) +{ + GimpPaintCore *paintcore = GIMP_PAINT_CORE (core); + gdouble paint_opacity = *(gdouble*)info->user_data; + + /* apply the paint area to the image */ + gimp_drawable_replace_region (drawable, srcPR, + FALSE, NULL, + info->image_opacity, + maskPR, + paintcore->canvas_buf->x, + paintcore->canvas_buf->y); + return 0; +} + +static void +mixbrush_paste_canvas_masks (GimpMixbrush *core, + GimpPaintOptions *paint_options, + GimpDrawable *drawable, + TempBuf *area, + gdouble paint_opacity, + gdouble image_opacity, + gdouble brush_opacity, + GimpLayerModeEffects paint_mode, + GimpBrushApplicationMode brush_hardness, + GimpPaintApplicationMode mode) +{ + GimpBrushCorePasteCanvasInfo brush_info; + GimpBrushCorePasteCanvasInfo* head_info = &brush_info; + + brush_info.gimp_brush_area = area; + brush_info.brush_opacity = brush_opacity; // [error]should be paint_opacity + brush_info.image_opacity = CLAMP (image_opacity, 0, 1); + brush_info.paint_mode = paint_mode; + brush_info.apply = TRUE; + brush_info.brush_hardness = brush_hardness; + brush_info.post_paint = NULL; + if (gimp_drawable_has_alpha(drawable)) + { + brush_info.pre_paint = NULL; + brush_info.apply_operation = mixbrush_paste_canvas_apply; + brush_info.paint_operation = mixbrush_paste_canvas_paint; + } + else + { + brush_info.pre_paint = mixbrush_prepare_maskPR_for_brush; + brush_info.apply_operation = NULL; + brush_info.paint_operation = NULL; + } + brush_info.user_data = &paint_opacity; // [error]should be brush_opacity + brush_info.next = NULL; + + gimp_brush_core_process_paste_canvas (GIMP_BRUSH_CORE(core), drawable, + head_info, + mode); +} + + +inline static void +gimp_mixbrush_paste_canvas (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *paint_options, + gdouble opacity) +{ + GimpMixbrush *mixbrush = GIMP_MIXBRUSH (paint_core); + GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_core); + GimpContext *context = GIMP_CONTEXT (paint_options); + GimpPressureOptions *pressure_options = paint_options->pressure_options; + GimpImage *image; + TempBuf *area; + GimpRGB *next_color = &mixbrush->next_color; + GimpMixbrushOptions *mixbrush_options = GIMP_MIXBRUSH_OPTIONS (paint_options); + GimpRGB *foreground_color = &mixbrush->foreground_color; + GimpRGB color_at_pos; + GimpPaintApplicationMode paint_appl_mode; + GimpMixbrushCoordsHistory *history = NULL; + GimpCoords orig_cur_coords = {0}; + GimpCoords orig_last_coords = {0}; + gdouble orig_pixel_dist = 0; + gdouble original_color_rate = mixbrush->current_orig_color_rate; + gdouble canvas_color_rate = mixbrush_options->canvas_color_rate; + + /* Overwrite cur_coords and last_coords if delay > 0 */ + if (mixbrush_options->delay > 0) { + history = + paint_history_peek_stack_at (paint_core, mixbrush_options->delay - 1); + orig_cur_coords = paint_core->cur_coords; + orig_last_coords = paint_core->last_coords; + orig_pixel_dist = paint_core->pixel_dist; + paint_core->cur_coords = history->cur_coords; + paint_core->last_coords = history->last_coords; + paint_core->pixel_dist = history->pixel_dist; + } + + image = gimp_item_get_image (GIMP_ITEM (drawable)); + + opacity *= gimp_paint_options_get_fade (paint_options, image, + paint_core->pixel_dist); + if (opacity == 0.0) + return; + + paint_appl_mode = paint_options->application_mode; + + area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options); + if (! area) + return; + + if (brush_core->brush && brush_core->brush->pixmap) + { + /* if it's a pixmap, do pixmap stuff */ + gimp_brush_core_color_area_with_pixmap (brush_core, drawable, + area, + gimp_paint_options_get_brush_mode (paint_options)); + + paint_appl_mode = GIMP_PAINT_INCREMENTAL; + } + else + { + /* Mix brush color with underlying canvas color */ + if (mixbrush_options->canvas_color_rate > 0.0) + { + /* Mix brush stroke color with foreground paint brush color */ + if (mixbrush->current_orig_color_rate > 0.0) + { + + if (mixbrush_options->original_color_pressure_rate > 0.0) + { + gdouble inv_pressure = + (mixbrush_options->invert_original_color_pressure)? + paint_core->cur_coords.pressure : + 1 - paint_core->cur_coords.pressure; + + original_color_rate -= mixbrush->current_orig_color_rate * + inv_pressure; + original_color_rate = CLAMP(original_color_rate, 0, 1.0); + } + } + + /* Mix brush color with underlying canvas color */ + if (mixbrush_get_mixed_image_color_at (mixbrush, + image, context, drawable, + mixbrush_options, + &history->color, + (gint) paint_core->cur_coords.x, + (gint) paint_core->cur_coords.y, + &color_at_pos)) + { + if (mixbrush_options->canvas_color_pressure_rate > 0.0) + { + gdouble inv_pressure = + (mixbrush_options->invert_canvas_color_pressure)? + paint_core->cur_coords.pressure : + 1 - paint_core->cur_coords.pressure; + + canvas_color_rate += + mixbrush_options->canvas_color_pressure_rate * + inv_pressure; + canvas_color_rate = CLAMP(canvas_color_rate, 0.0, 1.0); + } +#ifdef GIMP_MIXBRUSH_DEBUG_MIXING + g_print ("Brush:%lf,%lf,%lf,%lf\n", + next_color->r, + next_color->g, + next_color->b, + next_color->a); + g_print ("FGColor:%lf,%lf,%lf,%lf\n", + foreground_color->r, + foreground_color->g, + foreground_color->b, + foreground_color->a); + g_print ("Pos:%lf,%lf,%lf,%lf\n", + color_at_pos.r, + color_at_pos.g, + color_at_pos.b, + color_at_pos.a); +#endif + foreground_color->a = original_color_rate * (1 - canvas_color_rate); + color_at_pos.a *= canvas_color_rate; + next_color->a *= (1 - original_color_rate) * (1 - canvas_color_rate); + blend_colors(next_color, 2, &color_at_pos, foreground_color); +#ifdef GIMP_MIXBRUSH_DEBUG_MIXING + g_print ("Result:%lf,%lf,%lf,%lf\n", + next_color->r, + next_color->g, + next_color->b, + next_color->a); +#endif + } + } + + paint_appl_mode = GIMP_PAINT_INCREMENTAL; + } + + if (pressure_options->opacity) + opacity *= PRESSURE_SCALE * paint_core->cur_coords.pressure; + { + if (next_color->a > 0) + { + mixbrush_paste_canvas_masks (mixbrush, paint_options, + drawable, + area, + opacity, + gimp_context_get_opacity (context), + next_color->a, + gimp_context_get_paint_mode (context), + gimp_paint_options_get_brush_mode (paint_options), + paint_appl_mode); + } + } + + /* + * Restore original cur_coords and last_coords + * (But no need to restore ?) + */ + if (mixbrush_options->delay > 0) { + paint_core->cur_coords = orig_cur_coords; + paint_core->last_coords = orig_last_coords; + paint_core->pixel_dist = orig_pixel_dist; + } +} + + +static gboolean +blend_colors(GimpRGB *dest, + int num_colors, + ...) +{ + va_list args; + GimpRGB *src; + gdouble opacity = dest->a; + int i; + + va_start(args, num_colors); + + if (num_colors < 1) + return FALSE; + dest->r *= dest->a; + dest->g *= dest->a; + dest->b *= dest->a; + + for (i = 0; i < num_colors; i ++) + { + src = va_arg(args, GimpRGB*); + dest->r += src->r * src->a; + dest->g += src->g * src->a; + dest->b += src->b * src->a; + opacity += src->a; + } + va_end(args); + + if (opacity > 0) + { + dest->r /= opacity; + dest->g /= opacity; + dest->b /= opacity; + } + + dest->a = opacity; + + return TRUE; +} + diff -uNr gimp-2.4.1/app/paint/gimpmixbrush.h gimp-2.4.1-work/app/paint/gimpmixbrush.h --- gimp-2.4.1/app/paint/gimpmixbrush.h 1970-01-01 09:00:00.000000000 +0900 +++ gimp-2.4.1-work/app/paint/gimpmixbrush.h 2008-01-14 23:09:39.000000000 +0900 @@ -0,0 +1,73 @@ +/* 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_MIXBRUSH_H__ +#define __GIMP_MIXBRUSH_H__ + + +#include "gimppaintbrush.h" + + +#define GIMP_TYPE_MIXBRUSH (gimp_mixbrush_get_type ()) +#define GIMP_MIXBRUSH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_MIXBRUSH, GimpMixbrush)) +#define GIMP_MIXBRUSH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_MIXBRUSH, GimpMixbrushClass)) +#define GIMP_IS_MIXBRUSH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_MIXBRUSH)) +#define GIMP_IS_MIXBRUSH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_MIXBRUSH)) +#define GIMP_MIXBRUSH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_MIXBRUSH, GimpMixbrushClass)) + +#define GIMP_MIXBRUSH_MAX_HISTORY 10 + +typedef struct _GimpMixbrushClass GimpMixbrushClass; +typedef struct _GimpMixbrushCoordsHistory +{ + GimpCoords cur_coords; + GimpCoords last_coords; + gdouble pixel_dist; + GimpRGB color; +} GimpMixbrushCoordsHistory; + + +struct _GimpMixbrush +{ + GimpPaintbrush parent_instance; + + GimpDrawable *drawable; + GimpPaintOptions *paint_options; + gdouble current_orig_color_rate; + GimpRGB next_color; + GimpRGB foreground_color; + + /* circular history buffer */ + GimpMixbrushCoordsHistory history[GIMP_MIXBRUSH_MAX_HISTORY + 1]; + gint history_head; + gint history_tail; +}; + +struct _GimpMixbrushClass +{ + GimpPaintbrushClass parent_class; +}; + + +void gimp_mixbrush_register (Gimp *gimp, + GimpPaintRegisterCallback callback); + +GType gimp_mixbrush_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_MIXBRUSH_H__ */ diff -uNr gimp-2.4.1/app/paint/gimpmixbrushoptions.c gimp-2.4.1-work/app/paint/gimpmixbrushoptions.c --- gimp-2.4.1/app/paint/gimpmixbrushoptions.c 1970-01-01 09:00:00.000000000 +0900 +++ gimp-2.4.1-work/app/paint/gimpmixbrushoptions.c 2007-11-04 19:40:41.000000000 +0900 @@ -0,0 +1,295 @@ +/* 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 "libgimpconfig/gimpconfig.h" + +#include "paint-types.h" + +#include "gimpmixbrushoptions.h" + + +#define MIXBRUSH_DEFAULT_CANVAS_COLOR_RATE 0.8 +#define MIXBRUSH_DEFAULT_ORIGINAL_COLOR_RATE 0.5 +#define MIXBRUSH_DEFAULT_DELAYED_COLOR_RATE 0.0 +#define MIXBRUSH_DEFAULT_DRYOUT 0.0 +#define MIXBRUSH_DEFAULT_DELAY 0 +#define MIXBRUSH_DEFAULT_TAIL TRUE +#define MIXBRUSH_DEFAULT_MERGED FALSE +#define MIXBRUSH_DEFAULT_HIDDEN_COLOR GIMP_HIDDEN_COLOR_WHITE +#define MIXBRUSH_DEFAULT_REMOVE_COLOR FALSE + + +enum +{ + PROP_0, + PROP_CANVAS_COLOR_RATE, + PROP_ORIGINAL_COLOR_RATE, + PROP_CANVAS_COLOR_PRESSURE_RATE, + PROP_ORIGINAL_COLOR_PRESSURE_RATE, + PROP_DELAYED_COLOR_RATE, + PROP_DRYOUT, + PROP_DELAY, + PROP_TAIL, + PROP_MERGED, + PROP_HIDDEN_COLOR, + PROP_REMOVE_COLOR, + PROP_INVERT_ORIGINAL_COLOR_PRESSURE, + PROP_INVERT_CANVAS_COLOR_PRESSURE +}; + + +static void gimp_mixbrush_options_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_mixbrush_options_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + + +G_DEFINE_TYPE (GimpMixbrushOptions, gimp_mixbrush_options, + GIMP_TYPE_PAINT_OPTIONS) + +#define parent_class gimp_mixbrush_options_parent_class + + +static void +gimp_mixbrush_options_class_init (GimpMixbrushOptionsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = gimp_mixbrush_options_set_property; + object_class->get_property = gimp_mixbrush_options_get_property; + + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_CANVAS_COLOR_RATE, + "canvas-color-rate", NULL, + 0.0, 1.0, MIXBRUSH_DEFAULT_CANVAS_COLOR_RATE, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_CANVAS_COLOR_PRESSURE_RATE, + "canvas-color-pressure-rate", NULL, + 0.0, 1.0, MIXBRUSH_DEFAULT_CANVAS_COLOR_RATE, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_ORIGINAL_COLOR_RATE, + "original-color-rate", NULL, + 0.0, 1.0, MIXBRUSH_DEFAULT_ORIGINAL_COLOR_RATE, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_ORIGINAL_COLOR_PRESSURE_RATE, + "original-color-pressure-rate", NULL, + 0.0, 1.0, MIXBRUSH_DEFAULT_CANVAS_COLOR_RATE, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_DELAYED_COLOR_RATE, + "delayed-color-rate", NULL, + 0.0, 1.0, MIXBRUSH_DEFAULT_DELAYED_COLOR_RATE, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_INSTALL_PROP_UINT (object_class, PROP_DRYOUT, + "dryout", NULL, + 0, 10000, MIXBRUSH_DEFAULT_DRYOUT, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_INSTALL_PROP_UINT (object_class, PROP_DELAY, + "delay", NULL, + 0, 10, MIXBRUSH_DEFAULT_DELAY, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_TAIL, + "tail", NULL, + MIXBRUSH_DEFAULT_TAIL, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_MERGED, + "merged", NULL, + MIXBRUSH_DEFAULT_MERGED, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_HIDDEN_COLOR, + "hidden-color", NULL, + GIMP_TYPE_HIDDEN_COLOR, + MIXBRUSH_DEFAULT_HIDDEN_COLOR, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_REMOVE_COLOR, + "remove-color", NULL, + MIXBRUSH_DEFAULT_REMOVE_COLOR, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_INVERT_ORIGINAL_COLOR_PRESSURE, + "invert-original-color-pressure", NULL, + FALSE, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_INVERT_CANVAS_COLOR_PRESSURE, + "invert-canvas-color-pressure", NULL, + FALSE, + GIMP_PARAM_STATIC_STRINGS); +} + +static void +gimp_mixbrush_options_init (GimpMixbrushOptions *options) +{ +} + +static void +gimp_mixbrush_options_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpMixbrushOptions *options = GIMP_MIXBRUSH_OPTIONS (object); + + switch (property_id) + { + case PROP_CANVAS_COLOR_RATE: + options->canvas_color_rate = g_value_get_double (value); + break; + case PROP_CANVAS_COLOR_PRESSURE_RATE: + options->canvas_color_pressure_rate = g_value_get_double (value); + break; + case PROP_ORIGINAL_COLOR_RATE: + options->original_color_rate = g_value_get_double (value); + break; + case PROP_ORIGINAL_COLOR_PRESSURE_RATE: + options->original_color_pressure_rate = g_value_get_double (value); + break; + case PROP_DELAYED_COLOR_RATE: + options->delayed_color_rate = g_value_get_double (value); + break; + case PROP_DRYOUT: + options->dryout = g_value_get_uint (value); + break; + case PROP_DELAY: + options->delay = g_value_get_uint (value); + break; + case PROP_TAIL: + options->tail = g_value_get_boolean (value); + break; + case PROP_MERGED: + options->merged = g_value_get_boolean (value); + break; + case PROP_HIDDEN_COLOR: + options->hidden_color = g_value_get_enum (value); + break; + case PROP_REMOVE_COLOR: + options->remove_color = g_value_get_boolean (value); + break; + case PROP_INVERT_ORIGINAL_COLOR_PRESSURE: + options->invert_original_color_pressure = g_value_get_boolean (value); + break; + case PROP_INVERT_CANVAS_COLOR_PRESSURE: + options->invert_canvas_color_pressure = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_mixbrush_options_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpMixbrushOptions *options = GIMP_MIXBRUSH_OPTIONS (object); + + switch (property_id) + { + case PROP_CANVAS_COLOR_RATE: + g_value_set_double (value, options->canvas_color_rate); + break; + case PROP_CANVAS_COLOR_PRESSURE_RATE: + g_value_set_double (value, options->canvas_color_pressure_rate); + break; + case PROP_ORIGINAL_COLOR_RATE: + g_value_set_double (value, options->original_color_rate); + break; + case PROP_ORIGINAL_COLOR_PRESSURE_RATE: + g_value_set_double (value, options->original_color_pressure_rate); + break; + case PROP_DELAYED_COLOR_RATE: + g_value_set_double (value, options->delayed_color_rate); + break; + case PROP_DRYOUT: + g_value_set_uint (value, options->dryout); + break; + case PROP_DELAY: + g_value_set_uint (value, options->delay); + break; + case PROP_TAIL: + g_value_set_boolean (value, options->tail); + break; + case PROP_MERGED: + g_value_set_boolean (value, options->merged); + break; + case PROP_HIDDEN_COLOR: + g_value_set_enum (value, options->hidden_color); + break; + case PROP_REMOVE_COLOR: + g_value_set_boolean (value, options->remove_color); + break; + case PROP_INVERT_ORIGINAL_COLOR_PRESSURE: + g_value_set_boolean (value, options->invert_original_color_pressure); + break; + case PROP_INVERT_CANVAS_COLOR_PRESSURE: + g_value_set_boolean (value, options->invert_canvas_color_pressure); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +GType +gimp_hidden_color_get_type (void) +{ + static const GEnumValue values[] = + { + { GIMP_HIDDEN_COLOR_NORMAL, "GIMP_HIDDEN_COLOR_NORMAL", "normal" }, + { GIMP_HIDDEN_COLOR_WHITE, "GIMP_HIDDEN_COLOR_WHITE", "white" }, + { GIMP_HIDDEN_COLOR_BACKGROUND, "GIMP_HIDDEN_COLOR_BACKGROUND", "background color" }, + { 0, NULL, NULL } + }; + + static const GimpEnumDesc descs[] = + { + { GIMP_HIDDEN_COLOR_NORMAL, "normal", NULL }, + { GIMP_HIDDEN_COLOR_WHITE, "white", NULL }, + { GIMP_HIDDEN_COLOR_BACKGROUND, "background color", NULL }, + { 0, NULL, NULL } + }; + + static GType type = 0; + + if (! type) + { + type = g_enum_register_static ("GimpHiddenColor", values); + gimp_enum_set_value_descriptions (type, descs); + } + + return type; +} diff -uNr gimp-2.4.1/app/paint/gimpmixbrushoptions.h gimp-2.4.1-work/app/paint/gimpmixbrushoptions.h --- gimp-2.4.1/app/paint/gimpmixbrushoptions.h 1970-01-01 09:00:00.000000000 +0900 +++ gimp-2.4.1-work/app/paint/gimpmixbrushoptions.h 2007-11-04 19:40:41.000000000 +0900 @@ -0,0 +1,86 @@ +/* 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_MIXBRUSH_OPTIONS_H__ +#define __GIMP_MIXBRUSH_OPTIONS_H__ + + +#include "gimppaintoptions.h" + + +/* enum(s) */ + +typedef enum +{ + GIMP_HIDDEN_COLOR_NORMAL, + GIMP_HIDDEN_COLOR_WHITE, + GIMP_HIDDEN_COLOR_BACKGROUND +} GimpHiddenColor; + + +#define GIMP_TYPE_HIDDEN_COLOR (gimp_hidden_color_get_type ()) + + +/* values(s) */ + +#define MIXBRUSH_BLEED_MAX_VALUE 0.3 + + + +GType gimp_hidden_color_get_type (void) G_GNUC_CONST; + + +#define GIMP_TYPE_MIXBRUSH_OPTIONS (gimp_mixbrush_options_get_type ()) +#define GIMP_MIXBRUSH_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_MIXBRUSH_OPTIONS, GimpMixbrushOptions)) +#define GIMP_MIXBRUSH_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_MIXBRUSH_OPTIONS, GimpMixbrushOptionsClass)) +#define GIMP_IS_MIXBRUSH_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_MIXBRUSH_OPTIONS)) +#define GIMP_IS_MIXBRUSH_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_MIXBRUSH_OPTIONS)) +#define GIMP_MIXBRUSH_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_MIXBRUSH_OPTIONS, GimpMixbrushOptionsClass)) + + +typedef struct _GimpMixbrushOptionsClass GimpMixbrushOptionsClass; + +struct _GimpMixbrushOptions +{ + GimpPaintOptions parent_instance; + + gdouble canvas_color_rate; + gdouble canvas_color_pressure_rate; + gdouble original_color_rate; + gdouble original_color_pressure_rate; + gdouble delayed_color_rate; + guint dryout; + guint delay; + gboolean merged; + gboolean tail; + GimpHiddenColor hidden_color; + gboolean remove_color; + gboolean invert_original_color_pressure; + gboolean invert_canvas_color_pressure; +}; + +struct _GimpMixbrushOptionsClass +{ + GimpPaintOptionsClass parent_class; +}; + + +GType gimp_mixbrush_options_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_MIXBRUSH_OPTIONS_H__ */ diff -uNr gimp-2.4.1/app/paint/gimppaintcore.c gimp-2.4.1-work/app/paint/gimppaintcore.c --- gimp-2.4.1/app/paint/gimppaintcore.c 2007-09-22 04:40:01.000000000 +0900 +++ gimp-2.4.1-work/app/paint/gimppaintcore.c 2008-01-14 18:26:49.000000000 +0900 @@ -873,6 +873,167 @@ core->canvas_buf->height); } + +/* + * Apply two or more paint mask to the canvas + */ +void +gimp_paint_core_paste_mask_list (GimpPaintCore *core, + GimpDrawable *drawable, + GimpPaintMaskInfo *info, + GimpPaintApplicationMode mode) +{ + GimpImage *image; + TileManager *alt = NULL; + gint off_x; + gint off_y; + gboolean canvas_valid = FALSE; + + image = gimp_item_get_image (GIMP_ITEM (drawable)); + + gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y); + + /* set undo blocks */ + gimp_paint_core_validate_undo_tiles (core, drawable, + core->canvas_buf->x, + core->canvas_buf->y, + core->canvas_buf->width, + core->canvas_buf->height); + + if (core->use_saved_proj) + { + GimpPickable *pickable = GIMP_PICKABLE (image->projection); + + gimp_paint_core_validate_saved_proj_tiles (core, pickable, + core->canvas_buf->x + off_x, + core->canvas_buf->y + off_y, + core->canvas_buf->width, + core->canvas_buf->height); + } + + while (info) + { + alt = NULL; + + /* If the mode is CONSTANT: + * combine the canvas buf, the paint mask to the canvas tiles + */ + if (mode == GIMP_PAINT_CONSTANT) + { + /* Some tools (ink) paint the mask to paint_core->canvas_tiles + * directly. Don't need to copy it in this case. + */ + if (info->paint_maskPR->tiles != core->canvas_tiles) + { + // if (!canvas_valid) + { + /* initialize any invalid canvas tiles */ + gimp_paint_core_validate_canvas_tiles (core, + core->canvas_buf->x, + core->canvas_buf->y, + core->canvas_buf->width, + core->canvas_buf->height); + canvas_valid = TRUE; + } + + if (info->pre_paint) + info->pre_paint (info, core, drawable, mode); + + if (info->paint_operation) + { + PixelRegion srcPR; + + /* combine the paint mask and the canvas tiles */ + pixel_region_init (&srcPR, core->canvas_tiles, + core->canvas_buf->x, + core->canvas_buf->y, + core->canvas_buf->width, + core->canvas_buf->height, + TRUE); + + info->paint_operation (info, core, drawable, mode, &srcPR); + } + else + { + paint_mask_to_canvas_tiles (core, info->paint_maskPR, info->paint_opacity); + } + + if (info->post_paint) + info->post_paint (info, core, drawable, mode); + } + + canvas_tiles_to_canvas_buf (core); + alt = core->undo_tiles; + } + /* Otherwise: + * combine the canvas buf and the paint mask to the canvas buf + */ + else + { + if (info->pre_paint) + info->pre_paint (info, core, drawable, mode); + + + /* combine the canvas buf and the paint mask to the canvas buf */ + if (info->paint_operation) + { + PixelRegion srcPR; + pixel_region_init_temp_buf (&srcPR, core->canvas_buf, + 0, 0, + core->canvas_buf->width, + core->canvas_buf->height); + info->paint_operation (info, core, drawable, mode, &srcPR); + } + else + { + paint_mask_to_canvas_buf (core, info->paint_maskPR, info->paint_opacity); + } + + + if (info->post_paint) + info->post_paint (info, core, drawable, mode); + } + + /* intialize canvas buf source pixel regions */ + if (info->apply) { + PixelRegion srcPR; + pixel_region_init_temp_buf (&srcPR, core->canvas_buf, + 0, 0, + core->canvas_buf->width, + core->canvas_buf->height); + + /* apply the paint area to the image */ + if (info->apply_operation) + info->apply_operation(info, core, drawable, mode, &srcPR, alt); + else { + gimp_drawable_apply_region (drawable, &srcPR, + FALSE, NULL, + info->image_opacity, info->paint_mode, + alt, /* specify an alternative src1 */ + core->canvas_buf->x, + core->canvas_buf->y); + } + } + + info = info->next; + } + /* Update the undo extents */ + core->x1 = MIN (core->x1, core->canvas_buf->x); + core->y1 = MIN (core->y1, core->canvas_buf->y); + core->x2 = MAX (core->x2, core->canvas_buf->x + core->canvas_buf->width); + core->y2 = MAX (core->y2, core->canvas_buf->y + core->canvas_buf->height); + + /* Update the image -- It is important to call gimp_image_update() + * instead of gimp_drawable_update() because we don't want the + * drawable preview to be constantly invalidated + */ + gimp_image_update (image, + core->canvas_buf->x + off_x, + core->canvas_buf->y + off_y, + core->canvas_buf->width, + core->canvas_buf->height); +} + /* This works similarly to gimp_paint_core_paste. However, instead of * combining the canvas to the paint core drawable using one of the * combination modes, it uses a "replace" mode (i.e. transparent diff -uNr gimp-2.4.1/app/paint/gimppaintcore.h gimp-2.4.1-work/app/paint/gimppaintcore.h --- gimp-2.4.1/app/paint/gimppaintcore.h 2007-04-25 00:12:31.000000000 +0900 +++ gimp-2.4.1-work/app/paint/gimppaintcore.h 2008-01-14 23:27:49.000000000 +0900 @@ -34,6 +34,41 @@ typedef struct _GimpPaintCoreClass GimpPaintCoreClass; +typedef struct _GimpPaintMaskInfo GimpPaintMaskInfo; +typedef gint (*GimpPaintMaskPaintDelegator) (GimpPaintMaskInfo *info, + GimpPaintCore *core, + GimpDrawable *drawable, + GimpPaintApplicationMode mode, + PixelRegion *srcPR); + +typedef gint (*GimpPaintMaskApplicationDelegator) (GimpPaintMaskInfo *info, + GimpPaintCore *core, + GimpDrawable *drawable, + GimpPaintApplicationMode mode, + PixelRegion *srcPR, + TileManager* *undo_tiles); + +typedef gint (*GimpPaintMaskEventCallback) (GimpPaintMaskInfo *info, + GimpPaintCore *core, + GimpDrawable *drawable, + GimpPaintApplicationMode mode); + +struct _GimpPaintMaskInfo +{ + PixelRegion *paint_maskPR; + gdouble paint_opacity; + gdouble image_opacity; + gboolean apply; + GimpLayerModeEffects paint_mode; + + GimpPaintMaskEventCallback pre_paint; + GimpPaintMaskEventCallback post_paint; + GimpPaintMaskPaintDelegator paint_operation; + GimpPaintMaskApplicationDelegator apply_operation; + void *delegator_data; + GimpPaintMaskInfo *next; +}; + struct _GimpPaintCore { GimpObject parent_instance; @@ -159,6 +194,10 @@ gdouble image_opacity, GimpLayerModeEffects paint_mode, GimpPaintApplicationMode mode); +void gimp_paint_core_paste_mask_list (GimpPaintCore *core, + GimpDrawable *drawable, + GimpPaintMaskInfo *info, + GimpPaintApplicationMode mode); void gimp_paint_core_replace (GimpPaintCore *core, PixelRegion *paint_maskPR, GimpDrawable *drawable, diff -uNr gimp-2.4.1/app/paint/paint-types.h gimp-2.4.1-work/app/paint/paint-types.h --- gimp-2.4.1/app/paint/paint-types.h 2007-03-08 18:53:41.000000000 +0900 +++ gimp-2.4.1-work/app/paint/paint-types.h 2007-11-04 19:40:41.000000000 +0900 @@ -41,6 +41,8 @@ typedef struct _GimpPencil GimpPencil; typedef struct _GimpPerspectiveClone GimpPerspectiveClone; typedef struct _GimpSmudge GimpSmudge; +typedef struct _GimpInk2 GimpInk2; +typedef struct _GimpMixbrush GimpMixbrush; /* paint options */ @@ -57,12 +59,15 @@ typedef struct _GimpPencilOptions GimpPencilOptions; typedef struct _GimpPerspectiveCloneOptions GimpPerspectiveCloneOptions; typedef struct _GimpSmudgeOptions GimpSmudgeOptions; +typedef struct _GimpInk2Options GimpInk2Options; +typedef struct _GimpMixbrushOptions GimpMixbrushOptions; /* paint undos */ typedef struct _GimpPaintCoreUndo GimpPaintCoreUndo; typedef struct _GimpInkUndo GimpInkUndo; +typedef struct _GimpInk2Undo GimpInk2Undo; /* functions */ diff -uNr gimp-2.4.1/app/paint-funcs/paint-funcs-generic.h gimp-2.4.1-work/app/paint-funcs/paint-funcs-generic.h --- gimp-2.4.1/app/paint-funcs/paint-funcs-generic.h 2007-01-23 19:13:51.000000000 +0900 +++ gimp-2.4.1-work/app/paint-funcs/paint-funcs-generic.h 2008-01-15 10:43:33.000000000 +0900 @@ -348,10 +348,64 @@ const guchar *col, guchar blend, guint w, - guint bytes, - gboolean has_alpha) -{ + guint bytes) + // guint bytes, + // gboolean has_alpha) +{ + if (HAS_ALPHA (bytes)) + { + const guint blend1 = 255 - blend; + const guint blend2 = blend + 1; + const guint c = bytes - 1; + const gint a2 = blend2 * col[c]; + gint cola[MAX_CHANNELS]; + guint b; + + for (b = 0; b < c; b++) + cola[b] = col[b] * a2; + + while (w--) + { + const gint a1 = blend1 * src[c]; + const gint a = a1 + a2; + + if (!a) + { + for (b = 0; b < bytes; b++) + dest[b] = 0; + } + else + { + for (b = 0; b < c; b++) + dest[b] = + src[b] + (src[b] * a1 + cola[b] - a * src[b]) / a; + + dest[c] = a >> 8; + } + + src += bytes; + dest += bytes; + } + } + else + { + const guchar blend1 = 255 - blend; + + while (w--) + { + guint b; + + for (b = 0; b < bytes; b++) + dest[b] = + src[b] + (src[b] * blend1 + col[b] * blend - src[b] * 255) / 255; + + src += bytes; + dest += bytes; + } + } +#if 0 const guchar blend2 = (255 - blend); + const guint has_alpha = HAS_ALPHA(bytes); const guint alpha = (has_alpha) ? bytes - 1 : bytes; while (w--) @@ -367,6 +421,7 @@ src += bytes; dest += bytes; } +#endif } diff -uNr gimp-2.4.1/app/paint-funcs/paint-funcs.c gimp-2.4.1-work/app/paint-funcs/paint-funcs.c --- gimp-2.4.1/app/paint-funcs/paint-funcs.c 2007-10-23 04:16:17.000000000 +0900 +++ gimp-2.4.1-work/app/paint-funcs/paint-funcs.c 2008-01-15 10:38:45.000000000 +0900 @@ -1975,20 +1975,28 @@ guchar *color, guchar blend) { - const guchar *s = src->data; - guchar *d = dest->data; - gint h = src->h; + gpointer pr; - while (h --) + for (pr = pixel_regions_register (2, src, dest); + pr != NULL; + pr = pixel_regions_process (pr)) { - blend_pixels (s, d, color, blend, src->w, src->bytes); + const guchar *s = src->data; + guchar *d = dest->data; + gint h = src->h; - s += src->rowstride; - d += dest->rowstride; + while (h --) + { + shade_pixels (s, d, color, blend, src->w, src->bytes); + + s += src->rowstride; + d += dest->rowstride; + } } } + void copy_region (PixelRegion *src, PixelRegion *dest) diff -uNr gimp-2.4.1/app/paint-funcs/paint-funcs.h gimp-2.4.1-work/app/paint-funcs/paint-funcs.h --- gimp-2.4.1/app/paint-funcs/paint-funcs.h 2007-10-23 04:16:17.000000000 +0900 +++ gimp-2.4.1-work/app/paint-funcs/paint-funcs.h 2008-01-15 10:30:25.000000000 +0900 @@ -58,8 +58,9 @@ const guchar *color, guchar rblend, guint w, - guint bytes, - gboolean has_alpha); + guint bytes); + // guint bytes, + // gboolean has_alpha); void extract_alpha_pixels (const guchar *src, const guchar *mask, diff -uNr gimp-2.4.1/app/tools/Makefile.am gimp-2.4.1-work/app/tools/Makefile.am --- gimp-2.4.1/app/tools/Makefile.am 2007-06-27 18:50:25.000000000 +0900 +++ gimp-2.4.1-work/app/tools/Makefile.am 2007-11-04 19:40:41.000000000 +0900 @@ -167,7 +167,13 @@ gimpvectoroptions.c \ gimpvectoroptions.h \ gimpvectortool.c \ - gimpvectortool.h + gimpvectortool.h \ + gimpink2options-gui.c \ + gimpink2options-gui.h \ + gimpinktool2.c \ + gimpinktool2.h \ + gimpmixbrushtool.c \ + gimpmixbrushtool.h libapptools_a_built_sources = tools-enums.c diff -uNr gimp-2.4.1/app/tools/Makefile.in gimp-2.4.1-work/app/tools/Makefile.in --- gimp-2.4.1/app/tools/Makefile.in 2007-10-31 17:09:08.000000000 +0900 +++ gimp-2.4.1-work/app/tools/Makefile.in 2007-11-04 19:40:41.000000000 +0900 @@ -100,7 +100,9 @@ gimptoolcontrol.$(OBJEXT) gimptooloptions-gui.$(OBJEXT) \ gimptransformoptions.$(OBJEXT) gimptransformtool.$(OBJEXT) \ gimptransformtoolundo.$(OBJEXT) gimpvectoroptions.$(OBJEXT) \ - gimpvectortool.$(OBJEXT) + gimpvectortool.$(OBJEXT) \ + gimpinktool2.$(OBJEXT) gimpink2options-gui.$(OBJEXT) \ + gimpmixbrushtool.$(OBJEXT) am_libapptools_a_OBJECTS = $(am__objects_1) $(am__objects_2) libapptools_a_OBJECTS = $(am_libapptools_a_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) @@ -655,7 +657,13 @@ gimpvectoroptions.c \ gimpvectoroptions.h \ gimpvectortool.c \ - gimpvectortool.h + gimpvectortool.h \ + gimpinktool2.c \ + gimpinktool2.h \ + gimpink2options-gui.c \ + gimpink2options-gui.h \ + gimpmixbrushtool.c \ + gimpmixbrushtool.h libapptools_a_built_sources = tools-enums.c libapptools_a_SOURCES = $(libapptools_a_built_sources) $(libapptools_a_sources) @@ -807,6 +815,9 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_manager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tools-enums.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tools-utils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpink2options-gui.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpinktool2.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpmixbrushtool.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ diff -uNr gimp-2.4.1/app/tools/gimp-tools.c gimp-2.4.1-work/app/tools/gimp-tools.c --- gimp-2.4.1/app/tools/gimp-tools.c 2007-07-25 03:45:41.000000000 +0900 +++ gimp-2.4.1-work/app/tools/gimp-tools.c 2008-01-14 00:20:32.000000000 +0900 @@ -77,6 +77,8 @@ #include "gimpsmudgetool.h" #include "gimptexttool.h" #include "gimpvectortool.h" +#include "gimpinktool2.h" +#include "gimpmixbrushtool.h" #include "gimp-intl.h" @@ -138,6 +140,8 @@ gimp_blend_tool_register, gimp_bucket_fill_tool_register, gimp_text_tool_register, + gimp_ink2_tool_register, + gimp_mixbrush_tool_register, /* transform tools */ @@ -177,6 +181,8 @@ g_return_if_fail (GIMP_IS_GIMP (gimp)); + g_print("[Trace]:gimp_tool_init\n"); + tool_manager_init (gimp); gimp_container_freeze (gimp->tool_info_list); @@ -479,6 +485,14 @@ { paint_core_name = "gimp-ink"; } + else if (tool_type == GIMP_TYPE_INK2_TOOL) + { + paint_core_name = "gimp-ink2"; + } + else if (tool_type == GIMP_TYPE_MIXBRUSH_TOOL) + { + paint_core_name = "gimp-mixbrush"; + } else { paint_core_name = "gimp-paintbrush"; diff -uNr gimp-2.4.1/app/tools/gimpink2options-gui.c gimp-2.4.1-work/app/tools/gimpink2options-gui.c --- gimp-2.4.1/app/tools/gimpink2options-gui.c 1970-01-01 09:00:00.000000000 +0900 +++ gimp-2.4.1-work/app/tools/gimpink2options-gui.c 2007-11-04 19:40:41.000000000 +0900 @@ -0,0 +1,232 @@ +/* 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 "libgimpwidgets/gimpwidgets.h" + +#include "tools-types.h" + +#include "config/gimpconfig-utils.h" + +#include "paint/gimpink2options.h" +#include "paint/gimpink2.h" + +#include "widgets/gimpblobeditor.h" + +#include "gimpink2options-gui.h" +#include "gimppaintoptions-gui.h" + +#include "gimp-intl.h" + + +static GtkWidget * blob_image_new (GimpInkBlobType blob_type); + + +GtkWidget * +gimp_ink2_options_gui (GimpToolOptions *tool_options) +{ + GObject *config = G_OBJECT (tool_options); + GimpInk2Options *ink_options = GIMP_INK2_OPTIONS (tool_options); + GtkWidget *vbox = gimp_paint_options_gui (tool_options); + GtkWidget *frame; + GtkWidget *table; + GtkWidget *blob_vbox; + GtkWidget *hbox; + GtkWidget *editor; + GtkObject *adj; + GtkWidget *compensate_box; + GtkWidget *compensate_vbox; + GtkWidget *checkbox; + + /* adjust sliders */ + frame = gimp_frame_new (_("Adjustment")); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + gtk_widget_show (frame); + + table = gtk_table_new (2, 3, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 2); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_widget_show (table); + + /* size slider */ + adj = gimp_prop_scale_entry_new (config, "size", + GTK_TABLE (table), 0, 0, + _("Size:"), + 1.0, 2.0, 1, + FALSE, 0.0, 0.0); + gimp_scale_entry_set_logarithmic (adj, TRUE); + + /* angle adjust slider */ + gimp_prop_scale_entry_new (config, "tilt-angle", + GTK_TABLE (table), 0, 1, + _("Angle:"), + 1.0, 10.0, 1, + FALSE, 0.0, 0.0); + + /* sens sliders */ + frame = gimp_frame_new (_("Sensitivity")); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + gtk_widget_show (frame); + + table = gtk_table_new (3, 3, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 2); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_widget_show (table); + + /* size sens slider */ + gimp_prop_scale_entry_new (config, "size-sensitivity", + GTK_TABLE (table), 0, 0, + _("Size:"), + 0.01, 0.1, 1, + FALSE, 0.0, 0.0); + + /* tilt sens slider */ + gimp_prop_scale_entry_new (config, "tilt-sensitivity", + GTK_TABLE (table), 0, 1, + _("Tilt:"), + 0.01, 0.1, 1, + FALSE, 0.0, 0.0); + + /* velocity sens slider */ + gimp_prop_scale_entry_new (config, "vel-sensitivity", + GTK_TABLE (table), 0, 2, + _("Speed:"), + 0.01, 0.1, 1, + FALSE, 0.0, 0.0); + + /* compensate at last checkbox */ + compensate_box = gtk_frame_new (_("Pointer Adjustment")); + gtk_box_pack_start (GTK_BOX (vbox), compensate_box, FALSE, TRUE, 0); + gtk_widget_show(compensate_box); + compensate_vbox = gtk_vbox_new (FALSE, 2); + gtk_container_add (GTK_CONTAINER (compensate_box), compensate_vbox); + gtk_widget_show (compensate_vbox); + + table = gtk_table_new (3, 3, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 2); + gtk_box_pack_start (GTK_VBOX (compensate_vbox), table, TRUE, TRUE, 0); + gtk_widget_show (table); + + /* compensation history size slider */ + gimp_prop_scale_entry_new (config, "compensation-history-size", + GTK_TABLE (table), 0, 0, + _("Quality:"), + 1, 1, 0, + FALSE, 1.0, INK2_HISTORY_BUFFER); + + /* pointer tracking rate slider */ + adj = gimp_prop_scale_entry_new (config, "compensation-rate-temperature", + GTK_TABLE (table), 0, 1, + _("Rate:"), + 1, 10, 1, + FALSE, 0, 100); + gimp_scale_entry_set_logarithmic (adj, TRUE); + + checkbox = + gimp_prop_check_button_new (config, "compensate-at-last", + _("Draw pen line to finished point:")); + gtk_box_pack_start (GTK_VBOX (compensate_vbox), checkbox, FALSE, FALSE, 0); + gtk_widget_show(checkbox); + + /* bottom hbox */ + hbox = gtk_hbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + gtk_widget_show (hbox); + + /* Blob type radiobuttons */ + frame = gimp_prop_enum_radio_frame_new (config, "blob-type", + _("Type"), 0, 0); + gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0); + gtk_widget_show (frame); + + { + GList *children; + GList *list; + GimpInkBlobType blob_type; + + children = + gtk_container_get_children (GTK_CONTAINER (GTK_BIN (frame)->child)); + + for (list = children, blob_type = GIMP_INK_BLOB_TYPE_ELLIPSE; + list; + list = g_list_next (list), blob_type++) + { + GtkWidget *radio = GTK_WIDGET (list->data); + GtkWidget *blob; + + gtk_container_remove (GTK_CONTAINER (radio), GTK_BIN (radio)->child); + + blob = blob_image_new (blob_type); + gtk_container_add (GTK_CONTAINER (radio), blob); + gtk_widget_show (blob); + } + + g_list_free (children); + } + + /* Blob shape widget */ + frame = gimp_frame_new (_("Shape")); + gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0); + gtk_widget_show (frame); + + blob_vbox = gtk_vbox_new (FALSE, 2); + gtk_container_add (GTK_CONTAINER (frame), blob_vbox); + gtk_widget_show (blob_vbox); + + frame = gtk_aspect_frame_new (NULL, 0.0, 0.5, 1.0, FALSE); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (blob_vbox), frame, TRUE, TRUE, 0); + gtk_widget_show (frame); + + editor = gimp_blob_editor_new (ink_options->blob_type, + ink_options->blob_aspect, + ink_options->blob_angle); + gtk_widget_set_size_request (editor, 60, 60); + gtk_container_add (GTK_CONTAINER (frame), editor); + gtk_widget_show (editor); + + gimp_config_connect (config, G_OBJECT (editor), NULL); + + return vbox; +} + +static GtkWidget * +blob_image_new (GimpInkBlobType blob_type) +{ + const gchar *stock_id = NULL; + + switch (blob_type) + { + case GIMP_INK_BLOB_TYPE_ELLIPSE: + stock_id = GIMP_STOCK_SHAPE_CIRCLE; + break; + + case GIMP_INK_BLOB_TYPE_SQUARE: + stock_id = GIMP_STOCK_SHAPE_SQUARE; + break; + + case GIMP_INK_BLOB_TYPE_DIAMOND: + stock_id = GIMP_STOCK_SHAPE_DIAMOND; + break; + } + + return gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU); +} diff -uNr gimp-2.4.1/app/tools/gimpink2options-gui.h gimp-2.4.1-work/app/tools/gimpink2options-gui.h --- gimp-2.4.1/app/tools/gimpink2options-gui.h 1970-01-01 09:00:00.000000000 +0900 +++ gimp-2.4.1-work/app/tools/gimpink2options-gui.h 2007-11-04 19:40:41.000000000 +0900 @@ -0,0 +1,26 @@ +/* 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_INK2_OPTIONS_GUI_H__ +#define __GIMP_INK2_OPTIONS_GUI_H__ + + +GtkWidget * gimp_ink2_options_gui (GimpToolOptions *tool_options); + + +#endif /* __GIMP_INK2_OPTIONS_GUI_H__ */ diff -uNr gimp-2.4.1/app/tools/gimpinktool2.c gimp-2.4.1-work/app/tools/gimpinktool2.c --- gimp-2.4.1/app/tools/gimpinktool2.c 1970-01-01 09:00:00.000000000 +0900 +++ gimp-2.4.1-work/app/tools/gimpinktool2.c 2007-11-04 19:40:41.000000000 +0900 @@ -0,0 +1,83 @@ +/* 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 "libgimpwidgets/gimpwidgets.h" + +#include "tools-types.h" + +#include "paint/gimpink2options.h" + +#include "widgets/gimphelp-ids.h" + +#include "gimpink2options-gui.h" +#include "gimpinktool2.h" +#include "gimptoolcontrol.h" + +#include "gimp-intl.h" + + +G_DEFINE_TYPE (GimpInk2Tool, gimp_ink2_tool, GIMP_TYPE_PAINT_TOOL) + +#define parent_class gimp_ink2_tool_parent_class + + +void +gimp_ink2_tool_register (GimpToolRegisterCallback callback, + gpointer data) +{ + (* callback) (GIMP_TYPE_INK2_TOOL, + GIMP_TYPE_INK2_OPTIONS, + gimp_ink2_options_gui, + GIMP_CONTEXT_FOREGROUND_MASK | + GIMP_CONTEXT_BACKGROUND_MASK | + GIMP_CONTEXT_OPACITY_MASK | + GIMP_CONTEXT_PAINT_MODE_MASK, + "gimp-ink2-tool", + _("G-pen"), + _("Draw in G-pen -2-"), + N_("G-pen"), "G", + NULL, GIMP_HELP_TOOL_INK, + GIMP_STOCK_TOOL_INK, + data); +} + +static void +gimp_ink2_tool_class_init (GimpInk2ToolClass *klass) +{ +} + +static void +gimp_ink2_tool_init (GimpInk2Tool *ink_tool) +{ + GimpTool *tool = GIMP_TOOL (ink_tool); + + gimp_tool_control_set_tool_cursor (tool->control, GIMP_TOOL_CURSOR_INK); + gimp_tool_control_set_action_value_2 (tool->control, + "tools/tools-ink-blob-size-set"); + gimp_tool_control_set_action_value_3 (tool->control, + "tools/tools-ink-blob-aspect-set"); + gimp_tool_control_set_action_value_4 (tool->control, + "tools/tools-ink-blob-angle-set"); + + gimp_paint_tool_enable_color_picker (GIMP_PAINT_TOOL (ink_tool), + GIMP_COLOR_PICK_MODE_FOREGROUND); +} diff -uNr gimp-2.4.1/app/tools/gimpinktool2.h gimp-2.4.1-work/app/tools/gimpinktool2.h --- gimp-2.4.1/app/tools/gimpinktool2.h 1970-01-01 09:00:00.000000000 +0900 +++ gimp-2.4.1-work/app/tools/gimpinktool2.h 2007-11-04 19:40:41.000000000 +0900 @@ -0,0 +1,54 @@ +/* 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_INK2_TOOL_H__ +#define __GIMP_INK2_TOOL_H__ + + +#include "gimppainttool.h" + + +#define GIMP_TYPE_INK2_TOOL (gimp_ink2_tool_get_type ()) +#define GIMP_INK2_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_INK2_TOOL, GimpInk2Tool)) +#define GIMP_INK2_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_INK2_TOOL, GimpInk2ToolClass)) +#define GIMP_IS_INK2_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_INK2_TOOL)) +#define GIMP_IS_INK2_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_INK2_TOOL)) +#define GIMP_INK2_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_INK2_TOOL, GimpInk2ToolClass)) + + +typedef struct _GimpInk2Tool GimpInk2Tool; +typedef struct _GimpInk2ToolClass GimpInk2ToolClass; + +struct _GimpInk2Tool +{ + GimpPaintTool parent_instance; +}; + +struct _GimpInk2ToolClass +{ + GimpPaintToolClass parent_class; +}; + + +void gimp_ink2_tool_register (GimpToolRegisterCallback callback, + gpointer data); + +GType gimp_ink2_tool_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_INK2_TOOL_H__ */ diff -uNr gimp-2.4.1/app/tools/gimpmixbrushtool.c gimp-2.4.1-work/app/tools/gimpmixbrushtool.c --- gimp-2.4.1/app/tools/gimpmixbrushtool.c 1970-01-01 09:00:00.000000000 +0900 +++ gimp-2.4.1-work/app/tools/gimpmixbrushtool.c 2007-11-04 19:40:41.000000000 +0900 @@ -0,0 +1,198 @@ +/* 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 "libgimpwidgets/gimpwidgets.h" + +#include "tools-types.h" + +#include "paint/gimpmixbrushoptions.h" + +#include "widgets/gimphelp-ids.h" + +#include "gimpmixbrushtool.h" +#include "gimppaintoptions-gui.h" +#include "gimptoolcontrol.h" + +#include "gimp-intl.h" + + +static GtkWidget * gimp_mixbrush_options_gui (GimpToolOptions *tool_options); + + +G_DEFINE_TYPE (GimpMixbrushTool, gimp_mixbrush_tool, GIMP_TYPE_PAINTBRUSH_TOOL) + + +void +gimp_mixbrush_tool_register (GimpToolRegisterCallback callback, + gpointer data) +{ + (* callback) (GIMP_TYPE_MIXBRUSH_TOOL, + GIMP_TYPE_MIXBRUSH_OPTIONS, + gimp_mixbrush_options_gui, + GIMP_PAINT_OPTIONS_CONTEXT_MASK | + GIMP_CONTEXT_GRADIENT_MASK, + "gimp-mixbrush-tool", + _("Mixbrush"), + _("Mixbrush Tool: Brush with mixing color feature"), + N_("_Mixbrush"), "W", + NULL, GIMP_HELP_TOOL_PAINTBRUSH, + GIMP_STOCK_TOOL_PAINTBRUSH, + data); +} + +static void +gimp_mixbrush_tool_class_init (GimpMixbrushToolClass *klass) +{ +} + +static void +gimp_mixbrush_tool_init (GimpMixbrushTool *mixbrush) +{ + GimpTool *tool = GIMP_TOOL (mixbrush); + + gimp_tool_control_set_tool_cursor (tool->control, GIMP_TOOL_CURSOR_PAINTBRUSH); + + gimp_paint_tool_enable_color_picker (GIMP_PAINT_TOOL (mixbrush), + GIMP_COLOR_PICK_MODE_FOREGROUND); +} + + +/* tool options stuff */ + +static GtkWidget * +gimp_mixbrush_options_gui (GimpToolOptions *tool_options) +{ + GObject *config = G_OBJECT (tool_options); + GtkWidget *vbox = gimp_paint_options_gui (tool_options); + GtkWidget *table; + GtkWidget *mixbrush_box; + GtkWidget *mixbrush_vbox; + GtkWidget *mixbrush_button; + GtkWidget *mixbrush_frame; + + table = gtk_table_new (2, 3, FALSE); + gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0); + gtk_widget_show (table); + + /* Canvas Color Picking Configurations */ + mixbrush_box = gtk_frame_new (_("Canvas Color")); + gtk_box_pack_start (GTK_BOX (vbox), mixbrush_box, FALSE, TRUE, 0); + gtk_widget_show(mixbrush_box); + mixbrush_vbox = gtk_vbox_new (FALSE, 2); + gtk_container_add (GTK_CONTAINER (mixbrush_box), mixbrush_vbox); + gtk_widget_show (mixbrush_vbox); + + table = gtk_table_new (3, 5, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 2); + gtk_box_pack_start (GTK_BOX (mixbrush_vbox), table, TRUE, TRUE, 0); + gtk_widget_show (table); + + gimp_prop_scale_entry_new (config, "canvas-color-rate", + GTK_TABLE (table), 0, 0, + _("Rate:"), + 0.01, 0.1, 2, + FALSE, 0.0, 1.0); + + gimp_prop_scale_entry_new (config, "canvas-color-pressure-rate", + GTK_TABLE (table), 0, 1, + _("Pressure:"), + 0.01, 0.1, 2, + FALSE, 0.0, 1.0); + + mixbrush_button = gimp_prop_check_button_new (config, "invert-canvas-color-pressure", _("Invert Pressure")); + gtk_box_pack_start (GTK_BOX (mixbrush_vbox), mixbrush_button, FALSE, TRUE, 0); + gtk_widget_show (mixbrush_button); + + gimp_prop_scale_entry_new (config, "delayed-color-rate", + GTK_TABLE (table), 0, 2, + _("Delayed Mixing:"), + 0.005, 0.025, 3, + TRUE, 0.0, 1.0); + + /* Original Color Picking Configurations */ + mixbrush_box = gtk_frame_new (_("Original Color")); + gtk_box_pack_start (GTK_BOX (vbox), mixbrush_box, FALSE, TRUE, 0); + gtk_widget_show(mixbrush_box); + mixbrush_vbox = gtk_vbox_new (FALSE, 2); + gtk_container_add (GTK_CONTAINER (mixbrush_box), mixbrush_vbox); + gtk_widget_show (mixbrush_vbox); + + table = gtk_table_new (3, 4, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 2); + gtk_box_pack_start (GTK_BOX (mixbrush_vbox), table, TRUE, TRUE, 0); + gtk_widget_show (table); + + gimp_prop_scale_entry_new (config, "original-color-rate", + GTK_TABLE (table), 0, 0, + _("Rate:"), + 0.01, 0.1, 2, + FALSE, 0.0, 1.0); + + gimp_prop_scale_entry_new (config, "original-color-pressure-rate", + GTK_TABLE (table), 0, 1, + _("Pressure:"), + 0.01, 0.1, 2, + FALSE, -1.0, 1.0); + + mixbrush_button = gimp_prop_check_button_new (config, "invert-original-color-pressure", _("Invert Pressure")); + gtk_box_pack_start (GTK_BOX (mixbrush_vbox), mixbrush_button, FALSE, TRUE, 0); + gtk_widget_show (mixbrush_button); + + gimp_prop_scale_entry_new (config, "dryout", + GTK_TABLE (table), 0, 2, + _("Dryout:"), + 10.0, 100.0, 0, + TRUE, 0.0, 10000); + + table = gtk_table_new (3, 1, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 2); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_widget_show (table); + + gimp_prop_scale_entry_new (config, "delay", + GTK_TABLE (table), 0, 0, + _("Delay:"), + 1.0, 2.0, 0, + TRUE, 0.0, 10); + + mixbrush_button = gimp_prop_check_button_new (config, "tail", _("Paint the tail of stroke (delay > 0)")); + gtk_box_pack_start (GTK_BOX (vbox), mixbrush_button, FALSE, TRUE, 0); + gtk_widget_show (mixbrush_button); + + /*mixbrush_button = gimp_prop_check_button_new (config, "merged", _("Pick up underlying color"));*/ + mixbrush_button = gimp_prop_check_button_new (config, "merged", _("Pick up merged color")); + gtk_box_pack_start (GTK_BOX (vbox), mixbrush_button, FALSE, TRUE, 0); + gtk_widget_show (mixbrush_button); + + mixbrush_frame = gimp_prop_enum_radio_frame_new (config, "hidden-color", + _("Assume that the hidden color is:"), + 0, 0); + gtk_box_pack_start (GTK_BOX (vbox), mixbrush_frame, FALSE, TRUE, 0); + gtk_widget_show (mixbrush_frame); + + mixbrush_button = gimp_prop_check_button_new (config, "remove-color", _("Remove background color")); + gtk_box_pack_start (GTK_BOX (vbox), mixbrush_button, FALSE, TRUE, 0); + gtk_widget_show (mixbrush_button); + + return vbox; +} diff -uNr gimp-2.4.1/app/tools/gimpmixbrushtool.h gimp-2.4.1-work/app/tools/gimpmixbrushtool.h --- gimp-2.4.1/app/tools/gimpmixbrushtool.h 1970-01-01 09:00:00.000000000 +0900 +++ gimp-2.4.1-work/app/tools/gimpmixbrushtool.h 2007-11-04 19:40:41.000000000 +0900 @@ -0,0 +1,54 @@ +/* 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_MIXBRUSH_TOOL_H__ +#define __GIMP_MIXBRUSH_TOOL_H__ + + +#include "gimppaintbrushtool.h" + + +#define GIMP_TYPE_MIXBRUSH_TOOL (gimp_mixbrush_tool_get_type ()) +#define GIMP_MIXBRUSH_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_MIXBRUSH_TOOL, GimpMixbrushTool)) +#define GIMP_MIXBRUSH_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_MIXBRUSH_TOOL, GimpMixbrushToolClass)) +#define GIMP_IS_MIXBRUSH_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_MIXBRUSH_TOOL)) +#define GIMP_IS_MIXBRUSH_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_MIXBRUSH_TOOL)) +#define GIMP_MIXBRUSH_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_MIXBRUSH_TOOL, GimpMixbrushToolClass)) + + +typedef struct _GimpMixbrushTool GimpMixbrushTool; +typedef struct _GimpMixbrushToolClass GimpMixbrushToolClass; + +struct _GimpMixbrushTool +{ + GimpPaintbrushTool parent_instance; +}; + +struct _GimpMixbrushToolClass +{ + GimpPaintbrushToolClass parent_class; +}; + + +void gimp_mixbrush_tool_register (GimpToolRegisterCallback callback, + gpointer data); + +GType gimp_mixbrush_tool_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_MIXBRUSH_TOOL_H__ */ diff -uNr gimp-2.4.1/app/tools/gimppaintoptions-gui.c gimp-2.4.1-work/app/tools/gimppaintoptions-gui.c --- gimp-2.4.1/app/tools/gimppaintoptions-gui.c 2007-10-23 04:16:17.000000000 +0900 +++ gimp-2.4.1-work/app/tools/gimppaintoptions-gui.c 2007-11-04 19:40:41.000000000 +0900 @@ -46,6 +46,7 @@ #include "gimppenciltool.h" #include "gimpperspectiveclonetool.h" #include "gimpsmudgetool.h" +#include "gimpmixbrushtool.h" #include "gimptooloptions-gui.h" #include "gimp-intl.h" @@ -175,6 +176,7 @@ /* the "incremental" toggle */ if (tool_type == GIMP_TYPE_PENCIL_TOOL || tool_type == GIMP_TYPE_PAINTBRUSH_TOOL || + tool_type == GIMP_TYPE_MIXBRUSH_TOOL || tool_type == GIMP_TYPE_ERASER_TOOL) { incremental_toggle = @@ -293,6 +295,7 @@ tool_type == GIMP_TYPE_DODGE_BURN_TOOL || tool_type == GIMP_TYPE_ERASER_TOOL || tool_type == GIMP_TYPE_PAINTBRUSH_TOOL || + tool_type == GIMP_TYPE_MIXBRUSH_TOOL || tool_type == GIMP_TYPE_PENCIL_TOOL) { button = gimp_prop_check_button_new (config, "pressure-size", diff -uNr gimp-2.4.1/app/widgets/gimpdbusservice-glue.h gimp-2.4.1-work/app/widgets/gimpdbusservice-glue.h --- gimp-2.4.1/app/widgets/gimpdbusservice-glue.h 2007-08-16 07:51:29.000000000 +0900 +++ gimp-2.4.1-work/app/widgets/gimpdbusservice-glue.h 1970-01-01 09:00:00.000000000 +0900 @@ -1,169 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_gimp_MARSHAL_H__ -#define __dbus_glib_marshal_gimp_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_char (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -/* BOOLEAN:STRING,POINTER,POINTER (/tmp/dbus-binding-tool-c-marshallers.5HE9WT:1) */ -extern void dbus_glib_marshal_gimp_BOOLEAN__STRING_POINTER_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_gimp_BOOLEAN__STRING_POINTER_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data) -{ - typedef gboolean (*GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer arg_3, - gpointer data2); - register GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER callback; - register GCClosure *cc = (GCClosure*) closure; - register gpointer data1, data2; - gboolean v_return; - - g_return_if_fail (return_value != NULL); - g_return_if_fail (n_param_values == 4); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER) (marshal_data ? marshal_data : cc->callback); - - v_return = callback (data1, - g_marshal_value_peek_string (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), - g_marshal_value_peek_pointer (param_values + 3), - data2); - - g_value_set_boolean (return_value, v_return); -} - -/* BOOLEAN:POINTER (/tmp/dbus-binding-tool-c-marshallers.5HE9WT:2) */ -extern void dbus_glib_marshal_gimp_BOOLEAN__POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_gimp_BOOLEAN__POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data) -{ - typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER) (gpointer data1, - gpointer arg_1, - gpointer data2); - register GMarshalFunc_BOOLEAN__POINTER callback; - register GCClosure *cc = (GCClosure*) closure; - register gpointer data1, data2; - gboolean v_return; - - g_return_if_fail (return_value != NULL); - g_return_if_fail (n_param_values == 2); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_BOOLEAN__POINTER) (marshal_data ? marshal_data : cc->callback); - - v_return = callback (data1, - g_marshal_value_peek_pointer (param_values + 1), - data2); - - g_value_set_boolean (return_value, v_return); -} - -G_END_DECLS - -#endif /* __dbus_glib_marshal_gimp_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_gimp_methods[] = { - { (GCallback) gimp_dbus_service_open, dbus_glib_marshal_gimp_BOOLEAN__STRING_POINTER_POINTER, 0 }, - { (GCallback) gimp_dbus_service_open_as_new, dbus_glib_marshal_gimp_BOOLEAN__STRING_POINTER_POINTER, 49 }, - { (GCallback) gimp_dbus_service_activate, dbus_glib_marshal_gimp_BOOLEAN__POINTER, 103 }, -}; - -const DBusGObjectInfo dbus_glib_gimp_object_info = { - 0, - dbus_glib_gimp_methods, - 3, -"org.gimp.GIMP.UI\0Open\0S\0uri\0I\0s\0success\0O\0F\0N\0b\0\0org.gimp.GIMP.UI\0OpenAsNew\0S\0uri\0I\0s\0success\0O\0F\0N\0b\0\0org.gimp.GIMP.UI\0Activate\0S\0\0\0", -"\0", -"\0" -}; -