[gimp/wip/animation: 345/373] plug-ins: add a camera preview concept to update only the current frame.



commit c8fcd3a10b6ee58d057b661473406d7a31707f0b
Author: Jehan <jehan girinstud io>
Date:   Mon Jun 26 17:50:26 2017 +0200

    plug-ins: add a camera preview concept to update only the current frame.
    
    When moving the camera, it is useless to start big processing over all
    impacted frames (because of interpolation of camera moves) immediately.
    Just wait for when the user confirms the keyframe. Right now, that only
    happens when switching to another frame.

 plug-ins/animation-play/core/animation-camera.c    |  216 +++++++++++++-------
 plug-ins/animation-play/core/animation-camera.h    |   33 ++--
 .../animation-play/core/animation-celanimation.c   |    1 +
 .../widgets/animation-keyframe-view.c              |  120 ++++++-----
 4 files changed, 233 insertions(+), 137 deletions(-)
---
diff --git a/plug-ins/animation-play/core/animation-camera.c b/plug-ins/animation-play/core/animation-camera.c
index b42a264..26a2780 100644
--- a/plug-ins/animation-play/core/animation-camera.c
+++ b/plug-ins/animation-play/core/animation-camera.c
@@ -54,6 +54,10 @@ struct _AnimationCameraPrivate
 
   /* Panning and tilting. */
   GList     *offsets;
+
+  /* Preview */
+  Offset    *preview_offset;
+  gint       preview_position;
 };
 
 static void   animation_camera_finalize             (GObject         *object);
@@ -68,6 +72,10 @@ static void   animation_camera_get_property         (GObject         *object,
 
 static void   animation_camera_emit_offsets_changed (AnimationCamera *camera,
                                                      gint             position);
+static void   animation_camera_get_real             (AnimationCamera *camera,
+                                                     gint             position,
+                                                     gint            *x_offset,
+                                                     gint            *y_offset);
 
 G_DEFINE_TYPE (AnimationCamera, animation_camera, G_TYPE_OBJECT)
 
@@ -159,6 +167,7 @@ animation_camera_init (AnimationCamera *view)
   view->priv = G_TYPE_INSTANCE_GET_PRIVATE (view,
                                             ANIMATION_TYPE_CAMERA,
                                             AnimationCameraPrivate);
+  view->priv->preview_position = -1;
 }
 
 /************ Public Functions ****************/
@@ -246,84 +255,71 @@ animation_camera_delete_keyframe (AnimationCamera *camera,
 }
 
 void
