--- gimp-2.4.3--/app/paint/gimpmixbrush.c Mon Jan 21 06:22:01 2008 +++ gimp-painter--2.4.3/app/paint/gimpmixbrush.c Mon Jan 21 04:39:09 2008 @@ -38,6 +38,7 @@ #include "core/gimpdrawable.h" #include "core/gimplayer.h" #include "core/gimpgradient.h" +#include "core/gimppattern.h" #include "core/gimpimage.h" #include "core/gimppickable.h" #include "core/gimpprojection.h" @@ -137,9 +138,31 @@ #ifndef GIMP_MIXBRUSH_COMPOSITE void paste_canvas (GimpPaintCore *core, GimpDrawable *drawable, + GimpPattern *texture, GimpRGB *paint_color, gdouble opacity, + gdouble grain, gboolean reduce_update_freq); + +__inline__ void composite_dab (GimpRGB *paint_color, + gdouble opacity, + PixelRegion *srcPR, + PixelRegion *maskPR, + const gboolean is_rgb, + const gboolean has_alpha); + +__inline__ void composite_textured_dab (GimpRGB *paint_color, + gdouble opacity, + PixelRegion *srcPR, + PixelRegion *maskPR, + TempBuf *texture_buf, + gint x, + gint y, + gint drawable_x, + gint drawable_y, + gdouble grain, + const gboolean is_rgb, + const gboolean has_alpha); #endif @@ -595,14 +618,29 @@ #endif if (pressure_options->opacity) - history->opacity *= PRESSURE_SCALE * history->coords.pressure; + history->opacity *= PRESSURE_SCALE * paint_core->cur_coords.pressure; /* finally, let the brush core paste the colored area on the canvas */ if (mixbrush_options->alpha_channel_mixing && paint_appl_mode == GIMP_PAINT_INCREMENTAL) { gdouble op = MIN (history->opacity, GIMP_OPACITY_OPAQUE) * gimp_context_get_opacity (context); - paste_canvas (paint_core, drawable, last_color, op, paint_options->reduce_update_freq); + gdouble grain = 0.0; + GimpPattern *texture = NULL; + + if (mixbrush_options->texture_options->use_texture) + { + grain = mixbrush_options->texture_options->grain; + grain -= (2.0 - (grain + 1.0)) * (1.0 - paint_core->cur_coords.pressure); + + texture = gimp_context_get_pattern (context); + } + + paste_canvas (paint_core, drawable, + texture, + last_color, op, + grain, + paint_options->reduce_update_freq); } else { @@ -966,8 +1004,10 @@ void paste_canvas (GimpPaintCore *core, GimpDrawable *drawable, + GimpPattern *texture, GimpRGB *paint_color, gdouble opacity, + gdouble grain, gboolean reduce_update_freq) { TempBuf *brush_mask = gimp_brush_core_get_brush_mask (GIMP_BRUSH_CORE (core), GIMP_BRUSH_SOFT); @@ -975,6 +1015,7 @@ gint c_x = canvas_buf->x, c_y = canvas_buf->y, c_w = canvas_buf->width, c_h = canvas_buf->height; PixelRegion srcPR, maskPR; gint x, y, off_x, off_y; + gboolean is_rgb, has_alpha; if (!brush_mask || !canvas_buf || opacity == 0.0) return; @@ -998,6 +1039,119 @@ off_x, off_y, brush_mask->width, brush_mask->height); + is_rgb = (srcPR.bytes > 2); + has_alpha = (srcPR.bytes == 2 || srcPR.bytes == 4); + + if (texture) + { + gint dx, dy; + + gimp_item_offsets (GIMP_ITEM (drawable), &dx, &dy); + + composite_textured_dab (paint_color, + opacity, + &srcPR, + &maskPR, + texture->mask, + x, y, + dx, dy, + grain, + is_rgb, + has_alpha); + } + else + composite_dab (paint_color, + opacity, + &srcPR, + &maskPR, + is_rgb, + has_alpha); + +#if 0 + { + static int c = 0; + if (++c == 1) + { + /*g_file_set_contents ("r:\\out_canvas_buf_00.raw", temp_buf_data (canvas_buf), + canvas_buf->width * canvas_buf->height * canvas_buf->bytes, + NULL); + g_file_set_contents ("r:\\out_brush_mask_00.raw", temp_buf_data (brush_mask), + brush_mask->width * brush_mask->height * brush_mask->bytes, + NULL);*/ + + TileManager *tm = gimp_drawable_get_tiles (drawable); + guint stride = tile_manager_width (tm) * tile_manager_bpp (tm); + guint len = stride * tile_manager_height (tm); + guchar *buf = g_malloc(len); + read_pixel_data (tm, 0, 0, + tile_manager_width (tm) - 1, + tile_manager_height (tm) - 1, + buf, stride); + g_file_set_contents ("r:\\out_drawable_00.raw", buf, len, NULL); + } + } +#endif + + /* Update the undo extents */ + core->x1 = MIN (core->x1, c_x); + core->y1 = MIN (core->y1, c_y); + core->x2 = MAX (core->x2, c_x + c_w) ; + core->y2 = MAX (core->y2, c_y + c_h) ; + + /* Update the drawable */ + if (reduce_update_freq) + { + gdouble n; + gdouble r; + + n = MAX (core->cur_coords.velocity - 0.015, 0.0) * 25.0; + r = (core->canvas_buf->width + core->canvas_buf->height) / 2.0; + + n *= faster_pow (r / 30.0, 1.35); + //g_printerr ("velo : %f / n : %f / threshold %d\n", core->cur_coords.velocity, n, (gint)(MIN (n, 25.0 - sqrt (r)))); + + if (core->update_count) + { + core->_x1 = MIN (core->_x1, c_x); + core->_y1 = MIN (core->_y1, c_y); + core->_x2 = MAX (core->_x2, c_x + c_w - 1); + core->_y2 = MAX (core->_y2, c_y + c_h - 1); + } + else + { + core->_x1 = c_x; + core->_x2 = c_x + c_w - 1; + core->_y1 = c_y; + core->_y2 = c_y + c_h - 1; + } + + if (++core->update_count >= (gint)(MIN (n, 25.0 - sqrt (r)))) + { + core->update_count = 0; + core->updated = TRUE; + + gimp_drawable_update (drawable, + core->_x1, + core->_y1, + core->_x2 - core->_x1 + 1, + core->_y2 - core->_y1 + 1); + } + else + core->updated = FALSE; + } + else + gimp_drawable_update (drawable, c_x, c_y, c_w, c_h); + +} + +__inline__ void +composite_dab (GimpRGB *paint_color, + gdouble opacity, + PixelRegion *srcPR, + PixelRegion *maskPR, + const gboolean is_rgb, + const gboolean has_alpha) +{ { /* _composite_* () */ gpointer iter; gint w, h; @@ -1007,15 +1161,10 @@ guchar *mask_data, *_mask_data; GimpRGB _paint_color; gdouble adjusted_opacity = pow (opacity, 1.0 / 1.5); - gboolean is_rgb, has_alpha; /*static GimpRGB error = {0.0, 0.0, 0.0, 0.0}; GimpRGB _error = {0.0, 0.0, 0.0, 0.0};*/ - gint npixels = 0; - - src_bytes = srcPR.bytes; - is_rgb = (src_bytes > 2); - has_alpha = (src_bytes == 2 || src_bytes == 4); + src_bytes = srcPR->bytes; _paint_color.r = paint_color->r * 255.0; if (is_rgb) @@ -1024,16 +1173,16 @@ _paint_color.b = paint_color->b * 255.0; } - for (iter = pixel_regions_register (2, &srcPR, &maskPR); iter != NULL; iter = pixel_regions_process (iter)) + for (iter = pixel_regions_register (2, srcPR, maskPR); iter != NULL; iter = pixel_regions_process (iter)) { gint i, j; - src_data = srcPR.data; - mask_data = maskPR.data; - w = maskPR.w; - h = maskPR.h; - src_stride = srcPR.rowstride; - mask_stride = maskPR.rowstride; + src_data = srcPR->data; + mask_data = maskPR->data; + w = maskPR->w; + h = maskPR->h; + src_stride = srcPR->rowstride; + mask_stride = maskPR->rowstride; for (i = 0; i < h; i++) { @@ -1045,6 +1194,7 @@ gdouble op, mask_op, paint_color_op, canvas_color_op, src_op; gdouble factor1, factor2; gdouble component; + #if 0 if (j == c_w / 2 && i == c_h / 2) { @@ -1099,7 +1249,6 @@ _src_data[2] = component + .5; /*_error.b += component - _src_data[2];*/ } - /*npixels++;*/ } } #if 0 @@ -1124,81 +1273,135 @@ g_printerr ("error : %f %f %f %f\n", error.r, error.g, error.b, error.a); }*/ } /* _composite_* () */ +} -#if 0 - { - static int c = 0; - if (++c == 1) - { - /*g_file_set_contents ("r:\\out_canvas_buf_00.raw", temp_buf_data (canvas_buf), - canvas_buf->width * canvas_buf->height * canvas_buf->bytes, - NULL); - g_file_set_contents ("r:\\out_brush_mask_00.raw", temp_buf_data (brush_mask), - brush_mask->width * brush_mask->height * brush_mask->bytes, - NULL);*/ +__inline__ void +composite_textured_dab (GimpRGB *paint_color, + gdouble opacity, + PixelRegion *srcPR, + PixelRegion *maskPR, + TempBuf *texture_buf, + gint x, + gint y, + gint drawable_x, + gint drawable_y, + gdouble grain, + const gboolean is_rgb, + const gboolean has_alpha) +{ + gpointer iter; + gint w, h; + gint src_bytes; + gint src_stride, mask_stride, texture_stride; + guchar *src_data, *_src_data; + guchar *mask_data, *_mask_data; + guchar *texture_data; + GimpRGB _paint_color; + gdouble adjusted_opacity = pow (opacity, 1.0 / 1.5); + /*static GimpRGB error = {0.0, 0.0, 0.0, 0.0}; + GimpRGB _error = {0.0, 0.0, 0.0, 0.0};*/ - TileManager *tm = gimp_drawable_get_tiles (drawable); - guint stride = tile_manager_width (tm) * tile_manager_bpp (tm); - guint len = stride * tile_manager_height (tm); - guchar *buf = g_malloc(len); - read_pixel_data (tm, 0, 0, - tile_manager_width (tm) - 1, - tile_manager_height (tm) - 1, - buf, stride); - g_file_set_contents ("r:\\out_drawable_00.raw", buf, len, NULL); - } - } -#endif + src_bytes = srcPR->bytes; - /* Update the undo extents */ - core->x1 = MIN (core->x1, c_x); - core->y1 = MIN (core->y1, c_y); - core->x2 = MAX (core->x2, c_x + c_w) ; - core->y2 = MAX (core->y2, c_y + c_h) ; + _paint_color.r = paint_color->r * 255.0; + if (is_rgb) + { + _paint_color.g = paint_color->g * 255.0; + _paint_color.b = paint_color->b * 255.0; + } - /* Update the drawable */ - if (reduce_update_freq) - { - gdouble n; - gdouble r; + texture_data = temp_buf_data (texture_buf); + texture_stride = texture_buf->width * texture_buf->bytes; - n = MAX (core->cur_coords.velocity - 0.015, 0.0) * 25.0; - r = (core->canvas_buf->width + core->canvas_buf->height) / 2.0; + for (iter = pixel_regions_register (2, srcPR, maskPR); iter != NULL; iter = pixel_regions_process (iter)) + { + gint i, j; + gint texture_off_x, _texture_off_x, texture_off_y; - n *= faster_pow (r / 30.0, 1.35); - //g_printerr ("velo : %f / n : %f / threshold %d\n", core->cur_coords.velocity, n, (gint)(MIN (n, 25.0 - sqrt (r)))); + /* calc origin of texture buffer */ + texture_off_x = drawable_x + x + maskPR->x; + texture_off_y = drawable_y + y + maskPR->y; - if (core->update_count) - { - core->_x1 = MIN (core->_x1, c_x); - core->_y1 = MIN (core->_y1, c_y); - core->_x2 = MAX (core->_x2, c_x + c_w - 1); - core->_y2 = MAX (core->_y2, c_y + c_h - 1); - } - else - { - core->_x1 = c_x; - core->_x2 = c_x + c_w - 1; - core->_y1 = c_y; - core->_y2 = c_y + c_h - 1; - } + src_data = srcPR->data; + mask_data = maskPR->data; + w = maskPR->w; + h = maskPR->h; + src_stride = srcPR->rowstride; + mask_stride = maskPR->rowstride; - if (++core->update_count >= (gint)(MIN (n, 25.0 - sqrt (r)))) - { - core->update_count = 0; - core->updated = TRUE; + for (i = 0; i < h; i++, texture_off_y++) + { + _src_data = src_data; + _mask_data = mask_data; - gimp_drawable_update (drawable, - core->_x1, - core->_y1, - core->_x2 - core->_x1 + 1, - core->_y2 - core->_y1 + 1); - } - else - core->updated = FALSE; - } - else - gimp_drawable_update (drawable, c_x, c_y, c_w, c_h); + texture_off_y = texture_off_y % texture_buf->height; + _texture_off_x = texture_off_x; + for (j = 0; j < w; j++, _texture_off_x++) + { + gdouble op, mask_op, paint_color_op, canvas_color_op, src_op; + gdouble texture_op; + gdouble factor1, factor2; + gdouble component; + + _texture_off_x = _texture_off_x % texture_buf->width; + + texture_op = *(texture_data + texture_off_y * texture_stride + _texture_off_x * texture_buf->bytes) / 255.0; + texture_op = CLAMP (texture_op + grain, 0.0, 1.0); + + if (_mask_data[0]) + { + mask_op = _mask_data[0] / 255.0; + + if (has_alpha) + { + src_op = _src_data[src_bytes - 1] / 255.0; + + /* workaround against insufficiency of opacity */ + /*if (paint_color->a > src_op) + op = pow (opacity, 1.0 / 1.5) * mask_op;*/ + gfloat n = paint_color->a - src_op; + guint32 _n = (*(guint32 *) &n) >> 31; + op = (opacity * _n + adjusted_opacity * (1 - _n)) * mask_op * texture_op; + + component = (paint_color->a * op + src_op * (1.0 - op)) * 255.0/* + error.a*/; + _src_data[src_bytes - 1] = component + .5; + /*_error.a += component - _src_data[src_bytes - 1];*/ + } + else + src_op = 1.0; + + op = opacity * mask_op * texture_op; + paint_color_op = paint_color->a * op; + + if (paint_color_op > 0.0) + { + canvas_color_op = (1.0 - paint_color_op) * src_op; + + factor1 = paint_color_op / (paint_color_op + canvas_color_op); + factor2 = 1.0 - factor1; + + component = _paint_color.r * factor1 + _src_data[0] * factor2/* + error.r*/; + _src_data[0] = component + .5; + /*_error.r += component - _src_data[0];*/ + if (is_rgb) + { + component = _paint_color.g * factor1 + _src_data[1] * factor2/* + error.g*/; + _src_data[1] = component + .5; + /*_error.g += component - _src_data[1];*/ + + component = _paint_color.b * factor1 + _src_data[2] * factor2/* + error.b*/; + _src_data[2] = component + .5; + /*_error.b += component - _src_data[2];*/ + } + } + } + _src_data += src_bytes; + _mask_data++; + } + src_data += src_stride; + mask_data += mask_stride; + } + } /* end of iteration */ } #endif --- gimp-2.4.3--/app/paint/gimpmixbrushoptions.c Mon Jan 21 06:22:01 2008 +++ gimp-painter--2.4.3/app/paint/gimpmixbrushoptions.c Mon Jan 21 04:08:38 2008 @@ -28,6 +28,9 @@ #include "gimpmixbrushoptions.h" +#define MIXBRUSH_DEFAULT_USE_TEXTURE FALSE +#define MIXBRUSH_DEFAULT_TEXTURE_GRAIN 0.0 + #define MIXBRUSH_DEFAULT_MAIN_COLOR_DENSITY 0.5 #define MIXBRUSH_DEFAULT_MAIN_COLOR_RATE 0.2 #define MIXBRUSH_DEFAULT_CANVAS_COLOR_DENSITY 1.0 @@ -53,6 +56,8 @@ enum { PROP_0, + PROP_USE_TEXTURE, + PROP_TEXTURE_GRAIN, PROP_MAIN_COLOR_DENSITY, PROP_MAIN_COLOR_RATE, PROP_CANVAS_COLOR_DENSITY, @@ -86,6 +91,7 @@ }; +static void gimp_mixbrush_options_finalize (GObject *object); static void gimp_mixbrush_options_set_property (GObject *object, guint property_id, const GValue *value, @@ -107,9 +113,20 @@ { GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = gimp_mixbrush_options_finalize; object_class->set_property = gimp_mixbrush_options_set_property; object_class->get_property = gimp_mixbrush_options_get_property; + GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_USE_TEXTURE, + "use-texture", NULL, + MIXBRUSH_DEFAULT_USE_TEXTURE, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_TEXTURE_GRAIN, + "texture-grain", NULL, + -1.0, 1.0, MIXBRUSH_DEFAULT_TEXTURE_GRAIN, + GIMP_PARAM_STATIC_STRINGS); + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_MAIN_COLOR_DENSITY, "main-color-density", NULL, 0.0, 1.0, MIXBRUSH_DEFAULT_MAIN_COLOR_DENSITY, @@ -268,6 +285,17 @@ static void gimp_mixbrush_options_init (GimpMixbrushOptions *options) { + options->texture_options = g_slice_new0 (GimpTextureOptions); +} + +static void +gimp_mixbrush_options_finalize (GObject *object) +{ + GimpMixbrushOptions *options = GIMP_MIXBRUSH_OPTIONS (object); + + g_slice_free (GimpTextureOptions, options->texture_options); + + G_OBJECT_CLASS (parent_class)->finalize (object); } static void @@ -277,9 +305,16 @@ GParamSpec *pspec) { GimpMixbrushOptions *options = GIMP_MIXBRUSH_OPTIONS (object); + GimpTextureOptions *texture_options = options->texture_options; switch (property_id) { + case PROP_USE_TEXTURE: + texture_options->use_texture = g_value_get_boolean (value); + break; + case PROP_TEXTURE_GRAIN: + texture_options->grain = g_value_get_double (value); + break; case PROP_MAIN_COLOR_DENSITY: options->main_color_density = g_value_get_double (value); break; @@ -382,10 +417,17 @@ GValue *value, GParamSpec *pspec) { - GimpMixbrushOptions *options = GIMP_MIXBRUSH_OPTIONS (object); + GimpMixbrushOptions *options = GIMP_MIXBRUSH_OPTIONS (object); + GimpTextureOptions *texture_options = options->texture_options; switch (property_id) { + case PROP_USE_TEXTURE: + g_value_set_boolean (value, texture_options->use_texture); + break; + case PROP_TEXTURE_GRAIN: + g_value_set_double (value, texture_options->grain); + break; case PROP_MAIN_COLOR_DENSITY: g_value_set_double (value, options->main_color_density); break; --- gimp-2.4.3--/app/paint/gimpmixbrushoptions.h Mon Jan 21 06:22:01 2008 +++ gimp-painter--2.4.3/app/paint/gimpmixbrushoptions.h Mon Jan 21 03:51:14 2008 @@ -48,39 +48,46 @@ typedef struct _GimpMixbrushOptionsClass GimpMixbrushOptionsClass; +typedef struct _GimpTextureOptions +{ + gboolean use_texture; + gdouble grain; +} GimpTextureOptions; + struct _GimpMixbrushOptions { GimpPaintOptions parent_instance; - gdouble main_color_density; /* 塗料の量 */ - gdouble main_color_rate; /* 塗料に前回の塗り色が混じる割合(実際は1-rate) */ - gdouble main_color_density_pressure_in1; - gdouble main_color_density_pressure_in2; - gdouble main_color_density_pressure_out1; - gdouble main_color_density_pressure_out2; - gdouble main_color_pressure_in1; - gdouble main_color_pressure_in2; - gdouble main_color_pressure_out1; - gdouble main_color_pressure_out2; - gdouble canvas_color_density; /* 地の色が混じる量 */ - gdouble canvas_color_rate; /* 着色前の地の色が混じる割合(実際は1-rate) */ - gdouble canvas_color_density_pressure_in1; - gdouble canvas_color_density_pressure_in2; - gdouble canvas_color_density_pressure_out1; - gdouble canvas_color_density_pressure_out2; - gdouble canvas_color_pressure_in1; - gdouble canvas_color_pressure_in2; - gdouble canvas_color_pressure_out1; - gdouble canvas_color_pressure_out2; - guint dryout; /* main_color_densityが完全に尽きる距離(pixel) */ - guint delay; - gboolean tail; - gboolean merged; - gboolean pigment; - GimpHiddenColor hidden_color; - gboolean remove_color; - guint sample_size_limit; - gboolean alpha_channel_mixing; + GimpTextureOptions *texture_options; + gdouble main_color_density; /* 塗料の量 */ + gdouble main_color_rate; /* 塗料に前回の塗り色が混じる割合(実際は1-rate) */ + gdouble main_color_density_pressure_in1; + gdouble main_color_density_pressure_in2; + gdouble main_color_density_pressure_out1; + gdouble main_color_density_pressure_out2; + gdouble main_color_pressure_in1; + gdouble main_color_pressure_in2; + gdouble main_color_pressure_out1; + gdouble main_color_pressure_out2; + gdouble canvas_color_density; /* 地の色が混じる量 */ + gdouble canvas_color_rate; /* 着色前の地の色が混じる割合(実際は1-rate) */ + gdouble canvas_color_density_pressure_in1; + gdouble canvas_color_density_pressure_in2; + gdouble canvas_color_density_pressure_out1; + gdouble canvas_color_density_pressure_out2; + gdouble canvas_color_pressure_in1; + gdouble canvas_color_pressure_in2; + gdouble canvas_color_pressure_out1; + gdouble canvas_color_pressure_out2; + guint dryout; /* main_color_densityが完全に尽きる距離(pixel) */ + guint delay; + gboolean tail; + gboolean merged; + gboolean pigment; + GimpHiddenColor hidden_color; + gboolean remove_color; + guint sample_size_limit; + gboolean alpha_channel_mixing; }; struct _GimpMixbrushOptionsClass --- gimp-2.4.3--/app/tools/gimpmixbrushtool.c Mon Jan 21 06:22:01 2008 +++ gimp-painter--2.4.3/app/tools/gimpmixbrushtool.c Mon Jan 21 05:15:59 2008 @@ -89,11 +89,29 @@ 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); + /* Texture configurations */ + { + table = gtk_table_new (3, 3, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 2); + mixbrush_frame = gimp_prop_expanding_frame_new (config, "use-texture", "Use texture", table, NULL); + + gimp_prop_scale_entry_new (config, "texture-grain", + GTK_TABLE (table), 0, 1, + _("Grain:"), + 0.01, 0.1, 2, + FALSE, -1.0, 1.0); + + mixbrush_box = gimp_prop_pattern_box_new (NULL, GIMP_CONTEXT (tool_options), 2, + "pattern-view-type", "pattern-view-size"); + gtk_table_attach (GTK_TABLE (table), mixbrush_box, 0, 3, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, + 0, 0); + gtk_widget_show (mixbrush_box); + + gtk_box_pack_start (GTK_BOX (vbox), mixbrush_frame, FALSE, FALSE, 0); + gtk_widget_show (mixbrush_frame); + } mixbrush_button = gimp_prop_check_button_new (config, "alpha-channel-mixing", _("Alpha channel mixing")); gtk_box_pack_start (GTK_BOX (vbox), mixbrush_button, FALSE, TRUE, 0);