[gimp] app: implement creating an animation from a warp tool transform
- From: Michael Natterer <mitch src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] app: implement creating an animation from a warp tool transform
- Date: Fri, 7 Nov 2014 23:49:07 +0000 (UTC)
commit dfcbc23caccab9e43718717f73115228f1ef2a0d
Author: Michael Natterer <mitch gimp org>
Date: Sat Nov 8 00:47:39 2014 +0100
app: implement creating an animation from a warp tool transform
like in the iwarp plug-in. I consider the plug-in obsolete now.
app/tools/gimpwarpoptions.c | 51 +++++++++++-
app/tools/gimpwarpoptions.h | 15 +++-
app/tools/gimpwarptool.c | 185 ++++++++++++++++++++++++++++++++++++++----
3 files changed, 223 insertions(+), 28 deletions(-)
---
diff --git a/app/tools/gimpwarpoptions.c b/app/tools/gimpwarpoptions.c
index df1d650..0dd278c 100644
--- a/app/tools/gimpwarpoptions.c
+++ b/app/tools/gimpwarpoptions.c
@@ -42,7 +42,8 @@ enum
PROP_BEHAVIOR,
PROP_EFFECT_STRENGTH,
PROP_EFFECT_SIZE,
- PROP_EFFECT_HARDNESS
+ PROP_EFFECT_HARDNESS,
+ PROP_N_ANIMATION_FRAMES
};
@@ -94,6 +95,12 @@ gimp_warp_options_class_init (GimpWarpOptionsClass *klass)
_("Effect Hardness"),
0.0, 1.0, 0.5,
GIMP_PARAM_STATIC_STRINGS);
+
+ GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_N_ANIMATION_FRAMES,
+ "n-animation-frames",
+ _("Number of animation frames"),
+ 3, 1000, 10,
+ GIMP_PARAM_STATIC_STRINGS);
}
static void
@@ -123,6 +130,9 @@ gimp_warp_options_set_property (GObject *object,
case PROP_EFFECT_HARDNESS:
options->effect_hardness = g_value_get_double (value);
break;
+ case PROP_N_ANIMATION_FRAMES:
+ options->n_animation_frames = g_value_get_int (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -152,6 +162,9 @@ gimp_warp_options_get_property (GObject *object,
case PROP_EFFECT_HARDNESS:
g_value_set_double (value, options->effect_hardness);
break;
+ case PROP_N_ANIMATION_FRAMES:
+ g_value_set_int (value, options->n_animation_frames);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -162,10 +175,13 @@ gimp_warp_options_get_property (GObject *object,
GtkWidget *
gimp_warp_options_gui (GimpToolOptions *tool_options)
{
- GObject *config = G_OBJECT (tool_options);
- GtkWidget *vbox = gimp_tool_options_gui (tool_options);
- GtkWidget *combo;
- GtkWidget *scale;
+ GimpWarpOptions *options = GIMP_WARP_OPTIONS (tool_options);
+ GObject *config = G_OBJECT (tool_options);
+ GtkWidget *vbox = gimp_tool_options_gui (tool_options);
+ GtkWidget *frame;
+ GtkWidget *anim_vbox;
+ GtkWidget *combo;
+ GtkWidget *scale;
combo = gimp_prop_enum_combo_box_new (config, "behavior", 0, 0);
g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
@@ -193,5 +209,30 @@ gimp_warp_options_gui (GimpToolOptions *tool_options)
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
gtk_widget_show (scale);
+ /* the animation frame */
+ frame = gimp_frame_new (_("Animate"));
+ gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ anim_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
+ gtk_container_add (GTK_CONTAINER (frame), anim_vbox);
+ gtk_widget_show (anim_vbox);
+
+ scale = gimp_prop_spin_scale_new (config, "n-animation-frames",
+ _("Frames"),
+ 0.01, 1.0, 2);
+ gimp_spin_scale_set_scale_limits (GIMP_SPIN_SCALE (scale), 3.0, 100.0);
+ gtk_box_pack_start (GTK_BOX (anim_vbox), scale, FALSE, FALSE, 0);
+ gtk_widget_show (scale);
+
+ options->animate_button = gtk_button_new_with_label (_("Create Animation"));
+ gtk_widget_set_sensitive (options->animate_button, FALSE);
+ gtk_box_pack_start (GTK_BOX (anim_vbox), options->animate_button,
+ FALSE, FALSE, 0);
+ gtk_widget_show (options->animate_button);
+
+ g_object_add_weak_pointer (G_OBJECT (options->animate_button),
+ (gpointer) &options->animate_button);
+
return vbox;
}
diff --git a/app/tools/gimpwarpoptions.h b/app/tools/gimpwarpoptions.h
index 19b9970..46b1fde 100644
--- a/app/tools/gimpwarpoptions.h
+++ b/app/tools/gimpwarpoptions.h
@@ -37,12 +37,17 @@ typedef struct _GimpWarpOptionsClass GimpWarpOptionsClass;
struct _GimpWarpOptions
{
- GimpToolOptions parent_instance;
+ GimpToolOptions parent_instance;
- GimpWarpBehavior behavior;
- gdouble effect_strength;
- gdouble effect_size;
- gdouble effect_hardness;
+ GimpWarpBehavior behavior;
+ gdouble effect_strength;
+ gdouble effect_size;
+ gdouble effect_hardness;
+
+ gint n_animation_frames;
+
+ /* options gui */
+ GtkWidget *animate_button;
};
struct _GimpWarpOptionsClass
diff --git a/app/tools/gimpwarptool.c b/app/tools/gimpwarptool.c
index 79efe15..8dc0c77 100644
--- a/app/tools/gimpwarptool.c
+++ b/app/tools/gimpwarptool.c
@@ -28,14 +28,19 @@
#include "tools-types.h"
+#include "gegl/gimp-gegl-apply-operation.h"
+
#include "core/gimp.h"
#include "core/gimpchannel.h"
#include "core/gimpimage.h"
#include "core/gimpimagemap.h"
+#include "core/gimplayer.h"
#include "core/gimpprogress.h"
#include "core/gimpprojection.h"
+#include "core/gimpsubprogress.h"
#include "widgets/gimphelp-ids.h"
+#include "widgets/gimpwidgets-utils.h"
#include "display/gimpdisplay.h"
@@ -113,7 +118,11 @@ static void gimp_warp_tool_stroke_changed (GeglPath *stro
static void gimp_warp_tool_image_map_flush (GimpImageMap *image_map,
GimpTool *tool);
static void gimp_warp_tool_add_op (GimpWarpTool *wt,
- GeglNode *new_op);
+ GeglNode *op);
+static void gimp_warp_tool_remove_op (GimpWarpTool *wt,
+ GeglNode *op);
+
+static void gimp_warp_tool_animate (GimpWarpTool *wt);
G_DEFINE_TYPE (GimpWarpTool, gimp_warp_tool, GIMP_TYPE_DRAW_TOOL)
@@ -455,7 +464,6 @@ gimp_warp_tool_undo (GimpTool *tool,
{
GimpWarpTool *wt = GIMP_WARP_TOOL (tool);
GeglNode *to_delete;
- GeglNode *previous;
const gchar *type;
if (! wt->render_node)
@@ -467,14 +475,10 @@ gimp_warp_tool_undo (GimpTool *tool,
if (strcmp (type, "gegl:warp"))
return FALSE;
- previous = gegl_node_get_producer (to_delete, "input", NULL);
-
- gegl_node_disconnect (to_delete, "input");
- gegl_node_connect_to (previous, "output",
- wt->render_node, "aux");
-
wt->redo_stack = g_list_prepend (wt->redo_stack, g_object_ref (to_delete));
+ gimp_warp_tool_remove_op (wt, to_delete);
+
gegl_node_remove_child (wt->graph, to_delete);
gimp_warp_tool_update_stroke (wt, to_delete);
@@ -537,11 +541,12 @@ static void
gimp_warp_tool_start (GimpWarpTool *wt,
GimpDisplay *display)
{
- GimpTool *tool = GIMP_TOOL (wt);
- GimpImage *image = gimp_display_get_image (display);
- GimpDrawable *drawable = gimp_image_get_active_drawable (image);
- const Babl *format;
- GeglRectangle bbox;
+ GimpTool *tool = GIMP_TOOL (wt);
+ GimpWarpOptions *options = GIMP_WARP_TOOL_GET_OPTIONS (wt);
+ GimpImage *image = gimp_display_get_image (display);
+ GimpDrawable *drawable = gimp_image_get_active_drawable (image);
+ const Babl *format;
+ GeglRectangle bbox;
tool->display = display;
tool->drawable = drawable;
@@ -563,12 +568,22 @@ gimp_warp_tool_start (GimpWarpTool *wt,
if (! gimp_draw_tool_is_active (GIMP_DRAW_TOOL (wt)))
gimp_draw_tool_start (GIMP_DRAW_TOOL (wt), display);
+
+ if (options->animate_button)
+ {
+ g_signal_connect_swapped (options->animate_button, "clicked",
+ G_CALLBACK (gimp_warp_tool_animate),
+ wt);
+
+ gtk_widget_set_sensitive (options->animate_button, TRUE);
+ }
}
static void
gimp_warp_tool_halt (GimpWarpTool *wt)
{
- GimpTool *tool = GIMP_TOOL (wt);
+ GimpTool *tool = GIMP_TOOL (wt);
+ GimpWarpOptions *options = GIMP_WARP_TOOL_GET_OPTIONS (wt);
if (wt->coords_buffer)
{
@@ -603,6 +618,15 @@ gimp_warp_tool_halt (GimpWarpTool *wt)
if (gimp_draw_tool_is_active (GIMP_DRAW_TOOL (wt)))
gimp_draw_tool_stop (GIMP_DRAW_TOOL (wt));
+
+ if (options->animate_button)
+ {
+ gtk_widget_set_sensitive (options->animate_button, FALSE);
+
+ g_signal_handlers_disconnect_by_func (options->animate_button,
+ gimp_warp_tool_animate,
+ wt);
+ }
}
static void
@@ -769,19 +793,144 @@ gimp_warp_tool_image_map_flush (GimpImageMap *image_map,
static void
gimp_warp_tool_add_op (GimpWarpTool *wt,
- GeglNode *new_op)
+ GeglNode *op)
{
GeglNode *last_op;
g_return_if_fail (GEGL_IS_NODE (wt->render_node));
- gegl_node_add_child (wt->graph, new_op);
+ gegl_node_add_child (wt->graph, op);
last_op = gegl_node_get_producer (wt->render_node, "aux", NULL);
gegl_node_disconnect (wt->render_node, "aux");
gegl_node_connect_to (last_op, "output",
- new_op, "input");
- gegl_node_connect_to (new_op, "output",
+ op , "input");
+ gegl_node_connect_to (op, "output",
+ wt->render_node, "aux");
+}
+
+static void
+gimp_warp_tool_remove_op (GimpWarpTool *wt,
+ GeglNode *op)
+{
+ GeglNode *previous;
+
+ g_return_if_fail (GEGL_IS_NODE (wt->render_node));
+
+ previous = gegl_node_get_producer (op, "input", NULL);
+
+ gegl_node_disconnect (op, "input");
+ gegl_node_connect_to (previous, "output",
wt->render_node, "aux");
+
+ gegl_node_remove_child (wt->graph, op);
+}
+
+static void
+gimp_warp_tool_animate (GimpWarpTool *wt)
+{
+ GimpTool *tool = GIMP_TOOL (wt);
+ GimpWarpOptions *options = GIMP_WARP_TOOL_GET_OPTIONS (wt);
+ GimpImage *orig_image;
+ GimpImage *image;
+ GimpLayer *layer;
+ GimpLayer *first_layer;
+ GeglNode *scale_node;
+ GimpProgress *progress;
+ GtkWidget *widget;
+ gint i;
+
+ if (! gimp_warp_tool_get_undo_desc (tool, tool->display))
+ {
+ gimp_tool_message_literal (tool, tool->display,
+ _("Please add some warp strokes first."));
+ return;
+ }
+
+ /* get rid of the image map so we can use wt->graph */
+ if (wt->image_map)
+ {
+ gimp_image_map_abort (wt->image_map);
+ g_object_unref (wt->image_map);
+ wt->image_map = NULL;
+ }
+
+ gimp_progress_start (GIMP_PROGRESS (tool), FALSE,
+ _("Rendering Frame %d"), 1);
+
+ orig_image = gimp_item_get_image (GIMP_ITEM (tool->drawable));
+
+ image = gimp_create_image (orig_image->gimp,
+ gimp_item_get_width (GIMP_ITEM (tool->drawable)),
+ gimp_item_get_height (GIMP_ITEM (tool->drawable)),
+ gimp_drawable_get_base_type (tool->drawable),
+ gimp_drawable_get_precision (tool->drawable),
+ TRUE);
+
+ /* the first frame is always the unwarped image */
+ layer = GIMP_LAYER (gimp_item_convert (GIMP_ITEM (tool->drawable), image,
+ GIMP_TYPE_LAYER));
+ gimp_object_take_name (GIMP_OBJECT (layer),
+ g_strdup_printf (_("Frame %d"), 1));
+
+ gimp_item_set_offset (GIMP_ITEM (layer), 0, 0);
+ gimp_item_set_visible (GIMP_ITEM (layer), TRUE, FALSE);
+ gimp_layer_set_mode (layer, GIMP_NORMAL_MODE, FALSE);
+ gimp_layer_set_opacity (layer, GIMP_OPACITY_OPAQUE, FALSE);
+ gimp_image_add_layer (image, layer, NULL, 0, FALSE);
+
+ first_layer = layer;
+
+ scale_node = gegl_node_new_child (NULL,
+ "operation", "gimp:scalar-multiply",
+ "n-components", 2,
+ NULL);
+ gimp_warp_tool_add_op (wt, scale_node);
+
+ progress = gimp_sub_progress_new (GIMP_PROGRESS (tool));
+
+ for (i = 1; i < options->n_animation_frames; i++)
+ {
+ gimp_progress_set_text (GIMP_PROGRESS (tool),
+ _("Rendering Frame %d"), i + 1);
+
+ gimp_sub_progress_set_step (GIMP_SUB_PROGRESS (progress),
+ i, options->n_animation_frames);
+
+ layer = GIMP_LAYER (gimp_item_duplicate (GIMP_ITEM (first_layer),
+ GIMP_TYPE_LAYER));
+ gimp_object_take_name (GIMP_OBJECT (layer),
+ g_strdup_printf (_("Frame %d"), i + 1));
+
+ gegl_node_set (scale_node,
+ "factor", (gdouble) i /
+ (gdouble) (options->n_animation_frames - 1),
+ NULL);
+
+ gimp_gegl_apply_operation (gimp_drawable_get_buffer (GIMP_DRAWABLE (first_layer)),
+ progress,
+ _("Frame"),
+ wt->graph,
+ gimp_drawable_get_buffer (GIMP_DRAWABLE (layer)),
+ NULL);
+
+ gimp_image_add_layer (image, layer, NULL, 0, FALSE);
+ }
+
+ g_object_unref (progress);
+
+ gimp_warp_tool_remove_op (wt, scale_node);
+
+ gimp_progress_end (GIMP_PROGRESS (tool));
+
+ /* recreate the image map */
+ gimp_warp_tool_create_image_map (wt, tool->drawable);
+ gimp_image_map_apply (wt->image_map, NULL);
+
+ widget = GTK_WIDGET (gimp_display_get_shell (tool->display));
+ gimp_create_display (orig_image->gimp, image, GIMP_UNIT_PIXEL, 1.0,
+ G_OBJECT (gtk_widget_get_screen (widget)),
+ gimp_widget_get_monitor (widget));
+ g_object_unref (image);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]