--- gimp-2.4.3-/app/core/core-types.h Tue Nov 20 18:30:56 2007 +++ gimp-painter--2.4.3/app/core/core-types.h Wed Jan 16 16:37:56 2008 @@ -185,6 +185,11 @@ gdouble xtilt; gdouble ytilt; gdouble wheel; + gdouble delta_time; + gdouble delta_x; + gdouble delta_y; + gdouble distance; + gdouble velocity; }; --- gimp-2.4.3-/app/display/gimpdisplayshell-callbacks.c Tue Dec 11 16:31:24 2007 +++ gimp-painter--2.4.3/app/display/gimpdisplayshell-callbacks.c Fri Jan 18 06:28:23 2008 @@ -79,6 +79,9 @@ #include "gimp-intl.h" +#define DEFAULT_EVENT_SMOOTHING 0.7 + + /* #define DEBUG_TOOL_EVENTS */ #ifdef DEBUG_TOOL_EVENTS @@ -909,7 +912,7 @@ &image_coords, time, state, display); - shell->last_motion_time = bevent->time; + shell->last_read_motion_time = bevent->time; } } break; @@ -1199,11 +1202,19 @@ gimp_display_shell_autoscroll_start (shell, state, mevent); } - if (gimp_tool_control_get_motion_mode (active_tool->control) == - GIMP_MOTION_MODE_EXACT && + /* gdk_device_get_history() has several quirks. First is + * that events with borderline timestamps at both ends + * are included. Because of that we need to add 1 to + * lower border. The second is due to poor X event + * resolution. We need to do -1 to ensure that the + * amount of events between timestamps is final or + * risk loosing some. + */ + if ((gimp_tool_control_get_motion_mode (active_tool->control) == + GIMP_MOTION_MODE_EXACT) && gdk_device_get_history (mevent->device, mevent->window, - shell->last_motion_time, - mevent->time, + shell->last_read_motion_time + 1, + mevent->time - 1, &history_events, &n_history_events)) { @@ -1236,33 +1247,61 @@ x, y, width, height); } - tool_manager_motion_active (gimp, - &image_coords, - history_events[i]->time, - state, - display); + /* Early removal of useless events saves CPU time. + */ + if (gimp_display_shell_eval_event (shell, + &image_coords, + DEFAULT_EVENT_SMOOTHING, + history_events[i]->time)) + { + tool_manager_motion_active (gimp, + &image_coords, + history_events[i]->time, + state, + display); + } + + shell->last_read_motion_time = history_events[i]->time; } gdk_device_free_history (history_events, n_history_events); } else { - tool_manager_motion_active (gimp, - &image_coords, time, state, - display); - } + /* Early removal of useless events saves CPU time. + */ + if (gimp_display_shell_eval_event (shell, + &image_coords, + DEFAULT_EVENT_SMOOTHING, + time)) + { + tool_manager_motion_active (gimp, + &image_coords, + time, + state, + display); + } - shell->last_motion_time = mevent->time; + shell->last_read_motion_time = time; + } } } if (! (state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK))) { - tool_manager_oper_update_active (gimp, - &image_coords, state, - shell->proximity, - display); + /* Early removal of useless events saves CPU time. + * Smoothing is 0.0 here for coasting. + */ + if (gimp_display_shell_eval_event (shell, &image_coords, 0.0, time)) + { + tool_manager_oper_update_active (gimp, + &image_coords, state, + shell->proximity, + display); + } + + shell->last_read_motion_time = time; } } break; --- gimp-2.4.3-/app/display/gimpdisplayshell-coords.c Tue Nov 20 18:31:08 2007 +++ gimp-painter--2.4.3/app/display/gimpdisplayshell-coords.c Fri Jan 18 06:25:03 2008 @@ -20,6 +20,8 @@ #include +#include "libgimpmath/gimpmath.h" + #include "display-types.h" #include "gimpdisplayshell.h" @@ -131,7 +133,8 @@ * requested axis does not exist. */ - if (gdk_device_get_axis (device, event->axes, GDK_AXIS_PRESSURE, &coords->pressure)) + if (gdk_device_get_axis (device, + event->axes, GDK_AXIS_PRESSURE, &coords->pressure)) coords->pressure = CLAMP (coords->pressure, GIMP_COORDS_MIN_PRESSURE, GIMP_COORDS_MAX_PRESSURE); else @@ -176,4 +179,149 @@ GdkModifierType *state) { gdk_device_get_state (device, shell->canvas->window, NULL, state); +} + +/** + * gimp_display_shell_eval_event: + * @shell: + * @coords: + * @inertia_factor: + * @time: + * + * This function evaluates the event to decide if the change is + * big enough to need handling and returns FALSE, if change is less + * than one image pixel or when smoothed event distance covers less + * than one pixel taking a whole lot of load off any draw tools that + * have no use for these sub-pixel events anyway. If the event is + * seen fit at first look, it is evaluated for speed and smoothed. + * Due to lousy time resolution of events pretty strong smoothing is + * applied to timestamps for sensible speed result. This function is + * also ideal for other event adjustment like pressure curve or + * calculating other derived dynamics factors like angular velocity + * calculation from tilt values, to allow for even more dynamic + * brushes. Calculated distance to last event is stored in GimpCoords + * because its a sideproduct of velocity calculation and is currently + * calculated in each tool. If they were to use this distance, more + * resouces on recalculating the same value would be saved. + * + * Return value: + **/ +gboolean +gimp_display_shell_eval_event (GimpDisplayShell *shell, + GimpCoords *coords, + gdouble inertia_factor, + guint32 time) +{ + const gdouble smooth_factor = 0.3; + guint32 thistime = time; + gdouble dist; + + if (shell->last_disp_motion_time == 0) + { + /* First pair is invalid to do any velocity calculation, + * so we apply constant values. + */ + coords->velocity = 100; + coords->delta_time = 0.001; + coords->distance = 1; + } + else + { + gdouble dx = coords->delta_x = shell->last_coords.x - coords->x; + gdouble dy = coords->delta_y = shell->last_coords.y - coords->y; + + /* Events with distances less than 1 in either motion direction + * are not worth handling. + */ + if (fabs (dx) < 1.0 && fabs (dy) < 1.0) + return FALSE; + + coords->delta_time = thistime - shell->last_disp_motion_time; + coords->delta_time = (shell->last_coords.delta_time * (1 - smooth_factor) + + coords->delta_time * smooth_factor); + coords->distance = dist = sqrt (SQR (dx) + SQR (dy)); + + /* If even smoothed time resolution does not allow to guess for speed, + * use last velocity. + */ + if ((coords->delta_time == 0)) + { + coords->velocity = shell->last_coords.velocity; + } + else + { + coords->velocity = + (coords->distance / (gdouble) coords->delta_time) / 10; + + /* A little smooth on this too, feels better in tools this way. */ + coords->velocity = (shell->last_coords.velocity * (1 - smooth_factor) + + coords->velocity * smooth_factor); + /* Speed needs upper limit */ + coords->velocity = MIN (coords->velocity, 1.0); + } + + if (inertia_factor > 0) + { + /* Apply smoothing to X and Y. */ + + /* This tells how far from the pointer can stray from the line */ + gdouble max_deviation = SQR (20 * inertia_factor); + gdouble cur_deviation = max_deviation; + gdouble sin_avg; + gdouble sin_old; + gdouble sin_new; + gdouble cos_avg; + gdouble cos_old; + gdouble cos_new; + gdouble new_x; + gdouble new_y; + + sin_new = coords->delta_x / coords->distance; + cos_old = shell->last_coords.delta_y / shell->last_coords.distance; + cos_avg = cos (acos (cos_old) * inertia_factor + + acos (cos_new) * (1 - inertia_factor)); + coords->delta_x = sin_avg * coords->distance; + coords->delta_y = cos_avg * coords->distance; + + new_x = (shell->last_coords.x - coords->delta_x) * 0.5 + coords->x * 0.5; + new_y = (shell->last_coords.y - coords->delta_y) * 0.5 + coords->y * 0.5; + + cur_deviation = SQR (coords->x-new_x) + SQR (coords->y-new_y); + + while (cur_deviation >= max_deviation) + { + new_x = new_x * 0.8 + coords->x * 0.2; + new_y = new_y * 0.8 + coords->y * 0.2; + + cur_deviation = (SQR (coords->x - new_x) + + SQR (coords->y - new_y)); + } + + coords->x = new_x; + coords->y = new_y; + + coords->delta_x = shell->last_coords.x - coords->x; + coords->delta_y = shell->last_coords.y - coords->y; + + /* Recalculate distance */ + coords->distance = sqrt (SQR (coords->delta_x) + + SQR (coords->delta_y)); + } + +#ifdef VERBOSE + g_printerr ("DIST: %f, DT:%f, Vel:%f, Press:%f,smooth_dd:%f, sf %f\n", + coords->distance, + coords->delta_time, + shell->last_coords.velocity, + coords->pressure, + coords->distance - dist, + inertia_factor); +#endif + + } + + shell->last_coords = *coords; + shell->last_disp_motion_time = time; + + return TRUE; } --- gimp-2.4.3-/app/display/gimpdisplayshell-coords.h Tue Nov 20 18:31:08 2007 +++ gimp-painter--2.4.3/app/display/gimpdisplayshell-coords.h Wed Jan 16 19:30:26 2008 @@ -38,6 +38,10 @@ void gimp_display_shell_get_device_state (GimpDisplayShell *shell, GdkDevice *device, GdkModifierType *state); +gboolean gimp_display_shell_eval_event (GimpDisplayShell *shell, + GimpCoords *coords, + gdouble inertia_factor, + guint32 time); #endif /* __GIMP_DISPLAY_SHELL_COORDS_H__ */ --- gimp-2.4.3-/app/display/gimpdisplayshell.h Tue Nov 20 18:31:08 2007 +++ gimp-painter--2.4.3/app/display/gimpdisplayshell.h Wed Jan 16 16:47:48 2008 @@ -174,13 +174,16 @@ gint scroll_start_x; gint scroll_start_y; gboolean button_press_before_focus; - guint32 last_motion_time; + guint32 last_disp_motion_time; /* previous time of a forwarded motion event */ + guint32 last_read_motion_time; GdkRectangle *highlight; /* in image coordinates, can be NULL */ GimpDrawable *mask; GimpChannelType mask_color; gpointer scroll_info; + + GimpCoords last_coords; /* last motion event */ }; struct _GimpDisplayShellClass --- gimp-2.4.3-/app/paint/gimpbrushcore.c Thu Jan 3 20:16:18 2008 +++ gimp-painter--2.4.3/app/paint/gimpbrushcore.c Fri Jan 11 06:19:45 2008 @@ -808,7 +808,8 @@ gdouble image_opacity, GimpLayerModeEffects paint_mode, GimpBrushApplicationMode brush_hardness, - GimpPaintApplicationMode mode) + GimpPaintApplicationMode mode, + gboolean reduce_update_freq) { TempBuf *brush_mask = gimp_brush_core_get_brush_mask (core, brush_hardness); @@ -836,7 +837,7 @@ gimp_paint_core_paste (paint_core, &brush_maskPR, drawable, brush_opacity, image_opacity, paint_mode, - mode); + mode, reduce_update_freq); } } @@ -850,7 +851,8 @@ gdouble brush_opacity, gdouble image_opacity, GimpBrushApplicationMode brush_hardness, - GimpPaintApplicationMode mode) + GimpPaintApplicationMode mode, + gboolean reduce_update_freq) { TempBuf *brush_mask = gimp_brush_core_get_brush_mask (core, brush_hardness); @@ -878,7 +880,7 @@ gimp_paint_core_replace (paint_core, &brush_maskPR, drawable, brush_opacity, image_opacity, - mode); + mode, reduce_update_freq); } } --- gimp-2.4.3-/app/paint/gimpbrushcore.h Thu Jan 3 20:16:18 2008 +++ gimp-painter--2.4.3/app/paint/gimpbrushcore.h Thu Jan 10 07:10:23 2008 @@ -112,13 +112,15 @@ gdouble image_opacity, GimpLayerModeEffects paint_mode, GimpBrushApplicationMode brush_hardness, - GimpPaintApplicationMode mode); + GimpPaintApplicationMode mode, + gboolean reduce_update_freq); void gimp_brush_core_replace_canvas (GimpBrushCore *core, GimpDrawable *drawable, gdouble brush_opacity, gdouble image_opacity, GimpBrushApplicationMode brush_hardness, - GimpPaintApplicationMode mode); + GimpPaintApplicationMode mode, + gboolean reduce_update_freq); void gimp_brush_core_color_area_with_pixmap (GimpBrushCore *core, --- gimp-2.4.3-/app/paint/gimpclone.c Tue Nov 20 18:31:16 2007 +++ gimp-painter--2.4.3/app/paint/gimpclone.c Thu Jan 10 07:14:32 2008 @@ -253,7 +253,8 @@ */ source_options->align_mode == GIMP_SOURCE_ALIGN_FIXED ? - GIMP_PAINT_INCREMENTAL : GIMP_PAINT_CONSTANT); + GIMP_PAINT_INCREMENTAL : GIMP_PAINT_CONSTANT, + paint_options->reduce_update_freq); } static void --- gimp-2.4.3-/app/paint/gimpconvolve.c Tue Nov 20 18:31:16 2007 +++ gimp-painter--2.4.3/app/paint/gimpconvolve.c Thu Jan 10 07:22:15 2008 @@ -211,7 +211,8 @@ MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), gimp_paint_options_get_brush_mode (paint_options), - GIMP_PAINT_INCREMENTAL); + GIMP_PAINT_INCREMENTAL, + paint_options->reduce_update_freq); } static void --- gimp-2.4.3-/app/paint/gimpdodgeburn.c Tue Nov 20 18:31:16 2007 +++ gimp-painter--2.4.3/app/paint/gimpdodgeburn.c Thu Jan 10 07:22:49 2008 @@ -242,7 +242,8 @@ MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), gimp_paint_options_get_brush_mode (paint_options), - GIMP_PAINT_CONSTANT); + GIMP_PAINT_CONSTANT, + paint_options->reduce_update_freq); g_free (temp_data); } --- gimp-2.4.3-/app/paint/gimperaser.c Tue Nov 20 18:31:16 2007 +++ gimp-painter--2.4.3/app/paint/gimperaser.c Thu Jan 10 07:14:55 2008 @@ -140,5 +140,6 @@ (options->anti_erase ? GIMP_ANTI_ERASE_MODE : GIMP_ERASE_MODE), gimp_paint_options_get_brush_mode (paint_options), - paint_options->application_mode); + paint_options->application_mode, + paint_options->reduce_update_freq); } --- gimp-2.4.3-/app/paint/gimpheal.c Tue Dec 11 16:31:24 2007 +++ gimp-painter--2.4.3/app/paint/gimpheal.c Thu Jan 10 07:23:11 2008 @@ -505,7 +505,8 @@ MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), gimp_paint_options_get_brush_mode (paint_options), - GIMP_PAINT_INCREMENTAL); + GIMP_PAINT_INCREMENTAL, + paint_options->reduce_update_freq); temp_buf_free (src); temp_buf_free (temp); --- gimp-2.4.3-/app/paint/gimpink.c Tue Nov 20 18:31:16 2007 +++ gimp-painter--2.4.3/app/paint/gimpink.c Thu Jan 10 07:11:54 2008 @@ -385,7 +385,8 @@ GIMP_OPACITY_OPAQUE, gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), - GIMP_PAINT_CONSTANT); + GIMP_PAINT_CONSTANT, + paint_options->reduce_update_freq); if (blob_union) g_free (blob_union); --- gimp-2.4.3-/app/paint/gimpink2.c Thu Jan 3 20:16:18 2008 +++ gimp-painter--2.4.3/app/paint/gimpink2.c Wed Jan 16 16:02:12 2008 @@ -78,18 +78,6 @@ 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); @@ -289,19 +277,13 @@ paint_core->cur_coords.pressure, paint_core->cur_coords.xtilt, paint_core->cur_coords.ytilt, - 10.0); + 100); 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; @@ -309,49 +291,12 @@ 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); + hist_add(ink, &paint_core->cur_coords, paint_core->cur_coords.velocity * 100); average_hist = hist_result(ink, options); blob = ink2_pen_ellipse (options, average_hist.x, @@ -359,7 +304,7 @@ paint_core->cur_coords.pressure, paint_core->cur_coords.xtilt, paint_core->cur_coords.ytilt, - velocity); + paint_core->cur_coords.velocity * 100); ink->last_point = average_hist; } else @@ -370,7 +315,7 @@ paint_core->cur_coords.pressure, paint_core->cur_coords.xtilt, paint_core->cur_coords.ytilt, - velocity); + paint_core->cur_coords.velocity * 100); } blob_union = blob_convex_union (ink->last_blob, blob); @@ -425,7 +370,8 @@ GIMP_OPACITY_OPAQUE, gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), - GIMP_PAINT_CONSTANT); + GIMP_PAINT_CONSTANT, + paint_options->reduce_update_freq); if (blob_union) g_free (blob_union); @@ -505,7 +451,7 @@ tscale_c, tscale_s, x, y); #endif - aspect = sqrt (x * x + y * y); + aspect = sqrt (SQR (x) + SQR (y)); if (aspect != 0) { @@ -550,83 +496,6 @@ } -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 @@ -732,7 +601,11 @@ * do things. But it wouldn't be hard to implement at all. */ -enum { ROW_START, ROW_STOP }; +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 @@ -742,12 +615,12 @@ gint n) { gint i, j, k; - gint tmp1, tmp2; for (i = 2; i < 2 * n; i += 2) { - tmp1 = data[i]; - tmp2 = data[i + 1]; + gint tmp1 = data[i]; + gint tmp2 = data[i + 1]; + j = 0; while (data[j] < tmp1) j += 2; @@ -893,23 +766,19 @@ render_blob (Blob *blob, PixelRegion *dest) { - gint i; - gint h; - guchar *s; gpointer pr; for (pr = pixel_regions_register (1, dest); pr != NULL; pr = pixel_regions_process (pr)) { - h = dest->h; - s = dest->data; + guchar *d = dest->data; + gint h = dest->h; + gint y; - for (i=0; irowstride) { - render_blob_line (blob, s, - dest->x, dest->y + i, dest->w); - s += dest->rowstride; + render_blob_line (blob, d, dest->x, dest->y + y, dest->w); } } } --- gimp-2.4.3-/app/paint/gimpink2.h Thu Jan 3 20:16:18 2008 +++ gimp-painter--2.4.3/app/paint/gimpink2.h Wed Jan 16 16:05:32 2008 @@ -24,8 +24,6 @@ #include "gimpink-blob.h" -#define INK2_DIST_SMOOTHER_BUFFER 10 -#define INK2_TIME_SMOOTHER_BUFFER 10 #define INK2_HISTORY_BUFFER 20 @@ -48,24 +46,12 @@ 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 --- gimp-2.4.3-/app/paint/gimpink2undo.c Thu Jan 3 20:16:18 2008 +++ gimp-painter--2.4.3/app/paint/gimpink2undo.c Wed Jan 16 16:13:16 2008 @@ -82,20 +82,6 @@ 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; } @@ -112,44 +98,10 @@ { 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; } } --- gimp-2.4.3-/app/paint/gimpink2undo.h Thu Jan 3 20:16:18 2008 +++ gimp-painter--2.4.3/app/paint/gimpink2undo.h Wed Jan 16 16:10:40 2008 @@ -39,16 +39,6 @@ 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 --- gimp-2.4.3-/app/paint/gimpmixbrush.c Fri Jan 11 06:06:46 2008 +++ gimp-painter--2.4.3/app/paint/gimpmixbrush.c Mon Jan 21 04:39:09 2008 @@ -17,7 +17,7 @@ */ /*#define CHECK_TIME*/ -#define LOWER_UPDATE + #include "config.h" #include @@ -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" @@ -61,7 +62,6 @@ gdouble pixel_dist; GimpRGB color; gdouble opacity; - guint32 time; } CoordsHistory; @@ -73,24 +73,13 @@ GimpPaintState paint_state, guint32 time); -#ifdef LOWER_UPDATE static void gimp_mixbrush_motion (GimpPaintCore *paint_core, GimpDrawable *drawable, - GimpPaintOptions *paint_options, - guint32 time); -static void gimp_mixbrush_start (GimpPaintCore *paint_core, - GimpDrawable *drawable, - GimpPaintOptions *paint_options, - guint32 time); -#else -static void gimp_mixbrush_start (GimpPaintCore *paint_core, - GimpDrawable *drawable, GimpPaintOptions *paint_options); -static void gimp_mixbrush_motion (GimpPaintCore *paint_core, +static void gimp_mixbrush_start (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options); -#endif static void gimp_mixbrush_finish (GimpPaintCore *paint_core, GimpDrawable *drawable, @@ -104,14 +93,14 @@ static void coords_history_free (CoordsHistory *history, gpointer dummy); -static inline gboolean get_canvas_color (GimpImage *image, - GimpDrawable *drawable, - GimpPaintCore *paint_core, - gint x, - gint y, - guint sample_size_limit, - gboolean merged, - GimpRGB *color); +static inline gboolean get_canvas_color (GimpImage *image, + GimpDrawable *drawable, + GimpPaintCore *paint_core, + gint x, + gint y, + guint sample_size_limit, + gboolean merged, + GimpRGB *color); static inline gboolean pick_up_avarage_color (GimpPickable *pickable, GimpBrushCore *brush_core, @@ -149,13 +138,31 @@ #ifndef GIMP_MIXBRUSH_COMPOSITE void paste_canvas (GimpPaintCore *core, GimpDrawable *drawable, + GimpPattern *texture, GimpRGB *paint_color, - gdouble opacity); -#endif - -#ifdef LOWER_UPDATE -static inline void update_drawable (GimpMixbrush *mixbrush, - GimpDrawable *drawable); + 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 @@ -233,11 +240,7 @@ total_time = 0; count = 0; #endif -#ifdef LOWER_UPDATE - gimp_mixbrush_start (paint_core, drawable, paint_options, time); -#else gimp_mixbrush_start (paint_core, drawable, paint_options); -#endif GIMP_PAINT_CORE_CLASS (parent_class)->paint (paint_core, drawable, paint_options, paint_state, time); @@ -247,22 +250,14 @@ #ifdef CHECK_TIME timer = g_timer_new (); g_timer_start (timer); -#ifdef LOWER_UPDATE - gimp_mixbrush_motion (paint_core, drawable, paint_options, time); -#else gimp_mixbrush_motion (paint_core, drawable, paint_options); -#endif g_timer_stop (timer); total_time += g_timer_elapsed (timer, NULL); g_timer_destroy (timer); count++; #else -#ifdef LOWER_UPDATE - gimp_mixbrush_motion (paint_core, drawable, paint_options, time); -#else gimp_mixbrush_motion (paint_core, drawable, paint_options); #endif -#endif break; case GIMP_PAINT_STATE_FINISH: @@ -280,18 +275,10 @@ } } -#ifdef LOWER_UPDATE -static void -gimp_mixbrush_start (GimpPaintCore *paint_core, - GimpDrawable *drawable, - GimpPaintOptions *paint_options, - guint32 time) -#else static void gimp_mixbrush_start (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options) -#endif { GimpMixbrush *mixbrush = GIMP_MIXBRUSH (paint_core); GimpMixbrushOptions *mixbrush_options = GIMP_MIXBRUSH_OPTIONS (paint_options); @@ -401,15 +388,6 @@ /* Reset the rounding error */ gimp_rgba_set (&mixbrush->error, 0, 0, 0, 0); - -#ifdef LOWER_UPDATE - mixbrush->update_count = 0; - mixbrush->update_is_done = FALSE; - mixbrush->_x1 = mixbrush->_x2 = paint_core->cur_coords.x; - mixbrush->_y1 = mixbrush->_y2 = paint_core->cur_coords.y; - mixbrush->time = 100; - mixbrush->last_time = time; -#endif } static void @@ -429,11 +407,6 @@ while (mixbrush->history) gimp_mixbrush_paste_canvas (paint_core, drawable, paint_options); -#ifdef LOWER_UPDATE - if (! mixbrush->update_is_done) - update_drawable (mixbrush, drawable); -#endif - if (mixbrush->mask) { temp_buf_free (mixbrush->mask); @@ -441,18 +414,10 @@ } } -#ifdef LOWER_UPDATE -static void -gimp_mixbrush_motion (GimpPaintCore *paint_core, - GimpDrawable *drawable, - GimpPaintOptions *paint_options, - guint32 time) -#else static void gimp_mixbrush_motion (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options) -#endif { GimpImage *image; GimpMixbrush *mixbrush = GIMP_MIXBRUSH (paint_core); @@ -470,9 +435,6 @@ history->coords = paint_core->cur_coords; history->prev_coords = paint_core->last_coords; history->pixel_dist = paint_core->pixel_dist; -#ifdef LOWER_UPDATE - history->time = time; -#endif /* Pick up the raw canvas color */ get_canvas_color (image, drawable, paint_core, @@ -513,12 +475,6 @@ history = mixbrush->history->data; mixbrush->history = g_list_delete_link (mixbrush->history, mixbrush->history); - -#ifdef LOWER_UPDATE - mixbrush->time = (mixbrush->time + history->time - mixbrush->last_time) / 2; - mixbrush->last_time = history->time; - //g_printerr ("time = %d\n", mixbrush->time); -#endif if (history->opacity != 0.0) { @@ -662,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); + 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 { @@ -698,7 +669,8 @@ gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), gimp_paint_options_get_brush_mode (paint_options), - paint_appl_mode); + paint_appl_mode, + paint_options->reduce_update_freq); } } paint_core->cur_coords = orig_coords; @@ -1032,14 +1004,18 @@ void paste_canvas (GimpPaintCore *core, GimpDrawable *drawable, + GimpPattern *texture, GimpRGB *paint_color, - gdouble opacity) + gdouble opacity, + gdouble grain, + gboolean reduce_update_freq) { TempBuf *brush_mask = gimp_brush_core_get_brush_mask (GIMP_BRUSH_CORE (core), GIMP_BRUSH_SOFT); TempBuf *canvas_buf = core->canvas_buf; 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; @@ -1063,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; @@ -1072,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) @@ -1089,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++) { @@ -1110,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) { @@ -1164,7 +1249,6 @@ _src_data[2] = component + .5; /*_error.b += component - _src_data[2];*/ } - /*npixels++;*/ } } #if 0 @@ -1189,87 +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 */ -#ifdef LOWER_UPDATE - { - GimpMixbrush *mixbrush = GIMP_MIXBRUSH (core); - gfloat n; + texture_data = temp_buf_data (texture_buf); + texture_stride = texture_buf->width * texture_buf->bytes; - n = MAX (2.0 - log10f (mixbrush->time), 0) * 2.0; - n *= log10f ((c_w + c_h) / 2) + 1.0; - //g_printerr ("time = %d, size = %d, n = %d\n\n", mixbrush->time, c_w, (gint)n); + 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; - if (mixbrush->update_count) - { - mixbrush->_x1 = MIN (mixbrush->_x1, c_x); - mixbrush->_y1 = MIN (mixbrush->_y1, c_y); - mixbrush->_x2 = MAX (mixbrush->_x2, c_x + c_w - 1) ; - mixbrush->_y2 = MAX (mixbrush->_y2, c_y + c_h - 1) ; - } - else - { - mixbrush->_x1 = c_x; - mixbrush->_x2 = c_x + c_w - 1; - mixbrush->_y1 = c_y; - mixbrush->_y2 = c_y + c_h - 1; - } + /* calc origin of texture buffer */ + texture_off_x = drawable_x + x + maskPR->x; + texture_off_y = drawable_y + y + maskPR->y; - if (++mixbrush->update_count >= (gint)n) - { - mixbrush->update_count = 0; - mixbrush->update_is_done = TRUE; + src_data = srcPR->data; + mask_data = maskPR->data; + w = maskPR->w; + h = maskPR->h; + src_stride = srcPR->rowstride; + mask_stride = maskPR->rowstride; - update_drawable (mixbrush, drawable); - } - else - mixbrush->update_is_done = FALSE; - } -#else - gimp_drawable_update (drawable, c_x, c_y, c_w, c_h); -#endif -} -#endif + for (i = 0; i < h; i++, texture_off_y++) + { + _src_data = src_data; + _mask_data = mask_data; -#ifdef LOWER_UPDATE -static inline void update_drawable (GimpMixbrush *mixbrush, - GimpDrawable *drawable) -{ - gimp_drawable_update (drawable, - mixbrush->_x1, - mixbrush->_y1, - mixbrush->_x2 - mixbrush->_x1 + 1, - mixbrush->_y2 - mixbrush->_y1 + 1); + 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/gimpmixbrush.h Fri Jan 11 06:06:46 2008 +++ gimp-painter--2.4.3/app/paint/gimpmixbrush.h Tue Jan 8 05:06:59 2008 @@ -63,16 +63,6 @@ GimpRGB error; GList *history; gboolean use_alt_alpha_op; -#ifdef LOWER_UPDATE - guint32 time; - guint32 last_time; - gint update_count; - gboolean update_is_done; - gint _x1; - gint _x2; - gint _y1; - gint _y2; -#endif }; struct _GimpMixbrushClass --- gimp-2.4.3-/app/paint/gimpmixbrushoptions.c Thu Jan 3 20:16:18 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 Thu Jan 3 20:16:18 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/paint/gimppaintbrush.c Thu Jan 3 20:16:18 2008 +++ gimp-painter--2.4.3/app/paint/gimppaintbrush.c Thu Jan 10 07:15:20 2008 @@ -179,5 +179,6 @@ gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), gimp_paint_options_get_brush_mode (paint_options), - paint_appl_mode); + paint_appl_mode, + paint_options->reduce_update_freq); } --- gimp-2.4.3-/app/paint/gimppaintcore.c Thu Jan 3 20:16:18 2008 +++ gimp-painter--2.4.3/app/paint/gimppaintcore.c Fri Jan 18 18:22:49 2008 @@ -104,6 +104,9 @@ gdouble paint_opacity); static void canvas_tiles_to_canvas_buf (GimpPaintCore *core); +static inline gdouble drawable_update_reduced_freq (GimpDrawable *drawable, + GimpPaintCore *core); + G_DEFINE_TYPE (GimpPaintCore, gimp_paint_core, GIMP_TYPE_OBJECT) @@ -321,6 +324,13 @@ paint_options, paint_state, time); + if (paint_state == GIMP_PAINT_STATE_FINISH && ! core->updated) + gimp_drawable_update (drawable, + core->_x1, + core->_y1, + core->_x2 - core->_x1 + 1, + core->_y2 - core->_y1 + 1); + core_class->post_paint (core, drawable, paint_options, paint_state, time); @@ -798,7 +808,8 @@ gdouble paint_opacity, gdouble image_opacity, GimpLayerModeEffects paint_mode, - GimpPaintApplicationMode mode) + GimpPaintApplicationMode mode, + gboolean reduce_update_freq) { TileManager *alt = NULL; PixelRegion srcPR; @@ -992,11 +1003,14 @@ core->y2 = MAX (core->y2, core->canvas_buf->y + core->canvas_buf->height); /* Update the drawable */ - gimp_drawable_update (drawable, - core->canvas_buf->x, - core->canvas_buf->y, - core->canvas_buf->width, - core->canvas_buf->height); + if (reduce_update_freq) + drawable_update_reduced_freq (drawable, core); + else + gimp_drawable_update (drawable, + core->canvas_buf->x, + core->canvas_buf->y, + core->canvas_buf->width, + core->canvas_buf->height); } /* This works similarly to gimp_paint_core_paste. However, instead of @@ -1013,7 +1027,8 @@ GimpDrawable *drawable, gdouble paint_opacity, gdouble image_opacity, - GimpPaintApplicationMode mode) + GimpPaintApplicationMode mode, + gboolean reduce_update_freq) { PixelRegion srcPR; @@ -1022,7 +1037,8 @@ gimp_paint_core_paste (core, paint_maskPR, drawable, paint_opacity, image_opacity, GIMP_NORMAL_MODE, - mode); + mode, + reduce_update_freq); return; } @@ -1081,15 +1097,19 @@ /* 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) ; + 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 drawable */ - gimp_drawable_update (drawable, - core->canvas_buf->x, - core->canvas_buf->y, - core->canvas_buf->width, - core->canvas_buf->height); + if (reduce_update_freq) + drawable_update_reduced_freq (drawable, core); + else + gimp_drawable_update (drawable, + core->canvas_buf->x, + core->canvas_buf->y, + core->canvas_buf->width, + core->canvas_buf->height); + } static void @@ -1255,4 +1275,48 @@ } } } +} + + +static inline gdouble +drawable_update_reduced_freq (GimpDrawable *drawable, + GimpPaintCore *core) +{ + 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, 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 - 1); + core->_y2 = MAX (core->_y2, core->canvas_buf->y + core->canvas_buf->height - 1); + } + else + { + core->_x1 = core->canvas_buf->x; + core->_x2 = core->canvas_buf->x + core->canvas_buf->width - 1; + core->_y1 = core->canvas_buf->y; + core->_y2 = core->canvas_buf->y + core->canvas_buf->height - 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; } --- gimp-2.4.3-/app/paint/gimppaintcore.h Thu Jan 3 20:16:18 2008 +++ gimp-painter--2.4.3/app/paint/gimppaintcore.h Fri Jan 18 18:22:49 2008 @@ -66,6 +66,12 @@ TempBuf *orig_buf; /* the unmodified drawable pixels */ TempBuf *orig_proj_buf; /* the unmodified projection pixels */ TempBuf *canvas_buf; /* the buffer to paint pixels to */ + + /* to reduce update frequency */ + gint update_count; + gboolean updated; + gint _x1, _y1; + gint _x2, _y2; }; struct _GimpPaintCoreClass @@ -159,13 +165,15 @@ gdouble paint_opacity, gdouble image_opacity, GimpLayerModeEffects paint_mode, - GimpPaintApplicationMode mode); + GimpPaintApplicationMode mode, + gboolean reduce_update_freq); void gimp_paint_core_replace (GimpPaintCore *core, PixelRegion *paint_maskPR, GimpDrawable *drawable, gdouble paint_opacity, gdouble image_opacity, - GimpPaintApplicationMode mode); + GimpPaintApplicationMode mode, + gboolean reduce_update_freq); void gimp_paint_core_validate_undo_tiles (GimpPaintCore *core, GimpDrawable *drawable, @@ -184,6 +192,22 @@ gint y, gint w, gint h); + + +/* Utility function(s) */ +static inline gdouble faster_pow (gdouble a, gdouble b) +{ + guchar n[8] = "\0\0\0\0\0\0\0\0"; + guint32 i; + + (*((gdouble *)n)) = a; + i = (*((guint64 *)n)) >> 32; + + i = (guint32)(b * ((gint32)i - 1072632447) + 1072632447); + (*((guint64 *)n)) = (guint64)i << 32; + + return (*((gdouble *)n)); +} #endif /* __GIMP_PAINT_CORE_H__ */ --- gimp-2.4.3-/app/paint/gimppaintoptions.c Thu Jan 3 20:16:18 2008 +++ gimp-painter--2.4.3/app/paint/gimppaintoptions.c Thu Jan 10 02:50:26 2008 @@ -60,6 +60,8 @@ #define DEFAULT_GRADIENT_LENGTH 100.0 #define DEFAULT_GRADIENT_UNIT GIMP_UNIT_PIXEL +#define DEFAULT_REDUCE_UPDATE_FREQ FALSE + enum { @@ -92,7 +94,9 @@ PROP_PATTERN_VIEW_TYPE, PROP_PATTERN_VIEW_SIZE, PROP_GRADIENT_VIEW_TYPE, - PROP_GRADIENT_VIEW_SIZE + PROP_GRADIENT_VIEW_SIZE, + + PROP_REDUCE_UPDATE_FREQ }; @@ -257,6 +261,11 @@ GIMP_VIEWABLE_MAX_BUTTON_SIZE, GIMP_VIEW_SIZE_LARGE, GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_REDUCE_UPDATE_FREQ, + "reduce-update-frequency", NULL, + DEFAULT_REDUCE_UPDATE_FREQ, + GIMP_PARAM_STATIC_STRINGS); } static void @@ -398,6 +407,10 @@ options->gradient_view_size = g_value_get_int (value); break; + case PROP_REDUCE_UPDATE_FREQ: + options->reduce_update_freq = g_value_get_boolean (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -514,6 +527,10 @@ break; case PROP_GRADIENT_VIEW_SIZE: g_value_set_int (value, options->gradient_view_size); + break; + + case PROP_REDUCE_UPDATE_FREQ: + g_value_set_boolean (value, options->reduce_update_freq); break; default: --- gimp-2.4.3-/app/paint/gimppaintoptions.h Thu Jan 3 20:16:18 2008 +++ gimp-painter--2.4.3/app/paint/gimppaintoptions.h Thu Jan 10 02:41:43 2008 @@ -104,6 +104,8 @@ GimpViewSize pattern_view_size; GimpViewType gradient_view_type; GimpViewSize gradient_view_size; + + gboolean reduce_update_freq; }; struct _GimpPaintOptionsClass --- gimp-2.4.3-/app/paint/gimpsmudge.c Tue Nov 20 18:31:16 2007 +++ gimp-painter--2.4.3/app/paint/gimpsmudge.c Thu Jan 10 07:23:35 2008 @@ -312,7 +312,8 @@ MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), gimp_paint_options_get_brush_mode (paint_options), - GIMP_PAINT_INCREMENTAL); + GIMP_PAINT_INCREMENTAL, + paint_options->reduce_update_freq); } static void --- gimp-2.4.3-/app/tools/gimpmixbrushtool.c Thu Jan 3 20:16:18 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); --- gimp-2.4.3-/app/tools/gimppaintoptions-gui.c Thu Jan 3 20:16:18 2008 +++ gimp-painter--2.4.3/app/tools/gimppaintoptions-gui.c Thu Jan 10 03:00:10 2008 @@ -212,6 +212,11 @@ gtk_widget_show (frame); } + button = gimp_prop_check_button_new (config, "reduce-update-frequency", + _("Reduce update frequency")); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_widget_show (button); + return vbox; }