[gimp/wip/animation: 116/197] plug-ins: reorganize caching to have a visible GUI immediately.
- From: Jehan Pagès <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/animation: 116/197] plug-ins: reorganize caching to have a visible GUI immediately.
- Date: Sat, 7 Oct 2017 03:08:11 +0000 (UTC)
commit ebbc934f3fbd32f1c30be08659947866bb86ddef
Author: Jehan <jehan girinstud io>
Date: Tue Dec 20 07:43:25 2016 +0100
plug-ins: reorganize caching to have a visible GUI immediately.
Caching can take time and would delay the exposition of the GUI,
having one wonder whether the plugin really started or not. Now the
animation structure (saved in parasite as XML) is immediately parsed,
and the frame caching is only started once the GUI is exposed.
It is still not perfect because caching makes the GUI hardly responsive,
but this is a first step.
Also took the opportunity to some cleaning, renaming (i.e
s/load_xml/deserialize/) and code reorganization here and there.
plug-ins/animation-play/core/animation-animatic.c | 305 ++++++++--------
.../animation-play/core/animation-celanimation.c | 379 ++++++++++----------
plug-ins/animation-play/core/animation-playback.c | 2 -
plug-ins/animation-play/core/animation.c | 77 +++--
plug-ins/animation-play/core/animation.h | 47 ++--
plug-ins/animation-play/widgets/animation-dialog.c | 26 ++
6 files changed, 439 insertions(+), 397 deletions(-)
---
diff --git a/plug-ins/animation-play/core/animation-animatic.c
b/plug-ins/animation-play/core/animation-animatic.c
index c5a7a27..790549b 100644
--- a/plug-ins/animation-play/core/animation-animatic.c
+++ b/plug-ins/animation-play/core/animation-animatic.c
@@ -79,35 +79,39 @@ struct _AnimationAnimaticPrivate
ANIMATION_TYPE_ANIMATIC, \
AnimationAnimaticPrivate)
-static void animation_animatic_finalize (GObject *object);
+static void animation_animatic_finalize (GObject *object);
/* Virtual methods */
-static gint animation_animatic_get_duration (Animation *animation);
+static gint animation_animatic_get_duration (Animation *animation);
-static void animation_animatic_load (Animation *animation);
-static void animation_animatic_load_xml (Animation *animation,
- const gchar *xml);
-static GeglBuffer * animation_animatic_get_frame (Animation *animation,
- gint pos);
-static gchar * animation_animatic_serialize (Animation *animation);
+static GeglBuffer * animation_animatic_get_frame (Animation *animation,
+ gint pos);
-static gboolean animation_animatic_same (Animation *animation,
- gint pos1,
- gint pos2);
+static gboolean animation_animatic_same (Animation *animation,
+ gint pos1,
+ gint pos2);
+
+static void animation_animatic_purge_cache (Animation *animation);
+
+static void animation_animatic_reset_defaults (Animation *animation);
+static gchar * animation_animatic_serialize (Animation *animation);
+static gboolean animation_animatic_deserialize (Animation *animation,
+ const gchar *xml,
+ GError **error);
/* XML parsing */
-static void animation_animatic_start_element (GMarkupParseContext *context,
- const gchar *element_name,
- const gchar **attribute_names,
- const gchar **attribute_values,
- gpointer user_data,
- GError **error);
-static void animation_animatic_end_element (GMarkupParseContext *context,
- const gchar *element_name,
- gpointer user_data,
- GError **error);
+static void animation_animatic_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error);
+static void animation_animatic_end_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error);
static void animation_animatic_text (GMarkupParseContext *context,
const gchar *text,
@@ -117,19 +121,19 @@ static void animation_animatic_text (GMarkupParseContext *context
/* Utils */
-static void animation_animatic_cache (AnimationAnimatic *animation,
- gint panel,
- gboolean recursion);
+static void animation_animatic_cache_panel (AnimationAnimatic *animation,
+ gint panel,
+ gboolean recursion);
/* Tag handling (from layer names) */
-static gint parse_ms_tag (Animation *animation,
- const gchar *str);
-static gboolean parse_combine_tag (const gchar *str);
+static gint parse_ms_tag (Animation *animation,
+ const gchar *str);
+static gboolean parse_combine_tag (const gchar *str);
-static gboolean is_ms_tag (const gchar *str,
- gint *duration,
- gint *taglength);
+static gboolean is_ms_tag (const gchar *str,
+ gint *duration,
+ gint *taglength);
G_DEFINE_TYPE (AnimationAnimatic, animation_animatic, ANIMATION_TYPE_ANIMATION)
@@ -165,14 +169,18 @@ animation_animatic_class_init (AnimationAnimaticClass *klass)
G_TYPE_INT,
G_TYPE_INT);
- object_class->finalize = animation_animatic_finalize;
+ object_class->finalize = animation_animatic_finalize;
- anim_class->get_duration = animation_animatic_get_duration;
- anim_class->load = animation_animatic_load;
- anim_class->load_xml = animation_animatic_load_xml;
- anim_class->get_frame = animation_animatic_get_frame;
- anim_class->serialize = animation_animatic_serialize;
- anim_class->same = animation_animatic_same;
+ anim_class->get_duration = animation_animatic_get_duration;
+ anim_class->get_frame = animation_animatic_get_frame;
+
+ anim_class->same = animation_animatic_same;
+
+ anim_class->purge_cache = animation_animatic_purge_cache;
+
+ anim_class->reset_defaults = animation_animatic_reset_defaults;
+ anim_class->serialize = animation_animatic_serialize;
+ anim_class->deserialize = animation_animatic_deserialize;
g_type_class_add_private (klass, sizeof (AnimationAnimaticPrivate));
}
@@ -297,7 +305,7 @@ animation_animatic_set_combine (AnimationAnimatic *animatic,
if (priv->combine[panel_num] != combine)
{
priv->combine[panel_num] = combine;
- animation_animatic_cache (animatic, panel_num, TRUE);
+ animation_animatic_cache_panel (animatic, panel_num, TRUE);
}
}
@@ -375,8 +383,64 @@ animation_animatic_get_duration (Animation *animation)
return count;
}
+static GeglBuffer *
+animation_animatic_get_frame (Animation *animation,
+ gint pos)
+{
+ AnimationAnimaticPrivate *priv;
+ gint panel;
+
+ priv = GET_PRIVATE (animation);
+ panel = animation_animatic_get_panel (ANIMATION_ANIMATIC (animation),
+ pos);
+ return g_object_ref (priv->cache[panel]);
+}
+
+static gboolean
+animation_animatic_same (Animation *animation,
+ gint pos1,
+ gint pos2)
+{
+ AnimationAnimaticPrivate *priv = GET_PRIVATE (animation);
+ gint count = 0;
+ gboolean identical = FALSE;
+ gint i ;
+
+ for (i = 0; i < priv->n_panels; i++)
+ {
+ count += priv->durations[i];
+ if (count > pos1 && count > pos2)
+ {
+ identical = TRUE;
+ break;
+ }
+ else if (count > pos1 || count > pos2)
+ {
+ identical = FALSE;
+ break;
+ }
+ }
+
+ return identical;
+}
+
static void
-animation_animatic_load (Animation *animation)
+animation_animatic_purge_cache (Animation *animation)
+{
+ AnimationAnimaticPrivate *priv = GET_PRIVATE (animation);
+ gint i;
+
+ for (i = 0; i < priv->n_panels; i++)
+ {
+ animation_animatic_cache_panel (ANIMATION_ANIMATIC (animation), i, FALSE);
+ g_signal_emit_by_name (animation, "loading",
+ (gdouble) i / ((gdouble) priv->n_panels - 0.999));
+ }
+ g_signal_emit_by_name (animation, "loaded");
+}
+
+static void
+animation_animatic_reset_defaults (Animation *animation)
{
AnimationAnimaticPrivate *priv = GET_PRIVATE (animation);
gint32 *layers;
@@ -384,21 +448,17 @@ animation_animatic_load (Animation *animation)
gint i;
/* Cleaning. */
- if (priv->cache)
+ g_free (priv->tattoos);
+ g_free (priv->durations);
+ g_free (priv->combine);
+ for (i = 0; i < priv->n_panels; i++)
{
- g_free (priv->tattoos);
- g_free (priv->durations);
- g_free (priv->combine);
-
- for (i = 0; i < priv->n_panels; i++)
- {
- g_free (priv->comments[i]);
- if (priv->cache[i])
- g_object_unref (priv->cache[i]);
- }
- g_free (priv->comments);
- g_free (priv->cache);
+ g_free (priv->comments[i]);
+ if (priv->cache[i])
+ g_object_unref (priv->cache[i]);
}
+ g_free (priv->comments);
+ g_free (priv->cache);
image_id = animation_get_image_id (animation);
layers = gimp_image_get_layers (image_id, &priv->n_panels);
@@ -423,9 +483,6 @@ animation_animatic_load (Animation *animation)
gint duration;
gboolean combine;
- g_signal_emit_by_name (animation, "loading",
- (gdouble) i / ((gdouble) priv->n_panels - 0.999));
-
layer_name = gimp_item_get_name (layers[priv->n_panels - (i + 1)]);
duration = parse_ms_tag (animation, layer_name);
@@ -437,72 +494,10 @@ animation_animatic_load (Animation *animation)
priv->combine[i] = combine;
/* Layer names are used as default comments. */
priv->comments[i] = layer_name;
-
- /* Panel image. */
- animation_animatic_cache (ANIMATION_ANIMATIC (animation), i, FALSE);
}
g_free (layers);
}
-static void
-animation_animatic_load_xml (Animation *animation,
- const gchar *xml)
-{
- const GMarkupParser markup_parser =
- {
- animation_animatic_start_element,
- animation_animatic_end_element,
- animation_animatic_text,
- NULL, /* passthrough */
- NULL /* error */
- };
- GMarkupParseContext *context;
- ParseStatus status = { 0, };
- GError *error = NULL;
-
- g_return_if_fail (xml != NULL);
-
- /* Init with a default load. */
- animation_animatic_load (animation);
-
- /* Parse XML to update. */
- status.state = START_STATE;
- status.animation = animation;
- status.xml_level = 0;
-
- context = g_markup_parse_context_new (&markup_parser,
- 0, &status, NULL);
- g_markup_parse_context_parse (context, xml, strlen (xml), &error);
- if (error)
- {
- g_warning ("Error parsing XML: %s", error->message);
- }
- else
- {
- g_markup_parse_context_end_parse (context, &error);
- if (error)
- g_warning ("Error parsing XML: %s", error->message);
- }
- g_markup_parse_context_free (context);
-
- /* If XML parsing failed, just reset the animation. */
- if (error)
- animation_animatic_load (animation);
-}
-
-static GeglBuffer *
-animation_animatic_get_frame (Animation *animation,
- gint pos)
-{
- AnimationAnimaticPrivate *priv;
- gint panel;
-
- priv = GET_PRIVATE (animation);
- panel = animation_animatic_get_panel (ANIMATION_ANIMATIC (animation),
- pos);
- return g_object_ref (priv->cache[panel]);
-}
-
static gchar *
animation_animatic_serialize (Animation *animation)
{
@@ -566,31 +561,39 @@ animation_animatic_serialize (Animation *animation)
}
static gboolean
-animation_animatic_same (Animation *animation,
- gint pos1,
- gint pos2)
+animation_animatic_deserialize (Animation *animation,
+ const gchar *xml,
+ GError **error)
{
- AnimationAnimaticPrivate *priv = GET_PRIVATE (animation);
- gint count = 0;
- gboolean identical = FALSE;
- gint i ;
-
- for (i = 0; i < priv->n_panels; i++)
+ const GMarkupParser markup_parser =
{
- count += priv->durations[i];
- if (count > pos1 && count > pos2)
- {
- identical = TRUE;
- break;
- }
- else if (count > pos1 || count > pos2)
- {
- identical = FALSE;
- break;
- }
- }
+ animation_animatic_start_element,
+ animation_animatic_end_element,
+ animation_animatic_text,
+ NULL, /* passthrough */
+ NULL /* error */
+ };
+ GMarkupParseContext *context;
+ ParseStatus status = { 0, };
- return identical;
+ g_return_val_if_fail (xml != NULL && *error == NULL, FALSE);
+
+ /* Init with a default load. */
+ animation_animatic_reset_defaults (animation);
+
+ /* Parse XML to update. */
+ status.state = START_STATE;
+ status.animation = animation;
+ status.xml_level = 0;
+
+ context = g_markup_parse_context_new (&markup_parser,
+ 0, &status, NULL);
+ g_markup_parse_context_parse (context, xml, strlen (xml), error);
+ if (*error == NULL)
+ g_markup_parse_context_end_parse (context, error);
+ g_markup_parse_context_free (context);
+
+ return (*error == NULL);
}
static void
@@ -692,11 +695,7 @@ animation_animatic_start_element (GMarkupParseContext *context,
values++;
}
if (priv->combine[status->panel] != combine)
- {
- priv->combine[status->panel] = combine;
- animation_animatic_cache (ANIMATION_ANIMATIC (status->animation),
- status->panel, FALSE);
- }
+ priv->combine[status->panel] = combine;
status->state = PANEL_STATE;
break;
case PANEL_STATE:
@@ -828,9 +827,9 @@ animation_animatic_text (GMarkupParseContext *context,
/**** Utils ****/
static void
-animation_animatic_cache (AnimationAnimatic *animatic,
- gint panel,
- gboolean recursion)
+animation_animatic_cache_panel (AnimationAnimatic *animatic,
+ gint panel,
+ gboolean recursion)
{
AnimationAnimaticPrivate *priv = GET_PRIVATE (animatic);
Animation *animation = ANIMATION (animatic);
@@ -878,10 +877,12 @@ animation_animatic_cache (AnimationAnimatic *animatic,
layer_offx, layer_offy);
g_object_unref (buffer);
- g_signal_emit_by_name (animation, "cache-invalidated",
- animation_animatic_get_position (animatic,
- panel),
- 1);
+ if (animation_animatic_get_panel_duration (animatic, panel) > 0)
+ g_signal_emit_by_name (animation, "cache-invalidated",
+ animation_animatic_get_position (animatic,
+ panel),
+ animation_animatic_get_panel_duration (animatic,
+ panel));
/* If next panel is in "combine" mode, it must also be re-cached.
* And so on, recursively. */
@@ -889,7 +890,7 @@ animation_animatic_cache (AnimationAnimatic *animatic,
panel < priv->n_panels - 1 &&
priv->combine[panel + 1])
{
- animation_animatic_cache (animatic, panel + 1, TRUE);
+ animation_animatic_cache_panel (animatic, panel + 1, TRUE);
}
}
diff --git a/plug-ins/animation-play/core/animation-celanimation.c
b/plug-ins/animation-play/core/animation-celanimation.c
index b860c43..5b08fc7 100644
--- a/plug-ins/animation-play/core/animation-celanimation.c
+++ b/plug-ins/animation-play/core/animation-celanimation.c
@@ -95,51 +95,55 @@ typedef struct
ANIMATION_TYPE_CEL_ANIMATION, \
AnimationCelAnimationPrivate)
-static void animation_cel_animation_finalize (GObject *object);
+static void animation_cel_animation_finalize (GObject *object);
/* Virtual methods */
-static gint animation_cel_animation_get_duration (Animation *animation);
+static gint animation_cel_animation_get_duration (Animation *animation);
-static void animation_cel_animation_load (Animation *animation);
-static void animation_cel_animation_load_xml (Animation *animation,
- const gchar *xml);
-static GeglBuffer * animation_cel_animation_get_frame (Animation *animation,
- gint pos);
-static gchar * animation_cel_animation_serialize (Animation *animation);
+static GeglBuffer * animation_cel_animation_get_frame (Animation *animation,
+ gint pos);
-static gboolean animation_cel_animation_same (Animation *animation,
- gint previous_pos,
- gint next_pos);
+static gboolean animation_cel_animation_same (Animation *animation,
+ gint previous_pos,
+ gint next_pos);
+
+static void animation_cel_animation_purge_cache (Animation *animation);
+
+static void animation_cel_animation_reset_defaults (Animation *animation);
+static gchar * animation_cel_animation_serialize (Animation *animation);
+static gboolean animation_cel_animation_deserialize (Animation *animation,
+ const gchar *xml,
+ GError **error);
/* XML parsing */
-static void animation_cel_animation_start_element (GMarkupParseContext *context,
- const gchar *element_name,
- const gchar **attribute_names,
- const gchar **attribute_values,
- gpointer user_data,
- GError **error);
-static void animation_cel_animation_end_element (GMarkupParseContext *context,
- const gchar *element_name,
- gpointer user_data,
- GError **error);
-
-static void animation_cel_animation_text (GMarkupParseContext *context,
- const gchar *text,
- gsize text_len,
- gpointer user_data,
- GError **error);
+static void animation_cel_animation_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error);
+static void animation_cel_animation_end_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error);
+
+static void animation_cel_animation_text (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error);
/* Utils */
-static void animation_cel_animation_cleanup (AnimationCelAnimation *animation);
-static void animation_cel_animation_cache (AnimationCelAnimation *animation,
- gint position);
-static gboolean animation_cel_animation_cache_cmp (Cache *cache1,
- Cache *cache2);
-static void animation_cel_animation_clean_cache (Cache *cache);
-static void animation_cel_animation_clean_track (Track *track);
+static void animation_cel_animation_cache (AnimationCelAnimation *animation,
+ gint position);
+static void animation_cel_animation_cleanup (AnimationCelAnimation *animation);
+static gboolean animation_cel_animation_cache_cmp (Cache *cache1,
+ Cache *cache2);
+static void animation_cel_animation_clean_cache (Cache *cache);
+static void animation_cel_animation_clean_track (Track *track);
G_DEFINE_TYPE (AnimationCelAnimation, animation_cel_animation, ANIMATION_TYPE_ANIMATION)
@@ -151,14 +155,17 @@ animation_cel_animation_class_init (AnimationCelAnimationClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
AnimationClass *anim_class = ANIMATION_CLASS (klass);
- object_class->finalize = animation_cel_animation_finalize;
+ object_class->finalize = animation_cel_animation_finalize;
+
+ anim_class->get_duration = animation_cel_animation_get_duration;
+ anim_class->get_frame = animation_cel_animation_get_frame;
+ anim_class->same = animation_cel_animation_same;
- anim_class->get_duration = animation_cel_animation_get_duration;
- anim_class->load = animation_cel_animation_load;
- anim_class->load_xml = animation_cel_animation_load_xml;
- anim_class->get_frame = animation_cel_animation_get_frame;
- anim_class->serialize = animation_cel_animation_serialize;
- anim_class->same = animation_cel_animation_same;
+ anim_class->purge_cache = animation_cel_animation_purge_cache;
+
+ anim_class->reset_defaults = animation_cel_animation_reset_defaults;
+ anim_class->serialize = animation_cel_animation_serialize;
+ anim_class->deserialize = animation_cel_animation_deserialize;
g_type_class_add_private (klass, sizeof (AnimationCelAnimationPrivate));
}
@@ -222,6 +229,7 @@ animation_cel_animation_set_layers (AnimationCelAnimation *animation,
layers->data = NULL;
}
animation_cel_animation_cache (animation, position);
+ g_signal_emit_by_name (animation, "cache-invalidated", position, 1);
}
}
@@ -389,6 +397,8 @@ animation_cel_animation_level_up (AnimationCelAnimation *animation,
animation_cel_animation_cache (animation, i);
}
}
+ g_signal_emit_by_name (animation, "cache-invalidated",
+ 0, g_list_length (track->frames));
g_signal_emit_by_name (animation, "loaded");
}
@@ -436,6 +446,8 @@ animation_cel_animation_level_down (AnimationCelAnimation *animation,
animation_cel_animation_cache (animation, i);
}
}
+ g_signal_emit_by_name (animation, "cache-invalidated",
+ 0, g_list_length (track->frames));
g_signal_emit_by_name (animation, "loaded");
}
@@ -459,7 +471,6 @@ animation_cel_animation_level_delete (AnimationCelAnimation *animation,
{
item = g_list_nth (animation->priv->tracks, level);
track = item->data;
- animation_cel_animation_clean_track (track);
animation->priv->tracks = g_list_delete_link (animation->priv->tracks, item);
iter = track->frames;
@@ -474,7 +485,10 @@ animation_cel_animation_level_delete (AnimationCelAnimation *animation,
animation_cel_animation_cache (animation, i);
}
}
+ g_signal_emit_by_name (animation, "cache-invalidated",
+ 0, g_list_length (track->frames));
g_signal_emit_by_name (animation, "loaded");
+ animation_cel_animation_clean_track (track);
return TRUE;
}
@@ -560,6 +574,9 @@ animation_cel_animation_cel_delete (AnimationCelAnimation *animation,
animation_cel_animation_cache (animation, i);
}
+ if (i > position)
+ g_signal_emit_by_name (animation, "cache-invalidated",
+ position, i - position);
g_signal_emit_by_name (animation, "loaded");
return TRUE;
@@ -610,6 +627,9 @@ animation_cel_animation_cel_add (AnimationCelAnimation *animation,
animation_cel_animation_cache (animation, i);
}
+ if (i > position)
+ g_signal_emit_by_name (animation, "cache-invalidated",
+ position, i - position);
g_signal_emit_by_name (animation, "loaded");
return TRUE;
@@ -626,154 +646,110 @@ animation_cel_animation_get_duration (Animation *animation)
return ANIMATION_CEL_ANIMATION (animation)->priv->duration;
}
-static void
-animation_cel_animation_load (Animation *animation)
+static GeglBuffer *
+animation_cel_animation_get_frame (Animation *animation,
+ gint pos)
{
- AnimationCelAnimationPrivate *priv;
- Track *track;
- gint32 image_id;
- gint32 layer;
- gint i;
+ AnimationCelAnimation *cel_animation;
+ Cache *cache;
+ GeglBuffer *frame = NULL;
- priv = ANIMATION_CEL_ANIMATION (animation)->priv;
+ cel_animation = ANIMATION_CEL_ANIMATION (animation);
- /* First load with default values. */
- if (! priv->tracks)
+ cache = g_list_nth_data (cel_animation->priv->cache,
+ pos);
+ if (cache)
{
- /* Purely arbitrary value. User will anyway change it to suit one's needs. */
- priv->duration = 240;
-
- /* There are at least 2 tracks.
- * Second one is freely-named. */
- track = g_new0 (Track, 1);
- track->title = g_strdup (_("Name me"));
- priv->tracks = g_list_prepend (priv->tracks, track);
- /* The first track is called "Background". */
- track = g_new0 (Track, 1);
- track->title = g_strdup (_("Background"));
- priv->tracks = g_list_prepend (priv->tracks, track);
-
- /* If there is a layer named "Background", set it to all frames
- * on background track. */
- image_id = animation_get_image_id (animation);
- layer = gimp_image_get_layer_by_name (image_id, _("Background"));
- if (layer > 0)
- {
- gint tattoo;
+ frame = g_object_ref (cache->buffer);
+ }
+ return frame;
+}
- tattoo = gimp_item_get_tattoo (layer);
- for (i = 0; i < priv->duration; i++)
- {
- GList *layers = NULL;
+static gboolean
+animation_cel_animation_same (Animation *animation,
+ gint pos1,
+ gint pos2)
+{
+ AnimationCelAnimation *cel_animation;
+ Cache *cache1;
+ Cache *cache2;
- layers = g_list_prepend (layers,
- GINT_TO_POINTER (tattoo));
- track->frames = g_list_prepend (track->frames,
- layers);
- }
- }
- }
+ cel_animation = ANIMATION_CEL_ANIMATION (animation);
- /* Invalidate all cache. */
- g_list_free_full (priv->cache,
- (GDestroyNotify) animation_cel_animation_clean_cache);
- priv->cache = NULL;
+ g_return_val_if_fail (pos1 >= 0 &&
+ pos1 < cel_animation->priv->duration &&
+ pos2 >= 0 &&
+ pos2 < cel_animation->priv->duration,
+ FALSE);
- /* Finally cache. */
- for (i = 0; i < priv->duration; i++)
- {
- g_signal_emit_by_name (animation, "loading",
- (gdouble) i / ((gdouble) priv->duration - 0.999));
+ cache1 = g_list_nth_data (cel_animation->priv->cache, pos1);
+ cache2 = g_list_nth_data (cel_animation->priv->cache, pos2);
- /* Panel image. */
- animation_cel_animation_cache (ANIMATION_CEL_ANIMATION (animation), i);
- }
+ return animation_cel_animation_cache_cmp (cache1, cache2);
}
static void
-animation_cel_animation_load_xml (Animation *animation,
- const gchar *xml)
+animation_cel_animation_purge_cache (Animation *animation)
{
- const GMarkupParser markup_parser =
+ gint duration;
+ gint i;
+
+ duration = animation_get_duration (animation);
+ for (i = 0; i < duration; i++)
{
- animation_cel_animation_start_element,
- animation_cel_animation_end_element,
- animation_cel_animation_text,
- NULL, /* passthrough */
- NULL /* error */
- };
- GMarkupParseContext *context;
- ParseStatus status = { 0, };
- GError *error = NULL;
+ animation_cel_animation_cache (ANIMATION_CEL_ANIMATION (animation),
+ i);
+ g_signal_emit_by_name (animation, "loading",
+ (gdouble) i / ((gdouble) duration - 0.999));
+ }
+ g_signal_emit_by_name (animation, "loaded");
+}
- g_return_if_fail (xml != NULL);
+static void
+animation_cel_animation_reset_defaults (Animation *animation)
+{
+ AnimationCelAnimationPrivate *priv;
+ Track *track;
+ gint32 image_id;
+ gint32 layer;
+ gint i;
- /* Parse XML to update. */
- status.state = START_STATE;
- status.animation = animation;
+ priv = ANIMATION_CEL_ANIMATION (animation)->priv;
+ animation_cel_animation_cleanup (ANIMATION_CEL_ANIMATION (animation));
- context = g_markup_parse_context_new (&markup_parser,
- 0, &status, NULL);
- g_markup_parse_context_parse (context, xml, strlen (xml), &error);
- if (error)
- {
- g_warning ("Error parsing XML: %s", error->message);
- }
- else
- {
- g_markup_parse_context_end_parse (context, &error);
- if (error)
- g_warning ("Error parsing XML: %s", error->message);
- }
- g_markup_parse_context_free (context);
+ /* Purely arbitrary value. User will anyway change it to suit one's needs. */
+ priv->duration = 240;
- /* If XML parsing failed, just reset the animation. */
- if (error)
- {
- animation_cel_animation_cleanup (ANIMATION_CEL_ANIMATION (animation));
- animation_cel_animation_load (animation);
- }
- else
+ /* There are at least 2 tracks. Second one is freely-named. */
+ track = g_new0 (Track, 1);
+ track->title = g_strdup (_("Name me"));
+ priv->tracks = g_list_prepend (priv->tracks, track);
+ /* The first track is called "Background". */
+ track = g_new0 (Track, 1);
+ track->title = g_strdup (_("Background"));
+ priv->tracks = g_list_prepend (priv->tracks, track);
+
+ /* If there is a layer named "Background", set it to all frames
+ * on background track. */
+ image_id = animation_get_image_id (animation);
+ layer = gimp_image_get_layer_by_name (image_id, _("Background"));
+ if (layer > 0)
{
- AnimationCelAnimation *cel_animation;
- gint duration = animation_get_duration (animation);
- gint i;
-
- cel_animation = ANIMATION_CEL_ANIMATION (animation);
- /* Reverse track order. */
- cel_animation->priv->tracks = g_list_reverse (cel_animation->priv->tracks);
+ gint tattoo;
- /* cache. */
- for (i = 0; i < duration; i++)
+ tattoo = gimp_item_get_tattoo (layer);
+ for (i = 0; i < priv->duration; i++)
{
- g_signal_emit_by_name (animation, "loading",
- (gdouble) i / ((gdouble) duration - 0.999));
+ GList *layers = NULL;
- /* Panel image. */
- animation_cel_animation_cache (ANIMATION_CEL_ANIMATION (animation), i);
+ layers = g_list_prepend (layers,
+ GINT_TO_POINTER (tattoo));
+ track->frames = g_list_prepend (track->frames,
+ layers);
}
}
}
-static GeglBuffer *
-animation_cel_animation_get_frame (Animation *animation,
- gint pos)
-{
- AnimationCelAnimation *cel_animation;
- Cache *cache;
- GeglBuffer *frame = NULL;
-
- cel_animation = ANIMATION_CEL_ANIMATION (animation);
-
- cache = g_list_nth_data (cel_animation->priv->cache,
- pos);
- if (cache)
- {
- frame = g_object_ref (cache->buffer);
- }
- return frame;
-}
-
static gchar *
animation_cel_animation_serialize (Animation *animation)
{
@@ -901,26 +877,43 @@ animation_cel_animation_serialize (Animation *animation)
}
static gboolean
-animation_cel_animation_same (Animation *animation,
- gint pos1,
- gint pos2)
+animation_cel_animation_deserialize (Animation *animation,
+ const gchar *xml,
+ GError **error)
{
- AnimationCelAnimation *cel_animation;
- Cache *cache1;
- Cache *cache2;
+ const GMarkupParser markup_parser =
+ {
+ animation_cel_animation_start_element,
+ animation_cel_animation_end_element,
+ animation_cel_animation_text,
+ NULL, /* passthrough */
+ NULL /* error */
+ };
+ GMarkupParseContext *context;
+ ParseStatus status = { 0, };
- cel_animation = ANIMATION_CEL_ANIMATION (animation);
+ g_return_val_if_fail (xml != NULL && *error == NULL, FALSE);
- g_return_val_if_fail (pos1 >= 0 &&
- pos1 < cel_animation->priv->duration &&
- pos2 >= 0 &&
- pos2 < cel_animation->priv->duration,
- FALSE);
+ /* Parse XML to update. */
+ status.state = START_STATE;
+ status.animation = animation;
- cache1 = g_list_nth_data (cel_animation->priv->cache, pos1);
- cache2 = g_list_nth_data (cel_animation->priv->cache, pos2);
+ context = g_markup_parse_context_new (&markup_parser,
+ 0, &status, NULL);
+ g_markup_parse_context_parse (context, xml, strlen (xml), error);
+ if (*error == NULL)
+ {
+ AnimationCelAnimation *cel_animation;
- return animation_cel_animation_cache_cmp (cache1, cache2);
+ g_markup_parse_context_end_parse (context, error);
+
+ cel_animation = ANIMATION_CEL_ANIMATION (animation);
+ /* Reverse track order. */
+ cel_animation->priv->tracks = g_list_reverse (cel_animation->priv->tracks);
+ }
+ g_markup_parse_context_free (context);
+
+ return (*error == NULL);
}
static void
@@ -1217,20 +1210,6 @@ animation_cel_animation_text (GMarkupParseContext *context,
/**** Utils ****/
static void
-animation_cel_animation_cleanup (AnimationCelAnimation *animation)
-{
- g_list_free_full (animation->priv->cache,
- (GDestroyNotify) animation_cel_animation_clean_cache);
- animation->priv->cache = NULL;
- g_list_free_full (animation->priv->comments,
- (GDestroyNotify) g_free);
- animation->priv->comments = NULL;
- g_list_free_full (animation->priv->tracks,
- (GDestroyNotify) animation_cel_animation_clean_track);
- animation->priv->tracks = NULL;
-}
-
-static void
animation_cel_animation_cache (AnimationCelAnimation *animation,
gint pos)
{
@@ -1386,8 +1365,20 @@ animation_cel_animation_cache (AnimationCelAnimation *animation,
/* This item exists and has a NULL data. */
g_list_nth (animation->priv->cache, pos)->data = cache;
+}
- g_signal_emit_by_name (animation, "cache-invalidated", pos, 1);
+static void
+animation_cel_animation_cleanup (AnimationCelAnimation *animation)
+{
+ g_list_free_full (animation->priv->cache,
+ (GDestroyNotify) animation_cel_animation_clean_cache);
+ animation->priv->cache = NULL;
+ g_list_free_full (animation->priv->comments,
+ (GDestroyNotify) g_free);
+ animation->priv->comments = NULL;
+ g_list_free_full (animation->priv->tracks,
+ (GDestroyNotify) animation_cel_animation_clean_track);
+ animation->priv->tracks = NULL;
}
static gboolean
diff --git a/plug-ins/animation-play/core/animation-playback.c
b/plug-ins/animation-play/core/animation-playback.c
index f40b402..7c194e2 100644
--- a/plug-ins/animation-play/core/animation-playback.c
+++ b/plug-ins/animation-play/core/animation-playback.c
@@ -514,8 +514,6 @@ animation_playback_set_property (GObject *object,
if (! animation)
break;
- if (! animation_loaded (animation))
- animation_load (animation);
/* Default playback is the full range of frames. */
playback->priv->position = 0;
playback->priv->start = 0;
diff --git a/plug-ins/animation-play/core/animation.c b/plug-ins/animation-play/core/animation.c
index c714be3..654ec3a 100644
--- a/plug-ins/animation-play/core/animation.c
+++ b/plug-ins/animation-play/core/animation.c
@@ -54,7 +54,8 @@ enum
enum
{
PROP_0,
- PROP_IMAGE
+ PROP_IMAGE,
+ PROP_XML
};
typedef struct _AnimationPrivate AnimationPrivate;
@@ -62,7 +63,6 @@ typedef struct _AnimationPrivate AnimationPrivate;
struct _AnimationPrivate
{
gint32 image_id;
- gchar *xml;
gdouble framerate;
@@ -227,13 +227,23 @@ animation_class_init (AnimationClass *klass)
/**
* Animation:image:
*
- * The attached image id.
+ * The associated image id.
*/
g_object_class_install_property (object_class, PROP_IMAGE,
g_param_spec_int ("image", NULL, NULL,
0, G_MAXINT, 0,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
+ /**
+ * Animation:xml:
+ *
+ * The animation serialized as a XML string.
+ */
+ g_object_class_install_property (object_class, PROP_XML,
+ g_param_spec_string ("xml", NULL,
+ NULL, NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
g_type_class_add_private (klass, sizeof (AnimationPrivate));
}
@@ -262,15 +272,13 @@ animation_new (gint32 image_id,
gboolean animatic,
const gchar *xml)
{
- Animation *animation;
- AnimationPrivate *priv;
+ Animation *animation;
animation = g_object_new (animatic? ANIMATION_TYPE_ANIMATIC :
ANIMATION_TYPE_CEL_ANIMATION,
"image", image_id,
+ "xml", xml,
NULL);
- priv = ANIMATION_GET_PRIVATE (animation);
- priv->xml = g_strdup (xml);
return animation;
}
@@ -283,27 +291,21 @@ animation_get_image_id (Animation *animation)
return priv->image_id;
}
+/**
+ * animation_load:
+ * @animation: the #Animation.
+ *
+ * Cache the whole animation. This is to be used at the start, or each
+ * time you want to reload the image contents.
+ **/
void
animation_load (Animation *animation)
{
AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
priv->loaded = FALSE;
- g_signal_emit (animation, animation_signals[LOADING], 0, 0.0);
-
- if (priv->xml)
- ANIMATION_GET_CLASS (animation)->load_xml (animation,
- priv->xml);
- else
- ANIMATION_GET_CLASS (animation)->load (animation);
-
- /* XML is only used for the first load.
- * Any next loads will use internal data. */
- g_free (priv->xml);
- priv->xml = NULL;
-
+ ANIMATION_GET_CLASS (animation)->purge_cache (animation);
priv->loaded = TRUE;
- g_signal_emit (animation, animation_signals[LOADED], 0);
g_signal_emit (animation, animation_signals[CACHE_INVALIDATED], 0,
0, animation_get_duration (animation));
}
@@ -480,12 +482,6 @@ animation_loaded (Animation *animation)
static void
animation_finalize (GObject *object)
{
- Animation *animation = ANIMATION (object);
- AnimationPrivate *priv = ANIMATION_GET_PRIVATE (animation);
-
- if (priv->xml)
- g_free (priv->xml);
-
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -503,6 +499,25 @@ animation_set_property (GObject *object,
case PROP_IMAGE:
priv->image_id = g_value_get_int (value);
break;
+ case PROP_XML:
+ {
+ const gchar *xml = g_value_get_string (value);
+ GError *error = NULL;
+
+ if (! xml ||
+ ! ANIMATION_GET_CLASS (animation)->deserialize (animation,
+ xml,
+ &error))
+ {
+ if (error)
+ g_warning ("Error parsing XML: %s", error->message);
+
+ /* First time or XML parsing failed: reset to defaults. */
+ ANIMATION_GET_CLASS (animation)->reset_defaults (animation);
+ }
+ g_clear_error (&error);
+ }
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -524,6 +539,14 @@ animation_get_property (GObject *object,
case PROP_IMAGE:
g_value_set_int (value, priv->image_id);
break;
+ case PROP_XML:
+ {
+ gchar *xml;
+
+ xml = ANIMATION_GET_CLASS (animation)->serialize (animation);
+ g_value_take_string (value, xml);
+ }
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
diff --git a/plug-ins/animation-play/core/animation.h b/plug-ins/animation-play/core/animation.h
index de47fbc..59be8bc 100644
--- a/plug-ins/animation-play/core/animation.h
+++ b/plug-ins/animation-play/core/animation.h
@@ -41,34 +41,37 @@ struct _AnimationClass
GObjectClass parent_class;
/* Signals */
- void (*loading) (Animation *animation,
- gdouble ratio);
- void (*loaded) (Animation *animation);
-
- void (*cache_invalidated) (Animation *animation,
- gint position);
- void (*duration_changed) (Animation *animation,
- gint duration);
- void (*framerate_changed) (Animation *animation,
- gdouble fps);
- void (*proxy) (Animation *animation,
- gdouble ratio);
+ void (*loading) (Animation *animation,
+ gdouble ratio);
+ void (*loaded) (Animation *animation);
+
+ void (*cache_invalidated) (Animation *animation,
+ gint position);
+ void (*duration_changed) (Animation *animation,
+ gint duration);
+ void (*framerate_changed) (Animation *animation,
+ gdouble fps);
+ void (*proxy) (Animation *animation,
+ gdouble ratio);
/* Defaults to returning FALSE for any different position. */
- gboolean (*same) (Animation *animation,
- gint prev_pos,
- gint next_pos);
+ gboolean (*same) (Animation *animation,
+ gint prev_pos,
+ gint next_pos);
/* These virtual methods must be implemented by any subclass. */
- void (*load) (Animation *animation);
- void (*load_xml) (Animation *animation,
- const gchar *xml);
- gint (*get_duration) (Animation *animation);
+ gint (*get_duration) (Animation *animation);
- GeglBuffer * (*get_frame) (Animation *animation,
- gint pos);
+ GeglBuffer * (*get_frame) (Animation *animation,
+ gint pos);
- gchar * (*serialize) (Animation *animation);
+ void (*purge_cache) (Animation *animation);
+
+ void (*reset_defaults) (Animation *animation);
+ gchar * (*serialize) (Animation *animation);
+ gboolean (*deserialize) (Animation *animation,
+ const gchar *xml,
+ GError **error);
};
GType animation_get_type (void);
diff --git a/plug-ins/animation-play/widgets/animation-dialog.c
b/plug-ins/animation-play/widgets/animation-dialog.c
index a0eb27f..ab68d23 100755
--- a/plug-ins/animation-play/widgets/animation-dialog.c
+++ b/plug-ins/animation-play/widgets/animation-dialog.c
@@ -139,6 +139,10 @@ static void connect_accelerators (GtkUIManager *ui_manager,
static void animation_dialog_set_animation (AnimationDialog *dialog,
Animation *animation);
+
+static gboolean on_dialog_expose (GtkWidget *widget,
+ GdkEvent *event,
+ Animation *animation);
/* Finalization. */
static void update_ui_sensitivity (AnimationDialog *dialog);
@@ -1361,6 +1365,28 @@ animation_dialog_set_animation (AnimationDialog *dialog,
/* Set the playback */
animation_playback_set_animation (priv->playback, animation);
+
+ if (gtk_widget_get_realized (GTK_WIDGET (dialog)))
+ animation_load (priv->animation);
+ else
+ /* Wait for the dialog to be realized because cache loading can
+ take time and it is friendlier to have a visible GUI first. */
+ g_signal_connect_after (dialog, "expose-event",
+ G_CALLBACK (on_dialog_expose),
+ priv->animation);
+}
+
+static gboolean
+on_dialog_expose (GtkWidget *widget,
+ GdkEvent *event,
+ Animation *animation)
+{
+ g_signal_handlers_disconnect_by_func (widget,
+ G_CALLBACK (on_dialog_expose),
+ animation);
+ animation_load (animation);
+
+ return FALSE;
}
/* Update the tool sensitivity for playing, depending on the number of frames. */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]