--- gimp-painter--2.4.2/app/paint/gimpmixbrush.c Sat Dec 22 16:22:43 2007 +++ gimp-painter--2.4.3/app/paint/gimpmixbrush.c Sat Dec 22 15:01:16 2007 @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/*#define CHECK_TIME*/ #include "config.h" #include @@ -43,6 +44,10 @@ #include "gimpmixbrush.h" #include "gimpmixbrushoptions.h" +#ifdef GIMP_MIXBRUSH_COMPOSITE +#include "gimpmixbrush-composite.h" +#endif + #include "gimp-intl.h" @@ -128,10 +133,12 @@ static inline gdouble calc_pressure (gdouble value, PressureParams *params); +#ifndef GIMP_MIXBRUSH_COMPOSITE void paste_canvas (GimpPaintCore *core, GimpDrawable *drawable, GimpRGB *paint_color, gdouble opacity); +#endif @@ -169,6 +176,10 @@ { mixbrush->history = NULL; mixbrush->mask = NULL; + +#ifdef GIMP_MIXBRUSH_COMPOSITE + gimp_mixbrush_composite_init (); +#endif } static void @@ -193,9 +204,18 @@ GimpPaintState paint_state, guint32 time) { +#ifdef CHECK_TIME + GTimer *timer; + static gdouble total_time = 0; + static guint count = 0; +#endif switch (paint_state) { case GIMP_PAINT_STATE_INIT: +#ifdef CHECK_TIME + total_time = 0; + count = 0; +#endif gimp_mixbrush_start (paint_core, drawable, paint_options); GIMP_PAINT_CORE_CLASS (parent_class)->paint (paint_core, drawable, paint_options, @@ -203,10 +223,23 @@ break; case GIMP_PAINT_STATE_MOTION: +#ifdef CHECK_TIME + timer = g_timer_new (); + g_timer_start (timer); gimp_mixbrush_motion (paint_core, drawable, paint_options); + g_timer_stop (timer); + total_time += g_timer_elapsed (timer, NULL); + g_timer_destroy (timer); + count++; +#else + gimp_mixbrush_motion (paint_core, drawable, paint_options); +#endif break; case GIMP_PAINT_STATE_FINISH: +#ifdef CHECK_TIME + g_printerr ("average time:%f\n", total_time / count); +#endif gimp_mixbrush_finish (paint_core, drawable, paint_options); GIMP_PAINT_CORE_CLASS (parent_class)->paint (paint_core, drawable, paint_options, @@ -558,19 +591,6 @@ } #else - gimp_rgba_get_uchar (last_color, - &color_uchar[0], - &color_uchar[1], - &color_uchar[2], - &color_uchar[3]); - - /* Set the rounding error to mixbrush->error */ - mixbrush->error.r = last_color->r - color_uchar[0] / 255.0; - mixbrush->error.g = last_color->g - color_uchar[1] / 255.0; - mixbrush->error.b = last_color->b - color_uchar[2] / 255.0; - mixbrush->error.a = last_color->a - color_uchar[3] / 255.0; - - color_uchar[mixbrush->alpha_pix] = OPAQUE_OPACITY; #endif @@ -586,6 +606,20 @@ } else { + gimp_rgba_get_uchar (last_color, + &color_uchar[0], + &color_uchar[1], + &color_uchar[2], + &color_uchar[3]); + + /* Set the rounding error to mixbrush->error */ + mixbrush->error.r = last_color->r - color_uchar[0] / 255.0; + mixbrush->error.g = last_color->g - color_uchar[1] / 255.0; + mixbrush->error.b = last_color->b - color_uchar[2] / 255.0; + mixbrush->error.a = last_color->a - color_uchar[3] / 255.0; + + color_uchar[mixbrush->alpha_pix] = OPAQUE_OPACITY; + color_pixels (temp_buf_data (area), color_uchar, area->width * area->height, area->bytes); @@ -782,7 +816,7 @@ { rgb1.a = op1 / rgb1.a; /* factor */ rgb1.a = color1->a * rgb1.a + color2->a * (1.0 - rgb1.a); - rgb1.a *= op1 + (1.0 - op1) *op2; + rgb1.a *= op1 + (1.0 - op1) * op2; } } @@ -926,7 +960,212 @@ return CLAMP (value * params->out_factor + params->out_min, 0.0, 1.0); } +#if 1 +#ifndef GIMP_MIXBRUSH_COMPOSITE +void +paste_canvas (GimpPaintCore *core, + GimpDrawable *drawable, + GimpRGB *paint_color, + gdouble opacity) +{ + TempBuf *brush_mask = gimp_brush_core_get_brush_mask (GIMP_BRUSH_CORE (core), GIMP_BRUSH_SOFT); + TempBuf *canvas_buf = core->canvas_buf; + PixelRegion srcPR, maskPR; + gint x, y, off_x, off_y; + + if (!brush_mask || !canvas_buf || opacity == 0.0) + return; + + /* set undo blocks */ + gimp_paint_core_validate_undo_tiles (core, drawable, + canvas_buf->x, + canvas_buf->y, + canvas_buf->width, + canvas_buf->height); + + /* init the pixel regions */ + x = (gint) floor (core->cur_coords.x) - (brush_mask->width >> 1); + y = (gint) floor (core->cur_coords.y) - (brush_mask->height >> 1); + + off_x = (x < 0) ? -x : 0; + off_y = (y < 0) ? -y : 0; + + pixel_region_init (&srcPR, gimp_drawable_get_tiles (drawable), + canvas_buf->x, canvas_buf->y, + canvas_buf->width, canvas_buf->height, + TRUE); + + pixel_region_init_temp_buf (&maskPR, brush_mask, + off_x, off_y, + brush_mask->width, brush_mask->height); + + { /* _composite_* () */ + gpointer iter; + gint w, h; + gint src_bytes; + gint src_stride, mask_stride; + guchar *src_data, *_src_data; + 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); + + _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; + } + + 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; + + for (i = 0; i < h; i++) + { + _src_data = src_data; + _mask_data = mask_data; + + for (j = 0; j < w; j++) + { + gdouble op, mask_op, paint_color_op, canvas_color_op, src_op; + gdouble factor1, factor2; + gdouble component; +#if 0 + if (j == canvas_buf->width / 2 && i == canvas_buf->height / 2) + { + g_printerr ( "\nPos : %d %d\n", j, i); + g_printerr ( "Paint color: %f %f %f %f\n", _paint_color.r, _paint_color.g, _paint_color.b, paint_color->a); + g_printerr ( "Canvas color: %d %d %d %d\n", _src_data[0], _src_data[1], _src_data[2], _src_data[3]); + g_printerr ( "Opacity : %f\n", opacity); + } +#endif + 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; + + 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; + 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];*/ + } + /*npixels++;*/ + } + } +#if 0 + if (j == canvas_buf->width / 2 && i == canvas_buf->height / 2) + { + g_printerr ( "Result color: %d %d %d %d\n", _src_data[0], _src_data[1], _src_data[2], _src_data[3]); + } +#endif + _src_data += src_bytes; + _mask_data++; + } + src_data += src_stride; + mask_data += mask_stride; + } + } /* end of iteration */ + /*if (npixels) + { + error.r = (_error.r / npixels) / 255.0; + error.g = (_error.g / npixels) / 255.0; + error.b = (_error.b / npixels) / 255.0; + error.a = (_error.a / npixels) / 255.0; + 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);*/ + + 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, canvas_buf->x); + core->y1 = MIN (core->y1, canvas_buf->y); + core->x2 = MAX (core->x2, canvas_buf->x + canvas_buf->width) ; + core->y2 = MAX (core->y2, canvas_buf->y + canvas_buf->height) ; + + /* Update the drawable */ + gimp_drawable_update (drawable, + canvas_buf->x, + canvas_buf->y, + canvas_buf->width, + canvas_buf->height); +} +#endif +#else void paste_canvas (GimpPaintCore *core, GimpDrawable *drawable, @@ -1120,3 +1359,4 @@ gimp_paint_core_replace (core, &maskPR, drawable, 1.0, 1.0, GIMP_PAINT_INCREMENTAL); } +#endif