+animation_camera_preview_keyframe (AnimationCamera *camera,
+                                   gint             position,
+                                   gint             x,
+                                   gint             y)
+{
+  g_return_if_fail (position >= 0 &&
+                    position < animation_get_duration (camera->priv->animation));
+
+  if (! camera->priv->preview_offset)
+    camera->priv->preview_offset = g_new (Offset, 1);
+
+  camera->priv->preview_offset->x = x;
+  camera->priv->preview_offset->y = y;
+  camera->priv->preview_position  = position;
+
+  g_signal_emit (camera, signals[OFFSETS_CHANGED], 0,
+                 position, 1);
+}
+
+void
+animation_camera_reset_preview (AnimationCamera *camera)
+{
+  gboolean offsets_changed = FALSE;
+  gint     position_changed;
+
+  if (camera->priv->preview_offset)
+    {
+      gint preview_offset_x;
+      gint preview_offset_y;
+      gint real_offset_x;
+      gint real_offset_y;
+
+      animation_camera_get (camera, camera->priv->preview_position,
+                            &preview_offset_x, &preview_offset_y);
+      animation_camera_get_real (camera, camera->priv->preview_position,
+                                 &real_offset_x, &real_offset_y);
+      offsets_changed = (preview_offset_x != real_offset_x ||
+                         preview_offset_y != real_offset_y);
+      position_changed = camera->priv->preview_position;
+
+      g_free (camera->priv->preview_offset);
+      camera->priv->preview_offset    = NULL;
+    }
+
+  camera->priv->preview_position  = -1;
+
+  if (offsets_changed)
+    g_signal_emit (camera, signals[OFFSETS_CHANGED], 0,
+                   position_changed, 1);
+}
+
+void
 animation_camera_get (AnimationCamera *camera,
                       gint             position,
                       gint            *x_offset,
                       gint            *y_offset)
 {
-  Offset *keyframe;
-
-  g_return_if_fail (position >= 0 &&
-                    position < animation_get_duration (camera->priv->animation));
-
-  keyframe = g_list_nth_data (camera->priv->offsets, position);
-  if (keyframe)
+  if (camera->priv->preview_position == position)
     {
-      /* There is a keyframe to this exact position. Use its values. */
-      *x_offset = keyframe->x;
-      *y_offset = keyframe->y;
+      *x_offset = camera->priv->preview_offset->x;
+      *y_offset = camera->priv->preview_offset->y;
     }
   else
     {
-      GList  *iter;
-      Offset *prev_keyframe = NULL;
-      Offset *next_keyframe = NULL;
-      gint    prev_keyframe_pos;
-      gint    next_keyframe_pos;
-      gint    i;
-
-      /* This position is not a keyframe. */
-      if (position > 0)
-        {
-          i = MIN (position - 1, g_list_length (camera->priv->offsets) - 1);
-          iter = g_list_nth (camera->priv->offsets, i);
-          for (; iter && ! iter->data; iter = iter->prev, i--)
-            ;
-          if (iter && iter->data)
-            {
-              prev_keyframe_pos = i;
-              prev_keyframe = iter->data;
-            }
-        }
-      if (position < animation_get_duration (camera->priv->animation) - 1)
-        {
-          i = position + 1;
-          iter = g_list_nth (camera->priv->offsets, i);
-          for (; iter && ! iter->data; iter = iter->next, i++)
-            ;
-          if (iter && iter->data)
-            {
-              next_keyframe_pos = i;
-              next_keyframe = iter->data;
-            }
-        }
-
-      if (prev_keyframe == NULL && next_keyframe == NULL)
-        {
-          *x_offset = *y_offset = 0;
-        }
-      else if (prev_keyframe == NULL)
-        {
-          *x_offset = next_keyframe->x;
-          *y_offset = next_keyframe->y;
-        }
-      else if (next_keyframe == NULL)
-        {
-          *x_offset = prev_keyframe->x;
-          *y_offset = prev_keyframe->y;
-        }
-      else
-        {
-          /* XXX No curve editing or anything like this yet.
-           * All keyframing is linear in this first version.
-           */
-          *x_offset = prev_keyframe->x + (position - prev_keyframe_pos) *
-                                         (next_keyframe->x - prev_keyframe->x) /
-                                         (next_keyframe_pos - prev_keyframe_pos);
-          *y_offset = prev_keyframe->y + (position - prev_keyframe_pos) *
-                                         (next_keyframe->y - prev_keyframe->y) /
-                                         (next_keyframe_pos - prev_keyframe_pos);
-        }
+      animation_camera_get_real (camera, position, x_offset, y_offset);
     }
 }
 
@@ -416,3 +412,85 @@ animation_camera_emit_offsets_changed (AnimationCamera *camera,
   g_signal_emit (camera, signals[OFFSETS_CHANGED], 0,
                  prev_keyframe, next_keyframe - prev_keyframe + 1);
 }
+
+static void
+animation_camera_get_real (AnimationCamera *camera,
+                           gint             position,
+                           gint            *x_offset,
+                           gint            *y_offset)
+{
+  Offset *keyframe;
+
+  g_return_if_fail (position >= 0 &&
+                    position < animation_get_duration (camera->priv->animation));
+
+  keyframe = g_list_nth_data (camera->priv->offsets, position);
+  if (keyframe)
+    {
+      /* There is a keyframe to this exact position. Use its values. */
+      *x_offset = keyframe->x;
+      *y_offset = keyframe->y;
+    }
+  else
+    {
+      GList  *iter;
+      Offset *prev_keyframe = NULL;
+      Offset *next_keyframe = NULL;
+      gint    prev_keyframe_pos;
+      gint    next_keyframe_pos;
+      gint    i;
+
+      /* This position is not a keyframe. */
+      if (position > 0)
+        {
+          i = MIN (position - 1, g_list_length (camera->priv->offsets) - 1);
+          iter = g_list_nth (camera->priv->offsets, i);
+          for (; iter && ! iter->data; iter = iter->prev, i--)
+            ;
+          if (iter && iter->data)
+            {
+              prev_keyframe_pos = i;
+              prev_keyframe = iter->data;
+            }
+        }
+      if (position < animation_get_duration (camera->priv->animation) - 1)
+        {
+          i = position + 1;
+          iter = g_list_nth (camera->priv->offsets, i);
+          for (; iter && ! iter->data; iter = iter->next, i++)
+            ;
+          if (iter && iter->data)
+            {
+              next_keyframe_pos = i;
+              next_keyframe = iter->data;
+            }
+        }
+
+      if (prev_keyframe == NULL && next_keyframe == NULL)
+        {
+          *x_offset = *y_offset = 0;
+        }
+      else if (prev_keyframe == NULL)
+        {
+          *x_offset = next_keyframe->x;
+          *y_offset = next_keyframe->y;
+        }
+      else if (next_keyframe == NULL)
+        {
+          *x_offset = prev_keyframe->x;
+          *y_offset = prev_keyframe->y;
+        }
+      else
+        {
+          /* XXX No curve editing or anything like this yet.
+           * All keyframing is linear in this first version.
+           */
+          *x_offset = prev_keyframe->x + (position - prev_keyframe_pos) *
+                                         (next_keyframe->x - prev_keyframe->x) /
+                                         (next_keyframe_pos - prev_keyframe_pos);
+          *y_offset = prev_keyframe->y + (position - prev_keyframe_pos) *
+                                         (next_keyframe->y - prev_keyframe->y) /
+                                         (next_keyframe_pos - prev_keyframe_pos);
+        }
+    }
+}
diff --git a/plug-ins/animation-play/core/animation-camera.h b/plug-ins/animation-play/core/animation-camera.h
index 63e4e09..0301679 100644
--- a/plug-ins/animation-play/core/animation-camera.h
+++ b/plug-ins/animation-play/core/animation-camera.h
@@ -53,23 +53,28 @@ struct _AnimationCameraClass
                                      gint             position);
 };
 
-GType             animation_camera_get_type        (void) G_GNUC_CONST;
+GType             animation_camera_get_type         (void) G_GNUC_CONST;
 
-AnimationCamera * animation_camera_new             (Animation       *animation);
+AnimationCamera * animation_camera_new              (Animation       *animation);
 
-gboolean          animation_camera_has_keyframe    (AnimationCamera *camera,
-                                                    gint             position);
+gboolean          animation_camera_has_keyframe     (AnimationCamera *camera,
+                                                     gint             position);
 
-void              animation_camera_set_keyframe    (AnimationCamera *camera,
-                                                    gint             position,
-                                                    gint             x,
-                                                    gint             y);
-void              animation_camera_delete_keyframe (AnimationCamera *camera,
-                                                    gint             position);
+void              animation_camera_set_keyframe     (AnimationCamera *camera,
+                                                     gint             position,
+                                                     gint             x,
+                                                     gint             y);
+void              animation_camera_delete_keyframe  (AnimationCamera *camera,
+                                                     gint             position);
+void              animation_camera_preview_keyframe (AnimationCamera *camera,
+                                                     gint             position,
+                                                     gint             x,
+                                                     gint             y);
+void              animation_camera_reset_preview    (AnimationCamera *camera);
 
-void              animation_camera_get             (AnimationCamera *camera,
-                                                    gint             position,
-                                                    gint            *x_offset,
-                                                    gint            *y_offset);
+void              animation_camera_get              (AnimationCamera *camera,
+                                                     gint             position,
+                                                     gint            *x_offset,
+                                                     gint            *y_offset);
 
 #endif  /*  __ANIMATION_CAMERA_H__  */
diff --git a/plug-ins/animation-play/core/animation-celanimation.c 
b/plug-ins/animation-play/core/animation-celanimation.c
index 00bdeb8..1439fee 100644
--- a/plug-ins/animation-play/core/animation-celanimation.c
+++ b/plug-ins/animation-play/core/animation-celanimation.c
@@ -770,6 +770,7 @@ animation_cel_animation_serialize (Animation   *animation,
 
   priv = ANIMATION_CEL_ANIMATION (animation)->priv;
 
+  animation_camera_reset_preview (priv->camera);
   animation_get_size (animation, &width, &height);
   xml = g_strdup_printf ("<animation type=\"cels\" framerate=\"%f\" "
                           " duration=\"%d\" onion-skins=\"%d\""
diff --git a/plug-ins/animation-play/widgets/animation-keyframe-view.c 
b/plug-ins/animation-play/widgets/animation-keyframe-view.c
index 6ff661a..6ce4d65 100644
--- a/plug-ins/animation-play/widgets/animation-keyframe-view.c
+++ b/plug-ins/animation-play/widgets/animation-keyframe-view.c
@@ -75,6 +75,8 @@ animation_keyframe_view_init (AnimationKeyFrameView *view)
   view->priv = G_TYPE_INSTANCE_GET_PRIVATE (view,
                                             ANIMATION_TYPE_KEYFRAME_VIEW,
                                             AnimationKeyFrameViewPrivate);
+  view->priv->position        = -1;
+  view->priv->update_position = -1;
 }
 
 /************ Public Functions ****************/
@@ -121,46 +123,60 @@ animation_keyframe_view_show (AnimationKeyFrameView *view,
 
   camera = ANIMATION_CAMERA (animation_cel_animation_get_main_camera (animation));
 
-  view->priv->camera   = camera;
-  view->priv->position = position;
-
-  image_id = animation_get_image_id (ANIMATION (animation));
-  gimp_image_get_resolution (image_id, &xres, &yres);
-
-  animation_get_size (ANIMATION (animation), &width, &height);
-  gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (view->priv->offset_entry),
-                                         0, (gdouble) -GIMP_MAX_IMAGE_SIZE,
-                                         (gdouble) GIMP_MAX_IMAGE_SIZE);
-  gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (view->priv->offset_entry),
-                                         1, (gdouble) -GIMP_MAX_IMAGE_SIZE,
-                                         (gdouble) GIMP_MAX_IMAGE_SIZE);
-  gimp_size_entry_set_size (GIMP_SIZE_ENTRY (view->priv->offset_entry),
-                            0, 0.0, (gdouble) width);
-  gimp_size_entry_set_size (GIMP_SIZE_ENTRY (view->priv->offset_entry),
-                            1, 0.0, (gdouble) height);
-  gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (view->priv->offset_entry),
-                            0, xres, TRUE);
-  gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (view->priv->offset_entry),
-                            1, yres, TRUE);
-
-  g_signal_handlers_disconnect_by_func (view->priv->offset_entry,
-                                        G_CALLBACK (on_offset_entry_changed),
-                                        view);
-  g_signal_handlers_disconnect_by_func (view->priv->camera,
-                                        G_CALLBACK (on_offsets_changed),
-                                        view);
-  animation_camera_get (camera, position, &x_offset, &y_offset);
-  gimp_size_entry_set_value (GIMP_SIZE_ENTRY (view->priv->offset_entry),
-                             0, (gdouble) x_offset);
-  gimp_size_entry_set_value (GIMP_SIZE_ENTRY (view->priv->offset_entry),
-                             1, (gdouble) y_offset);
-  g_signal_connect (view->priv->offset_entry, "value-changed",
-                    G_CALLBACK (on_offset_entry_changed),
-                    view);
-  g_signal_connect (camera, "offsets-changed",
-                    G_CALLBACK (on_offsets_changed),
-                    view);
-  gtk_widget_show (GTK_WIDGET (view));
+  if (view->priv->position != position ||
+      view->priv->camera != camera)
+    {
+      if (view->priv->camera == camera &&
+          view->priv->update_position != -1)
+        {
+          /* We jumped to another position. Apply the ongoing preview. */
+          animation_camera_set_keyframe (view->priv->camera,
+                                         view->priv->update_position,
+                                         view->priv->update_x_offset,
+                                         view->priv->update_y_offset);
+        }
+      view->priv->camera   = camera;
+      view->priv->position = position;
+
+      image_id = animation_get_image_id (ANIMATION (animation));
+      gimp_image_get_resolution (image_id, &xres, &yres);
+
+      animation_get_size (ANIMATION (animation), &width, &height);
+      gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (view->priv->offset_entry),
+                                             0, (gdouble) -GIMP_MAX_IMAGE_SIZE,
+                                             (gdouble) GIMP_MAX_IMAGE_SIZE);
+      gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (view->priv->offset_entry),
+                                             1, (gdouble) -GIMP_MAX_IMAGE_SIZE,
+                                             (gdouble) GIMP_MAX_IMAGE_SIZE);
+      gimp_size_entry_set_size (GIMP_SIZE_ENTRY (view->priv->offset_entry),
+                                0, 0.0, (gdouble) width);
+      gimp_size_entry_set_size (GIMP_SIZE_ENTRY (view->priv->offset_entry),
+                                1, 0.0, (gdouble) height);
+      gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (view->priv->offset_entry),
+                                      0, xres, TRUE);
+      gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (view->priv->offset_entry),
+                                      1, yres, TRUE);
+
+      g_signal_handlers_disconnect_by_func (view->priv->offset_entry,
+                                            G_CALLBACK (on_offset_entry_changed),
+                                            view);
+      g_signal_handlers_disconnect_by_func (view->priv->camera,
+                                            G_CALLBACK (on_offsets_changed),
+                                            view);
+      animation_camera_reset_preview (camera);
+      animation_camera_get (camera, position, &x_offset, &y_offset);
+      gimp_size_entry_set_value (GIMP_SIZE_ENTRY (view->priv->offset_entry),
+                                 0, (gdouble) x_offset);
+      gimp_size_entry_set_value (GIMP_SIZE_ENTRY (view->priv->offset_entry),
+                                 1, (gdouble) y_offset);
+      g_signal_connect (view->priv->offset_entry, "value-changed",
+                        G_CALLBACK (on_offset_entry_changed),
+                        view);
+      g_signal_connect (camera, "offsets-changed",
+                        G_CALLBACK (on_offsets_changed),
+                        view);
+      gtk_widget_show (GTK_WIDGET (view));
+    }
 }
 
 void
@@ -210,10 +226,14 @@ animation_keyframe_update_source (gpointer user_data)
   AnimationKeyFrameView *view = user_data;
 
   view->priv->update_source = 0;
-  animation_camera_set_keyframe (view->priv->camera,
-                                 view->priv->update_position,
-                                 view->priv->update_x_offset,
-                                 view->priv->update_y_offset);
+  /* Only update the preview if we are currently showing this frame. */
+  if (view->priv->position == view->priv->update_position)
+    {
+      animation_camera_preview_keyframe (view->priv->camera,
+                                         view->priv->update_position,
+                                         view->priv->update_x_offset,
+                                         view->priv->update_y_offset);
+    }
   return G_SOURCE_REMOVE;
 }
 
@@ -224,19 +244,11 @@ on_offset_entry_changed (GimpSizeEntry         *entry,
   gdouble x_offset;
   gdouble y_offset;
 
-  /* If a timeout is pending, remove then recreate it in order to
+  /* If a timeout is pending, remove before recreating in order to
    * postpone the camera update. */
   if (view->priv->update_source)
     {
       g_source_remove (view->priv->update_source);
-      if (view->priv->position != view->priv->update_position)
-        {
-          /* Do not postpone the update for another position. */
-          animation_camera_set_keyframe (view->priv->camera,
-                                         view->priv->update_position,
-                                         view->priv->update_x_offset,
-                                         view->priv->update_y_offset);
-        }
     }
 
   x_offset = gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (view->priv->offset_entry), 0);
@@ -244,7 +256,7 @@ on_offset_entry_changed (GimpSizeEntry         *entry,
   view->priv->update_x_offset = x_offset;
   view->priv->update_y_offset = y_offset;
   view->priv->update_position = view->priv->position;
-  view->priv->update_source = g_timeout_add (100, animation_keyframe_update_source, view);
+  view->priv->update_source = g_timeout_add (10, animation_keyframe_update_source, view);
 }
 
 static void


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]