Commit 9999ccf7 authored by Michael Natterer's avatar Michael Natterer 😴 Committed by Michael Natterer

Bug 520078 – Rotate brushes

2009-02-08  Michael Natterer  <mitch@gimp.org>

	Bug 520078 – Rotate brushes

	Applied a slightly modified patch from Alexia Death:

	* app/core/core-types.h (struct GimpCoords): add "direction" member.

	* app/core/gimpcoords.c: take direction into account in mix(),
	scalarprod(), length_squared(), manhattan_dist() and equal().

	* app/core/gimpcoords-interpolate.c
	(gimp_coords_interpolate_catmull): same here.
	* app/display/gimpdisplayshell-coords.c

	(gimp_display_shell_eval_event): same here.

	* app/paint/gimppaintoptions.[ch]: add properties for direction
	dynamics and adapt dynamics mixing accordingly.

	* app/paint/gimpbrushcore.c (gimp_brush_core_interpolate):
	"interpolate" direction too (in fact, just copy it from
	last_coords since it doesn't change along a straight line).

	* app/paint/gimppaintcore-stroke.c
	(gimp_paint_core_stroke_emulate_dynamics): emulate direction too.

	* app/tools/gimppaintoptions-gui.c: add GUI for direction dynamics.


svn path=/trunk/; revision=28001
parent cb0f8d8d
2009-02-08 Michael Natterer <mitch@gimp.org>
Bug 520078 Rotate brushes
Applied a slightly modified patch from Alexia Death:
* app/core/core-types.h (struct GimpCoords): add "direction" member.
* app/core/gimpcoords.c: take direction into account in mix(),
scalarprod(), length_squared(), manhattan_dist() and equal().
* app/core/gimpcoords-interpolate.c
(gimp_coords_interpolate_catmull): same here.
* app/display/gimpdisplayshell-coords.c
(gimp_display_shell_eval_event): same here.
* app/paint/gimppaintoptions.[ch]: add properties for direction
dynamics and adapt dynamics mixing accordingly.
* app/paint/gimpbrushcore.c (gimp_brush_core_interpolate):
"interpolate" direction too (in fact, just copy it from
last_coords since it doesn't change along a straight line).
* app/paint/gimppaintcore-stroke.c
(gimp_paint_core_stroke_emulate_dynamics): emulate direction too.
* app/tools/gimppaintoptions-gui.c: add GUI for direction dynamics.
2009-02-07 Michael Natterer <mitch@gimp.org>
Simplify floating selection handling a bit more:
......
......@@ -199,6 +199,7 @@ struct _GimpCoords
gdouble ytilt;
gdouble wheel;
gdouble velocity;
gdouble direction;
};
......
......@@ -255,7 +255,10 @@ gimp_coords_interpolate_catmull (const GimpCoords catmul_pt1,
for (n = 1; n <=num_points; n++)
{
GimpCoords res_coords;
GimpCoords last_coords;
gdouble velocity;
gdouble delta_x;
gdouble delta_y;
gdouble p = (gdouble) n / num_points;
res_coords.x =
......@@ -306,6 +309,26 @@ gimp_coords_interpolate_catmull (const GimpCoords catmul_pt1,
future_coords.velocity);
res_coords.velocity = CLAMP (velocity, 0.0, 1.0);
if (n > 1)
last_coords = g_array_index (*ret_coords, GimpCoords, n - 2);
else
last_coords = start_coords;
delta_x = last_coords.x - res_coords.x;
delta_y = last_coords.y - res_coords.y;
if (delta_x == 0)
{
res_coords.direction = last_coords.direction;
}
else
{
res_coords.direction = atan (delta_y / delta_x) / (2 * G_PI);
if (delta_x > 0.0)
res_coords.direction = res_coords.direction + 0.5;
}
g_array_append_val (*ret_coords, res_coords);
if (ret_params)
......
......@@ -43,23 +43,25 @@ gimp_coords_mix (const gdouble amul,
{
if (b)
{
ret_val->x = amul * a->x + bmul * b->x;
ret_val->y = amul * a->y + bmul * b->y;
ret_val->pressure = amul * a->pressure + bmul * b->pressure;
ret_val->xtilt = amul * a->xtilt + bmul * b->xtilt;
ret_val->ytilt = amul * a->ytilt + bmul * b->ytilt;
ret_val->wheel = amul * a->wheel + bmul * b->wheel;
ret_val->velocity = amul * a->velocity + bmul * b->velocity;
ret_val->x = amul * a->x + bmul * b->x;
ret_val->y = amul * a->y + bmul * b->y;
ret_val->pressure = amul * a->pressure + bmul * b->pressure;
ret_val->xtilt = amul * a->xtilt + bmul * b->xtilt;
ret_val->ytilt = amul * a->ytilt + bmul * b->ytilt;
ret_val->wheel = amul * a->wheel + bmul * b->wheel;
ret_val->velocity = amul * a->velocity + bmul * b->velocity;
ret_val->direction = amul * a->direction + bmul * b->direction;
}
else
{
ret_val->x = amul * a->x;
ret_val->y = amul * a->y;
ret_val->pressure = amul * a->pressure;
ret_val->xtilt = amul * a->xtilt;
ret_val->ytilt = amul * a->ytilt;
ret_val->wheel = amul * a->wheel;
ret_val->velocity = amul * a->velocity;
ret_val->x = amul * a->x;
ret_val->y = amul * a->y;
ret_val->pressure = amul * a->pressure;
ret_val->xtilt = amul * a->xtilt;
ret_val->ytilt = amul * a->ytilt;
ret_val->wheel = amul * a->wheel;
ret_val->velocity = amul * a->velocity;
ret_val->direction = amul * a->direction;
}
}
......@@ -114,13 +116,14 @@ gdouble
gimp_coords_scalarprod (const GimpCoords *a,
const GimpCoords *b)
{
return (a->x * b->x +
a->y * b->y +
a->pressure * b->pressure +
a->xtilt * b->xtilt +
a->ytilt * b->ytilt +
a->wheel * b->wheel +
a->velocity * a->velocity);
return (a->x * b->x +
a->y * b->y +
a->pressure * b->pressure +
a->xtilt * b->xtilt +
a->ytilt * b->ytilt +
a->wheel * b->wheel +
a->velocity * b->velocity +
a->direction * b->direction);
}
......@@ -135,13 +138,14 @@ gimp_coords_length_squared (const GimpCoords *a)
{
GimpCoords upscaled_a;
upscaled_a.x = a->x;
upscaled_a.y = a->y;
upscaled_a.pressure = a->pressure * INPUT_RESOLUTION;
upscaled_a.xtilt = a->xtilt * INPUT_RESOLUTION;
upscaled_a.ytilt = a->ytilt * INPUT_RESOLUTION;
upscaled_a.wheel = a->wheel * INPUT_RESOLUTION;
upscaled_a.velocity = a->velocity * INPUT_RESOLUTION;
upscaled_a.x = a->x;
upscaled_a.y = a->y;
upscaled_a.pressure = a->pressure * INPUT_RESOLUTION;
upscaled_a.xtilt = a->xtilt * INPUT_RESOLUTION;
upscaled_a.ytilt = a->ytilt * INPUT_RESOLUTION;
upscaled_a.wheel = a->wheel * INPUT_RESOLUTION;
upscaled_a.velocity = a->velocity * INPUT_RESOLUTION;
upscaled_a.direction = a->direction * INPUT_RESOLUTION;
return gimp_coords_scalarprod (&upscaled_a, &upscaled_a);
}
......@@ -169,6 +173,7 @@ gimp_coords_manhattan_dist (const GimpCoords *a,
dist += ABS (a->ytilt - b->ytilt);
dist += ABS (a->wheel - b->wheel);
dist += ABS (a->velocity - b->velocity);
dist += ABS (a->direction - b->direction);
dist *= INPUT_RESOLUTION;
......@@ -182,11 +187,12 @@ gboolean
gimp_coords_equal (const GimpCoords *a,
const GimpCoords *b)
{
return ( a->x == b->x &&
a->y == b->y &&
a->pressure == b->pressure &&
a->xtilt == b->xtilt &&
a->ytilt == b->ytilt &&
a->wheel == b->wheel &&
a->velocity == b->velocity);
return (a->x == b->x &&
a->y == b->y &&
a->pressure == b->pressure &&
a->xtilt == b->xtilt &&
a->ytilt == b->ytilt &&
a->wheel == b->wheel &&
a->velocity == b->velocity &&
a->direction == b->direction);
}
......@@ -224,6 +224,7 @@ gimp_display_shell_eval_event (GimpDisplayShell *shell,
gdouble delta_y = 0.0;
gdouble distance = 1.0;
gboolean event_fill = (inertia_factor > 0);
gint i;
/* Smoothing causes problems with cursor tracking
* when zoomed above screen resolution so we need to supress it.
......@@ -291,6 +292,17 @@ gimp_display_shell_eval_event (GimpDisplayShell *shell,
coords->velocity = MIN (coords->velocity, 1.0);
}
if (delta_x == 0)
{
coords->direction = shell->last_coords.direction;
}
else
{
coords->direction = atan (delta_y / delta_x) / (2 * G_PI);
if (delta_x > 0.0)
coords->direction = coords->direction + 0.5;
}
/* High speed -> less smooth*/
inertia_factor *= (1 - coords->velocity);
......@@ -387,9 +399,10 @@ gimp_display_shell_eval_event (GimpDisplayShell *shell,
#endif
}
shell->last_coords = *coords;
g_array_append_val (shell->event_queue, *coords);
shell->last_coords = *coords;
shell->last_motion_time = time;
shell->last_motion_delta_time = delta_time;
shell->last_motion_delta_x = delta_x;
......
......@@ -421,6 +421,7 @@ gimp_brush_core_interpolate (GimpPaintCore *paint_core,
gdouble delta_xtilt, delta_ytilt;
gdouble delta_wheel;
gdouble delta_velocity;
gdouble temp_direction;
GimpVector2 temp_vec;
gint n, num_points;
gdouble t0, dt, tn;
......@@ -447,6 +448,7 @@ gimp_brush_core_interpolate (GimpPaintCore *paint_core,
delta_ytilt = paint_core->cur_coords.ytilt - paint_core->last_coords.ytilt;
delta_wheel = paint_core->cur_coords.wheel - paint_core->last_coords.wheel;
delta_velocity = paint_core->cur_coords.velocity - paint_core->last_coords.velocity;
temp_direction = paint_core->cur_coords.direction;
/* return if there has been no motion */
if (! delta_vec.x &&
......@@ -636,20 +638,21 @@ gimp_brush_core_interpolate (GimpPaintCore *paint_core,
gdouble t = t0 + n * dt;
gdouble p = (gdouble) n / num_points;
paint_core->cur_coords.x = (paint_core->last_coords.x +
t * delta_vec.x);
paint_core->cur_coords.y = (paint_core->last_coords.y +
t * delta_vec.y);
paint_core->cur_coords.pressure = (paint_core->last_coords.pressure +
p * delta_pressure);
paint_core->cur_coords.xtilt = (paint_core->last_coords.xtilt +
p * delta_xtilt);
paint_core->cur_coords.ytilt = (paint_core->last_coords.ytilt +
p * delta_ytilt);
paint_core->cur_coords.wheel = (paint_core->last_coords.wheel +
p * delta_wheel);
paint_core->cur_coords.velocity = (paint_core->last_coords.velocity +
p * delta_velocity);
paint_core->cur_coords.x = (paint_core->last_coords.x +
t * delta_vec.x);
paint_core->cur_coords.y = (paint_core->last_coords.y +
t * delta_vec.y);
paint_core->cur_coords.pressure = (paint_core->last_coords.pressure +
p * delta_pressure);
paint_core->cur_coords.xtilt = (paint_core->last_coords.xtilt +
p * delta_xtilt);
paint_core->cur_coords.ytilt = (paint_core->last_coords.ytilt +
p * delta_ytilt);
paint_core->cur_coords.wheel = (paint_core->last_coords.wheel +
p * delta_wheel);
paint_core->cur_coords.velocity = (paint_core->last_coords.velocity +
p * delta_velocity);
paint_core->cur_coords.direction = temp_direction;
if (core->jitter > 0.0)
{
......
......@@ -19,6 +19,8 @@
#include <gegl.h>
#include "libgimpmath/gimpmath.h"
#include "paint-types.h"
#include "base/boundary.h"
......@@ -39,6 +41,7 @@
static void gimp_paint_core_stroke_emulate_dynamics (GimpCoords *coords,
gint length);
static const GimpCoords default_coords = GIMP_COORDS_DEFAULT_VALUES;
......@@ -374,4 +377,39 @@ gimp_paint_core_stroke_emulate_dynamics (GimpCoords *coords,
coords[i].velocity = i * slope;
}
}
if (length > 0)
{
gint i;
/* Fill in direction */
for (i = 2; i < length; i++)
{
gdouble delta_x = coords[i - 1].x - coords[i].x;
gdouble delta_y = coords[i - 1].y - coords[i].y;
if (delta_x == 0)
{
coords[i].direction = coords[i - 1].direction;
}
else
{
coords[i].direction = atan (delta_y / delta_x) / (2 * G_PI);
if (delta_x > 0.0)
coords[i].direction = coords[i].direction + 0.5;
}
/* This should avoid confusing the interpolator on sharp
* turns where the angle warps
*/
if (fabs (coords[i].direction - coords[i - 1].direction) > 0.5)
coords[i].direction = coords[i].direction + 1.0;
}
if (length > 2)
{
coords[0].direction = coords[2].direction;
coords[1].direction = coords[2].direction;
}
}
}
This diff is collapsed.
......@@ -98,6 +98,7 @@ struct _GimpPaintOptions
gboolean dynamics_expanded;
GimpDynamicOptions *pressure_options;
GimpDynamicOptions *velocity_options;
GimpDynamicOptions *direction_options;
GimpDynamicOptions *random_options;
GimpFadeOptions *fade_options;
......
......@@ -54,26 +54,30 @@ static gboolean tool_has_size_dynamics (GType tool_type);
static gboolean tool_has_color_dynamics (GType tool_type);
static gboolean tool_has_angle_dynamics (GType tool_type);
static void pressure_options_gui (GimpPaintOptions *paint_options,
GType tool_type,
GtkTable *table,
gint row,
GtkWidget *labels[]);
static void velocity_options_gui (GimpPaintOptions *paint_options,
GType tool_type,
GtkTable *table,
gint row);
static void random_options_gui (GimpPaintOptions *paint_options,
GType tool_type,
GtkTable *table,
gint row);
static GtkWidget * fade_options_gui (GimpPaintOptions *paint_options,
GType tool_type);
static GtkWidget * gradient_options_gui (GimpPaintOptions *paint_options,
GType tool_type,
GtkWidget *incremental_toggle);
static GtkWidget * jitter_options_gui (GimpPaintOptions *paint_options,
GType tool_type);
static void pressure_options_gui (GimpPaintOptions *paint_options,
GType tool_type,
GtkTable *table,
gint row,
GtkWidget *labels[]);
static void velocity_options_gui (GimpPaintOptions *paint_options,
GType tool_type,
GtkTable *table,
gint row);
static void direction_options_gui (GimpPaintOptions *paint_options,
GType tool_type,
GtkTable *table,
gint row);
static void random_options_gui (GimpPaintOptions *paint_options,
GType tool_type,
GtkTable *table,
gint row);
static GtkWidget * fade_options_gui (GimpPaintOptions *paint_options,
GType tool_type);
static GtkWidget * gradient_options_gui (GimpPaintOptions *paint_options,
GType tool_type,
GtkWidget *incremental_toggle);
static GtkWidget * jitter_options_gui (GimpPaintOptions *paint_options,
GType tool_type);
/* public functions */
......@@ -150,8 +154,6 @@ gimp_paint_options_gui (GimpToolOptions *tool_options)
_("Angle:"),
1.0, 5.0, 2,
FALSE, 0.0, 0.0);
gimp_scale_entry_set_logarithmic (adj_angle, FALSE);
}
if (tool_has_opacity_dynamics (tool_type))
......@@ -206,7 +208,7 @@ gimp_paint_options_gui (GimpToolOptions *tool_options)
gtk_container_add (GTK_CONTAINER (frame), inner_frame);
gtk_widget_show (inner_frame);
table = gtk_table_new (4, n_dynamics + 2, FALSE);
table = gtk_table_new (5, n_dynamics + 2, FALSE);
gtk_container_add (GTK_CONTAINER (inner_frame), table);
gtk_widget_show (table);
......@@ -222,12 +224,18 @@ gimp_paint_options_gui (GimpToolOptions *tool_options)
GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
gtk_widget_show (label);
label = gtk_label_new (_("Random:"));
label = gtk_label_new (_("Direction:"));
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
gtk_widget_show (label);
label = gtk_label_new (_("Random:"));
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5,
GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
gtk_widget_show (label);
pressure_options_gui (options, tool_type,
GTK_TABLE (table), 1,
dynamics_labels);
......@@ -235,8 +243,11 @@ gimp_paint_options_gui (GimpToolOptions *tool_options)
velocity_options_gui (options, tool_type,
GTK_TABLE (table), 2);
direction_options_gui (options, tool_type,
GTK_TABLE (table), 3);
random_options_gui (options, tool_type,
GTK_TABLE (table), 3);
GTK_TABLE (table), 4);
/* EEK: pack the fixed *after* the buttons so the table calls
* size-allocates on it *before* it places the toggles. Fixes
......@@ -539,6 +550,58 @@ velocity_options_gui (GimpPaintOptions *paint_options,
gtk_widget_show (scalebutton);
}
static void
direction_options_gui (GimpPaintOptions *paint_options,
GType tool_type,
GtkTable *table,
gint row)
{
GObject *config = G_OBJECT (paint_options);
gint column = 1;
GtkWidget *scalebutton;
if (tool_has_opacity_dynamics (tool_type))
{
dynamics_check_button_new (config, "direction-opacity",
table, column++, row);
}
if (tool_has_hardness_dynamics (tool_type))
{
dynamics_check_button_new (config, "direction-hardness",
table, column++, row);
}
if (tool_has_rate_dynamics (tool_type))
{
dynamics_check_button_new (config, "direction-rate",
table, column++, row);
}
if (tool_has_size_dynamics (tool_type))
{
dynamics_check_button_new (config, "direction-size",
table, column++, row);
}
if (tool_has_angle_dynamics (tool_type))
{
dynamics_check_button_new (config, "direction-angle",
table, column++, row);
}
if (tool_has_color_dynamics (tool_type))
{
dynamics_check_button_new (config, "direction-color",
table, column++, row);
}
scalebutton = gimp_prop_scale_button_new (config, "direction-prescale");
gtk_table_attach (table, scalebutton, column, column + 1, row, row + 1,
GTK_SHRINK, GTK_SHRINK, 0, 0);
gtk_widget_show (scalebutton);
}
static void
random_options_gui (GimpPaintOptions *paint_options,
GType tool_type,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment