gimp r24607 - in trunk: . app/core app/display app/paint
- From: neo svn gnome org
- To: svn-commits-list gnome org
- Subject: gimp r24607 - in trunk: . app/core app/display app/paint
- Date: Mon, 14 Jan 2008 20:34:38 +0000 (GMT)
Author: neo
Date: Mon Jan 14 20:34:37 2008
New Revision: 24607
URL: http://svn.gnome.org/viewvc/gimp?rev=24607&view=rev
Log:
2008-01-14 Sven Neumann <sven gimp org>
* app/core/core-types.h
* app/display/gimpdisplayshell-callbacks.c
* app/display/gimpdisplayshell-coords.[ch]
* app/display/gimpdisplayshell.h
* app/paint/gimpink.[ch]
* app/paint/gimpinkundo.[ch]: applied patch from Alexia Death
that
adds an event evaluation function that decides if an event is
needed or can be discarded. As a side-product some useful
dynamics
parameters like velocity are added to the GimpCoords struct. The
Ink tool is changed to use this information. See bug #508639.
Modified:
trunk/ChangeLog
trunk/app/core/core-types.h
trunk/app/display/gimpdisplayshell-callbacks.c
trunk/app/display/gimpdisplayshell-coords.c
trunk/app/display/gimpdisplayshell-coords.h
trunk/app/display/gimpdisplayshell.h
trunk/app/paint/gimpink.c
trunk/app/paint/gimpink.h
trunk/app/paint/gimpinkundo.c
trunk/app/paint/gimpinkundo.h
Modified: trunk/app/core/core-types.h
==============================================================================
--- trunk/app/core/core-types.h (original)
+++ trunk/app/core/core-types.h Mon Jan 14 20:34:37 2008
@@ -190,6 +190,11 @@
gdouble xtilt;
gdouble ytilt;
gdouble wheel;
+ gdouble delta_time;
+ gdouble delta_x;
+ gdouble delta_y;
+ gdouble distance;
+ gdouble velocity;
};
Modified: trunk/app/display/gimpdisplayshell-callbacks.c
==============================================================================
--- trunk/app/display/gimpdisplayshell-callbacks.c (original)
+++ trunk/app/display/gimpdisplayshell-callbacks.c Mon Jan 14 20:34:37 2008
@@ -902,7 +902,7 @@
&image_coords,
time, state, display);
- shell->last_motion_time = bevent->time;
+ shell->last_read_motion_time = bevent->time;
}
}
break;
@@ -1182,7 +1182,7 @@
GdkTimeCoord **history_events;
gint n_history_events;
- /* if the first mouse button is down, check for automatic
+ /* if the first mouse button is down, check for automatic
* scrolling...
*/
if ((mevent->x < 0 ||
@@ -1194,11 +1194,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))
{
@@ -1206,6 +1214,7 @@
for (i = 0; i < n_history_events; i++)
{
+
gimp_display_shell_get_time_coords (shell,
mevent->device,
history_events[i],
@@ -1231,33 +1240,71 @@
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.
+ * Defaulting smoothing to 0.4.
+ */
+ if (gimp_display_shell_eval_event (shell,
+ &image_coords, 0.4,
+ history_events[i]->time))
+ {
+ tool_manager_motion_active (gimp,
+ &image_coords,
+ history_events[i]->time,
+ state,
+ display);
+
+ shell->last_coords = image_coords;
+ shell->last_disp_motion_time = history_events[i]->time;
+ }
+
+ 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.
+ * Defaulting smoothing to 0.4.
+ */
+ if (gimp_display_shell_eval_event (shell,
+ &image_coords, 0.4,
+ time))
+ {
+ tool_manager_motion_active (gimp,
+ &image_coords,
+ time,
+ state,
+ display);
+
+ shell->last_coords = image_coords;
+ shell->last_disp_motion_time = time;
+ }
- 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 coasting to avoid unpredicted jumps when making contact.
+ * This may need a different solution but cant properly test it without
+ * adjustment.
+ */
+ if (gimp_display_shell_eval_event (shell, &image_coords, 0.4, time))
+ {
+ tool_manager_oper_update_active (gimp,
+ &image_coords, state,
+ shell->proximity,
+ display);
+ shell->last_coords = image_coords;
+ shell->last_disp_motion_time = time;
+ }
+
+ shell->last_read_motion_time = time;
}
}
break;
Modified: trunk/app/display/gimpdisplayshell-coords.c
==============================================================================
--- trunk/app/display/gimpdisplayshell-coords.c (original)
+++ trunk/app/display/gimpdisplayshell-coords.c Mon Jan 14 20:34:37 2008
@@ -20,6 +20,8 @@
#include <gtk/gtk.h>
+#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
@@ -177,3 +180,127 @@
{
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)
+{
+ guint32 thistime = time;
+ gdouble dist;
+ gdouble xy_sfactor = 0;
+ const gdouble smooth_factor = 0.3;
+
+ 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 = 0;
+
+ shell->last_coords = *coords;
+ }
+ 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.
+ *
+ * The very high velocity values (yes, thats around 25
+ * according to tests) happen at great zoom outs and scream
+ * for heavyhanded smooth so I made it automatic. This
+ * should be bound to zoom level once theres a GUI foob to
+ * adjust smooth or disabled completely.
+ */
+
+ /*Apply smoothing to X and Y.
+ Smooth is dampened for high speeds to minimize the whip effect.*/
+ xy_sfactor = inertia_factor - inertia_factor * fabs (coords->velocity);
+ coords->x = shell->last_coords.x - (shell->last_coords.delta_x * xy_sfactor
+ + coords->delta_x * (1 - xy_sfactor));
+ coords->y = shell->last_coords.y - (shell->last_coords.delta_y * xy_sfactor
+ + coords->delta_y * (1 - xy_sfactor));
+
+ /* Recalculate distance */
+ coords->distance = sqrt ((shell->last_coords.x - coords->x) *
+ (shell->last_coords.x - coords->x) +
+ (shell->last_coords.y - coords->y) *
+ (shell->last_coords.y - coords->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,
+ xy_sfactor);
+#endif
+
+ }
+
+ return TRUE;
+}
Modified: trunk/app/display/gimpdisplayshell-coords.h
==============================================================================
--- trunk/app/display/gimpdisplayshell-coords.h (original)
+++ trunk/app/display/gimpdisplayshell-coords.h Mon Jan 14 20:34:37 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__ */
Modified: trunk/app/display/gimpdisplayshell.h
==============================================================================
--- trunk/app/display/gimpdisplayshell.h (original)
+++ trunk/app/display/gimpdisplayshell.h Mon Jan 14 20:34:37 2008
@@ -178,13 +178,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
Modified: trunk/app/paint/gimpink.c
==============================================================================
--- trunk/app/paint/gimpink.c (original)
+++ trunk/app/paint/gimpink.c Mon Jan 14 20:34:37 2008
@@ -77,18 +77,6 @@
gdouble ytilt,
gdouble velocity);
-static void time_smoother_add (GimpInk *ink,
- guint32 value);
-static guint32 time_smoother_result (GimpInk *ink);
-static void time_smoother_init (GimpInk *ink,
- guint32 initval);
-
-static void dist_smoother_add (GimpInk *ink,
- gdouble value);
-static gdouble dist_smoother_result (GimpInk *ink);
-static void dist_smoother_init (GimpInk *ink,
- gdouble initval);
-
static void render_blob (Blob *blob,
PixelRegion *dest);
@@ -270,67 +258,25 @@
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;
-
blob_to_render = ink->last_blob;
}
else
{
Blob *blob;
- gdouble dist;
- gdouble velocity;
- guint32 lasttime = ink->last_time;
- guint32 thistime;
-
- 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));
-
blob = ink_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);
+ paint_core->cur_coords.velocity * 100);
blob_union = blob_convex_union (ink->last_blob, blob);
g_free (ink->last_blob);
@@ -510,84 +456,6 @@
}
-static void
-time_smoother_init (GimpInk *ink,
- guint32 initval)
-{
- gint i;
-
- ink->ts_index = 0;
-
- for (i = 0; i < TIME_SMOOTHER_BUFFER; i++)
- ink->ts_buffer[i] = initval;
-}
-
-static guint32
-time_smoother_result (GimpInk *ink)
-{
- guint64 result = 0;
- gint i;
-
- for (i = 0; i < TIME_SMOOTHER_BUFFER; i++)
- result += ink->ts_buffer[i];
-
- return (result / (guint64) TIME_SMOOTHER_BUFFER);
-}
-
-static void
-time_smoother_add (GimpInk *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 == TIME_SMOOTHER_BUFFER)
- ink->ts_index = 0;
-}
-
-
-static void
-dist_smoother_init (GimpInk *ink,
- gdouble initval)
-{
- gint i;
-
- ink->dt_index = 0;
-
- for (i = 0; i < DIST_SMOOTHER_BUFFER; i++)
- ink->dt_buffer[i] = initval;
-}
-
-static gdouble
-dist_smoother_result (GimpInk *ink)
-{
- gint i;
- gdouble result = 0.0;
-
- for (i = 0; i < DIST_SMOOTHER_BUFFER; i++)
- result += ink->dt_buffer[i];
-
- return (result / (gdouble) DIST_SMOOTHER_BUFFER);
-}
-
-static void
-dist_smoother_add (GimpInk *ink,
- gdouble value)
-{
- ink->dt_buffer[ink->dt_index++] = value;
-
- if (ink->dt_index == DIST_SMOOTHER_BUFFER)
- ink->dt_index = 0;
-}
-
-
/*********************************/
/* Rendering functions */
/*********************************/
Modified: trunk/app/paint/gimpink.h
==============================================================================
--- trunk/app/paint/gimpink.h (original)
+++ trunk/app/paint/gimpink.h Mon Jan 14 20:34:37 2008
@@ -24,10 +24,6 @@
#include "gimpink-blob.h"
-#define DIST_SMOOTHER_BUFFER 10
-#define TIME_SMOOTHER_BUFFER 10
-
-
#define GIMP_TYPE_INK (gimp_ink_get_type ())
#define GIMP_INK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_INK, GimpInk))
#define GIMP_INK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_INK, GimpInkClass))
@@ -46,18 +42,6 @@
Blob *cur_blob; /* current blob */
Blob *last_blob; /* blob for last cursor position */
-
- /* circular distance history buffer */
- gdouble dt_buffer[DIST_SMOOTHER_BUFFER];
- gint dt_index;
-
- /* circular timing history buffer */
- guint32 ts_buffer[TIME_SMOOTHER_BUFFER];
- gint ts_index;
-
- guint32 last_time; /* previous time of a motion event */
-
- gboolean init_velocity;
};
struct _GimpInkClass
Modified: trunk/app/paint/gimpinkundo.c
==============================================================================
--- trunk/app/paint/gimpinkundo.c (original)
+++ trunk/app/paint/gimpinkundo.c Mon Jan 14 20:34:37 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,11 @@
{
GimpInk *ink = GIMP_INK (GIMP_PAINT_CORE_UNDO (ink_undo)->paint_core);
Blob *tmp_blob;
- gint tmp_int;
- gdouble tmp_double;
- guint32 tmp_int_buf[DIST_SMOOTHER_BUFFER];
- gdouble tmp_double_buf[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;
}
}
Modified: trunk/app/paint/gimpinkundo.h
==============================================================================
--- trunk/app/paint/gimpinkundo.h (original)
+++ trunk/app/paint/gimpinkundo.h Mon Jan 14 20:34:37 2008
@@ -38,16 +38,6 @@
GimpPaintCoreUndo parent_instance;
Blob *last_blob;
-
- gdouble dt_buffer[DIST_SMOOTHER_BUFFER];
- gint dt_index;
-
- guint32 ts_buffer[TIME_SMOOTHER_BUFFER];
- gint ts_index;
-
- gdouble last_time;
-
- gboolean init_velocity;
};
struct _GimpInkUndoClass
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]