gnome-games r8161 - trunk/aisleriot



Author: jclinton
Date: Tue Oct 21 19:47:01 2008
New Revision: 8161
URL: http://svn.gnome.org/viewvc/gnome-games?rev=8161&view=rev

Log:
Moved the animation code to the slot renderer so the slot can keep
track of how many cards are being animated. The animated cards are now
children of the slot.

Modified:
   trunk/aisleriot/board.c
   trunk/aisleriot/slot-renderer.c
   trunk/aisleriot/slot-renderer.h

Modified: trunk/aisleriot/board.c
==============================================================================
--- trunk/aisleriot/board.c	(original)
+++ trunk/aisleriot/board.c	Tue Oct 21 19:47:01 2008
@@ -202,13 +202,6 @@
   guint force_geometry_update : 1;
 };
 
-typedef struct _AnimationData AnimationData;
-
-struct _AnimationData
-{
-  ClutterBehaviour *move, *rotate, *depth;
-};
-
 typedef struct _RemovedCard RemovedCard;
 
 struct _RemovedCard
@@ -833,85 +826,14 @@
 }
 
 static void
-destroy_animation_data (ClutterActor *actor, AnimationData *data)
-{
-  g_signal_handlers_disconnect_by_func (actor, destroy_animation_data, data);
-
-  if (data->move)
-    g_object_unref (data->move);
-  if (data->rotate)
-    g_object_unref (data->rotate);
-  if (data->depth)
-    g_object_unref (data->depth);
-
-  g_slice_free (AnimationData, data);
-}
-
-static void
-add_animation (AisleriotBoard *board,
-               gint oldx, gint oldy, gboolean old_face_down,
-               gint newx, gint newy, gboolean new_face_down,
-               ClutterActor *actor)
-{
-  AisleriotBoardPrivate *priv = board->priv;
-  ClutterTimeline *tl;
-  ClutterAlpha *alpha;
-  AnimationData *data;
-  ClutterKnot knots[] = { { oldx, oldy }, { newx, newy } };
-
-  data = g_slice_new0 (AnimationData);
-
-  g_signal_connect (actor, "destroy",
-                    G_CALLBACK (destroy_animation_data),
-                    data);
-
-  clutter_actor_set_position (actor, oldx, oldy);
-
-  tl = clutter_timeline_new_for_duration (500);
-  alpha = clutter_alpha_new_full (tl, CLUTTER_ALPHA_RAMP_INC, NULL, NULL);
-  data->move = clutter_behaviour_path_new (alpha, knots,
-                                           G_N_ELEMENTS (knots));
-
-  clutter_behaviour_apply (data->move, actor);
-
-  if (old_face_down != new_face_down) {
-    gint center_x = priv->card_size.width / 2;
-    gint center_y = priv->card_size.height / 2;
-
-    clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS,
-                                180.0,
-                                center_x, center_y, 0);
-
-    data->rotate = clutter_behaviour_rotate_new (alpha,
-                                                 CLUTTER_Y_AXIS,
-                                                 CLUTTER_ROTATE_CW,
-                                                 180.0, 0.0);
-    clutter_behaviour_rotate_set_center (CLUTTER_BEHAVIOUR_ROTATE
-                                         (data->rotate),
-                                         center_x, center_y, 0);
-
-    clutter_behaviour_apply (data->rotate, actor);
-  }
-
-  alpha = clutter_alpha_new_full (tl, CLUTTER_ALPHA_SINE, NULL, NULL);
-
-  data->depth = clutter_behaviour_depth_new (alpha,
-                                             0, priv->card_size.height);
-  clutter_behaviour_apply (data->depth, actor);
-
-  clutter_timeline_start (tl);
-  g_object_unref (tl);
-}
-
-static void
 check_animations (AisleriotBoard *board)
 {
-#if 0
   AisleriotBoardPrivate *priv = board->priv;
   GPtrArray *slots;
   int slot_num, i;
   Slot *slot;
   GArray *removed_cards = g_array_new (FALSE, FALSE, sizeof (RemovedCard));
+  GArray *animations = g_array_new (FALSE, FALSE, sizeof (AisleriotAnimStart));
 
   slots = aisleriot_game_get_slots (priv->game);
 
@@ -920,8 +842,6 @@
   for (slot_num = 0; slot_num < slots->len; slot_num++) {
     slot = slots->pdata[slot_num];
 
-    g_assert (slot->cards->len == slot->card_images->len);
-
     if (slot->old_cards->len > slot->cards->len) {
       for (i = 0; i < slot->cards->len; i++) {
         Card old_card = CARD (slot->old_cards->data[i]);
@@ -948,6 +868,8 @@
   for (slot_num = 0; slot_num < slots->len; slot_num++) {
     slot = slots->pdata[slot_num];
 
+    g_array_set_size (animations, 0);
+
     /* Check if the top card has been flipped over */
     if (slot->old_cards->len >= slot->cards->len
         && slot->cards->len >= 1
@@ -958,22 +880,23 @@
 
       if (old_card.attr.suit == new_card.attr.suit
           && old_card.attr.rank == new_card.attr.rank
-          && old_card.attr.face_down != new_card.attr.face_down
-          && slot->card_images->pdata[slot->cards->len - 1]) {
-        gint cardx = slot->rect.x + slot->pixeldx * (slot->cards->len - 1);
-        gint cardy = slot->rect.y + slot->pixeldy * (slot->cards->len - 1);
-
-        add_animation (board,
-                       cardx, cardy, old_card.attr.face_down,
-                       cardx, cardy, new_card.attr.face_down,
-                       slot->card_images->pdata[slot->cards->len - 1]);
+          && old_card.attr.face_down != new_card.attr.face_down) {
+        AisleriotAnimStart anim;
+
+        anim.cardx = slot->pixeldx * (slot->cards->len - 1);
+        anim.cardy = slot->pixeldy * (slot->cards->len - 1);
+        anim.face_down = old_card.attr.face_down;
+
+        g_array_append_val (animations, anim);
       }
       /* Check if any cards have been added from the removed cards
          pile */
     } else if (slot->old_cards->len < slot->cards->len
                && !memcmp (slot->old_cards->data, slot->cards->data,
                            slot->old_cards->len)) {
-      for (i = slot->old_cards->len; i < slot->cards->len; i++) {
+      for (i = MAX (slot->old_cards->len, slot->cards->len - slot->exposed);
+           i < slot->cards->len;
+           i++) {
         Card added_card = CARD (slot->cards->data[i]);
         int j;
 
@@ -982,15 +905,14 @@
                                                       RemovedCard, j);
 
           if (added_card.attr.suit == removed_card->card.attr.suit
-              && added_card.attr.rank == removed_card->card.attr.rank
-              && slot->card_images->pdata[i]) {
-            gint cardx = slot->rect.x + slot->pixeldx * i;
-            gint cardy = slot->rect.y + slot->pixeldy * i;
-
-            add_animation (board, removed_card->cardx, removed_card->cardy,
-                           removed_card->card.attr.face_down,
-                           cardx, cardy, added_card.attr.face_down,
-                           slot->card_images->pdata[i]);
+              && added_card.attr.rank == removed_card->card.attr.rank) {
+            AisleriotAnimStart anim;
+
+            anim.cardx = removed_card->cardx - slot->rect.x + slot->pixeldx * i;
+            anim.cardy = removed_card->cardy - slot->rect.y + slot->pixeldy * i;
+            anim.face_down = removed_card->card.attr.face_down;
+
+            g_array_append_val (animations, anim);
 
             g_array_remove_index (removed_cards, j);
 
@@ -1000,13 +922,17 @@
       }
     }
 
+    aisleriot_slot_renderer_set_animations
+      (AISLERIOT_SLOT_RENDERER (slot->slot_renderer),
+       animations->len, (const AisleriotAnimStart *) animations->data);
+
     /* Set the old cards back to the new cards */
     g_byte_array_set_size (slot->old_cards, 0);
     g_byte_array_append (slot->old_cards, slot->cards->data, slot->cards->len);
   }
 
+  g_array_free (animations, TRUE);
   g_array_free (removed_cards, TRUE);
-#endif
 }
 
 static void

Modified: trunk/aisleriot/slot-renderer.c
==============================================================================
--- trunk/aisleriot/slot-renderer.c	(original)
+++ trunk/aisleriot/slot-renderer.c	Tue Oct 21 19:47:01 2008
@@ -19,10 +19,17 @@
 #include <config.h>
 
 #include <clutter/clutter-actor.h>
+#include <clutter/clutter-container.h>
+#include <clutter/clutter-timeline.h>
+#include <clutter/clutter-behaviour-rotate.h>
+#include <clutter/clutter-behaviour-depth.h>
+#include <clutter/clutter-behaviour-path.h>
 #include <gtk/gtk.h>
 #include <cogl/cogl.h>
+#include <string.h>
 
 #include "slot-renderer.h"
+#include "card.h"
 
 static void aisleriot_slot_renderer_dispose (GObject *object);
 static void aisleriot_slot_renderer_finalize (GObject *object);
@@ -41,19 +48,43 @@
 static void aisleriot_slot_renderer_set_cache (AisleriotSlotRenderer *srend,
                                                AisleriotCardCache *cache);
 
-G_DEFINE_TYPE (AisleriotSlotRenderer, aisleriot_slot_renderer,
-               CLUTTER_TYPE_ACTOR);
+static void clutter_container_iface_init (ClutterContainerIface *iface);
+
+static void aisleriot_slot_renderer_allocate (ClutterActor *actor,
+                                              const ClutterActorBox *box,
+                                              gboolean origin_changed);
+
+static void completed_cb (AisleriotSlotRenderer *srend);
+
+G_DEFINE_TYPE_WITH_CODE (AisleriotSlotRenderer, aisleriot_slot_renderer,
+                         CLUTTER_TYPE_ACTOR,
+                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
+                                                clutter_container_iface_init));
 
 #define AISLERIOT_SLOT_RENDERER_GET_PRIVATE(obj) \
   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), AISLERIOT_TYPE_SLOT_RENDERER, \
                                 AisleriotSlotRendererPrivate))
 
+typedef struct _AnimationData AnimationData;
+
 struct _AisleriotSlotRendererPrivate
 {
   AisleriotCardCache *cache;
+
   Slot *slot;
+
   gboolean show_highlight;
   guint highlight_start;
+
+  ClutterTimeline *timeline;
+  guint completed_handler;
+  GArray *animations;
+};
+
+struct _AnimationData
+{
+  ClutterActor *card_tex;
+  ClutterBehaviour *move, *rotate, *depth;
 };
 
 enum
@@ -79,6 +110,7 @@
   gobject_class->get_property = aisleriot_slot_renderer_get_property;
 
   actor_class->paint = aisleriot_slot_renderer_paint;
+  actor_class->allocate = aisleriot_slot_renderer_allocate;
 
   pspec = g_param_spec_object ("cache", NULL, NULL,
                                AISLERIOT_TYPE_CARD_CACHE,
@@ -118,15 +150,29 @@
   priv = self->priv = AISLERIOT_SLOT_RENDERER_GET_PRIVATE (self);
 
   priv->highlight_start = G_MAXUINT;
+  priv->animations = g_array_new (FALSE, FALSE, sizeof (AnimationData));
+  priv->timeline = clutter_timeline_new_for_duration (500);
+  g_signal_connect_swapped (priv->timeline, "completed",
+                            G_CALLBACK (completed_cb), self);
+
 }
 
 static void
 aisleriot_slot_renderer_dispose (GObject *object)
 {
   AisleriotSlotRenderer *self = (AisleriotSlotRenderer *) object;
+  AisleriotSlotRendererPrivate *priv = self->priv;
 
   aisleriot_slot_renderer_set_cache (self, NULL);
 
+  /* Get rid of any running animations */
+  aisleriot_slot_renderer_set_animations (self, 0, NULL);
+
+  if (priv->timeline) {
+    g_object_unref (priv->timeline);
+    priv->timeline = NULL;
+  }
+
   G_OBJECT_CLASS (aisleriot_slot_renderer_parent_class)->dispose (object);
 }
 
@@ -134,6 +180,9 @@
 aisleriot_slot_renderer_finalize (GObject *object)
 {
   AisleriotSlotRenderer *self = (AisleriotSlotRenderer *) object;
+  AisleriotSlotRendererPrivate *priv = self->priv;
+
+  g_array_free (priv->animations, TRUE);
 
   G_OBJECT_CLASS (aisleriot_slot_renderer_parent_class)->finalize (object);
 }
@@ -275,6 +324,14 @@
     cardx += priv->slot->pixeldx;
     cardy += priv->slot->pixeldy;
   }
+
+  /* Paint the animated actors */
+  for (i = 0; i < priv->animations->len; i++) {
+    AnimationData *data = &g_array_index (priv->animations, AnimationData, i);
+
+    if (CLUTTER_ACTOR_IS_VISIBLE (data->card_tex))
+      clutter_actor_paint (data->card_tex);
+  }
 }
 
 guint
@@ -298,3 +355,212 @@
 
   clutter_actor_queue_redraw (CLUTTER_ACTOR (srend));
 }
+
+void
+aisleriot_slot_renderer_set_animations (AisleriotSlotRenderer *srend,
+                                        guint n_anims,
+                                        const AisleriotAnimStart *anims)
+{
+  AisleriotSlotRendererPrivate *priv;
+  guint i;
+  gint card_num;
+
+  g_return_if_fail (AISLERIOT_IS_SLOT_RENDERER (srend));
+
+  priv = srend->priv;
+
+  g_return_if_fail (n_anims <= priv->slot->exposed);
+
+  /* Destroy the current animations */
+  for (i = 0; i < priv->animations->len; i++) {
+    AnimationData *anim_data;
+
+    anim_data = &g_array_index (priv->animations, AnimationData, i);
+
+    if (anim_data->move)
+      g_object_unref (anim_data->move);
+    if (anim_data->rotate)
+      g_object_unref (anim_data->rotate);
+    if (anim_data->depth)
+      g_object_unref (anim_data->depth);
+
+    clutter_actor_destroy (anim_data->card_tex);
+    g_object_unref (anim_data->card_tex);
+  }
+
+  g_array_set_size (priv->animations, 0);
+
+  card_num = priv->slot->cards->len - n_anims;
+
+  for (i = 0; i < n_anims; i++) {
+    AnimationData anim_data;
+    ClutterAlpha *alpha;
+    ClutterKnot knots[2];
+    Card card = CARD (priv->slot->cards->data[card_num]);
+    guint card_width, card_height;
+    CoglHandle cogl_tex;
+
+    memset (&anim_data, 0, sizeof (anim_data));
+
+    anim_data.card_tex = aisleriot_card_new (priv->cache, card);
+    g_object_ref_sink (anim_data.card_tex);
+    clutter_actor_set_parent (anim_data.card_tex, CLUTTER_ACTOR (srend));
+
+    cogl_tex = aisleriot_card_cache_get_card_texture (priv->cache, card, FALSE);
+    card_width = cogl_texture_get_width (cogl_tex);
+    card_height = cogl_texture_get_height (cogl_tex);
+
+    clutter_actor_set_position (anim_data.card_tex,
+                                anims[i].cardx, anims[i].cardy);
+
+    knots[0].x = anims[i].cardx;
+    knots[0].y = anims[i].cardy;
+    knots[1].x = priv->slot->pixeldx * card_num;
+    knots[1].y = priv->slot->pixeldy * card_num;
+
+    alpha = clutter_alpha_new_full (priv->timeline, CLUTTER_ALPHA_RAMP_INC,
+                                    NULL, NULL);
+
+    anim_data.move = clutter_behaviour_path_new (alpha, knots,
+                                                 G_N_ELEMENTS (knots));
+    clutter_behaviour_apply (anim_data.move, anim_data.card_tex);
+
+    if (anims[i].face_down != card.attr.face_down) {
+      gint center_x = card_width / 2;
+      gint center_y = card_height / 2;
+
+      clutter_actor_set_rotation (anim_data.card_tex, CLUTTER_Y_AXIS,
+                                  180.0,
+                                  center_x, center_y, 0);
+
+      anim_data.rotate = clutter_behaviour_rotate_new (alpha,
+                                                       CLUTTER_Y_AXIS,
+                                                       CLUTTER_ROTATE_CW,
+                                                       180.0, 0.0);
+      clutter_behaviour_rotate_set_center (CLUTTER_BEHAVIOUR_ROTATE
+                                           (anim_data.rotate),
+                                           center_x, center_y, 0);
+
+      clutter_behaviour_apply (anim_data.rotate, anim_data.card_tex);
+    }
+
+    alpha = clutter_alpha_new_full (priv->timeline, CLUTTER_ALPHA_SINE,
+                                    NULL, NULL);
+
+    anim_data.depth = clutter_behaviour_depth_new (alpha,
+                                                   0, card_height);
+    clutter_behaviour_apply (anim_data.depth, anim_data.card_tex);
+
+    g_array_append_val (priv->animations, anim_data);
+
+    card_num++;
+  }
+
+  if (n_anims > 0) {
+    clutter_timeline_rewind (priv->timeline);
+    clutter_timeline_start (priv->timeline);
+  }
+
+  clutter_actor_queue_redraw (CLUTTER_ACTOR (srend));
+}
+
+static void
+completed_cb (AisleriotSlotRenderer *srend)
+{
+  /* Get rid of all animation actors */
+  aisleriot_slot_renderer_set_animations (srend, 0, NULL);
+
+  /* Redraw so that the animated actors will be drawn as part of the
+     renderer instead */
+  clutter_actor_queue_redraw (CLUTTER_ACTOR (srend));
+}
+
+static void
+aisleriot_slot_renderer_real_add (ClutterContainer *container,
+                                  ClutterActor     *actor)
+{
+  g_critical ("Do not add actors to an AisleriotSlotRenderer directly");
+}
+
+static void
+aisleriot_slot_renderer_real_remove (ClutterContainer *container,
+                                     ClutterActor     *actor)
+{
+  g_object_ref (actor);
+
+  clutter_actor_unparent (actor);
+
+  clutter_actor_queue_relayout (CLUTTER_ACTOR (container));
+
+  if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (container)))
+    clutter_actor_queue_redraw (CLUTTER_ACTOR (container));
+
+  g_object_unref (actor);
+}
+
+static void
+aisleriot_slot_renderer_real_foreach (ClutterContainer *container,
+                                      ClutterCallback   callback,
+                                      gpointer          user_data)
+{
+  AisleriotSlotRenderer *srend = AISLERIOT_SLOT_RENDERER (container);
+  AisleriotSlotRendererPrivate *priv = srend->priv;
+  guint i;
+
+  for (i = 0; i < priv->animations->len; i++) {
+    AnimationData *data = &g_array_index (priv->animations, AnimationData, i);
+
+    (* callback) (data->card_tex, user_data);
+  }
+}
+
+static void
+aisleriot_slot_renderer_real_raise (ClutterContainer *container,
+                                    ClutterActor     *actor,
+                                    ClutterActor     *sibling)
+{
+}
+
+static void
+aisleriot_slot_renderer_real_lower (ClutterContainer *container,
+                                    ClutterActor     *actor,
+                                    ClutterActor     *sibling)
+{
+}
+
+static void
+aisleriot_slot_renderer_real_sort_depth_order (ClutterContainer *container)
+{
+}
+
+static void
+clutter_container_iface_init (ClutterContainerIface *iface)
+{
+  iface->add = aisleriot_slot_renderer_real_add;
+  iface->remove = aisleriot_slot_renderer_real_remove;
+  iface->foreach = aisleriot_slot_renderer_real_foreach;
+  iface->raise = aisleriot_slot_renderer_real_raise;
+  iface->lower = aisleriot_slot_renderer_real_lower;
+  iface->sort_depth_order = aisleriot_slot_renderer_real_sort_depth_order;
+}
+
+static void
+aisleriot_slot_renderer_allocate (ClutterActor *actor,
+                                  const ClutterActorBox *box,
+                                  gboolean origin_changed)
+{
+  AisleriotSlotRenderer *srend = (AisleriotSlotRenderer *) actor;
+  AisleriotSlotRendererPrivate *priv = srend->priv;
+  guint i;
+
+  /* chain up to set actor->allocation */
+  CLUTTER_ACTOR_CLASS (aisleriot_slot_renderer_parent_class)
+    ->allocate (actor, box, origin_changed);
+
+  for (i = 0; i < priv->animations->len; i++) {
+    AnimationData *anim = &g_array_index (priv->animations, AnimationData, i);
+
+    clutter_actor_allocate_preferred_size (anim->card_tex,
+                                           origin_changed);
+  }
+}

Modified: trunk/aisleriot/slot-renderer.h
==============================================================================
--- trunk/aisleriot/slot-renderer.h	(original)
+++ trunk/aisleriot/slot-renderer.h	Tue Oct 21 19:47:01 2008
@@ -50,6 +50,7 @@
 typedef struct _AisleriotSlotRenderer        AisleriotSlotRenderer;
 typedef struct _AisleriotSlotRendererClass   AisleriotSlotRendererClass;
 typedef struct _AisleriotSlotRendererPrivate AisleriotSlotRendererPrivate;
+typedef struct _AisleriotAnimStart           AisleriotAnimStart;
 
 struct _AisleriotSlotRendererClass
 {
@@ -63,6 +64,12 @@
   AisleriotSlotRendererPrivate *priv;
 };
 
+struct _AisleriotAnimStart
+{
+  gint cardx, cardy;
+  gboolean face_down;
+};
+
 GType aisleriot_slot_renderer_get_type (void) G_GNUC_CONST;
 
 ClutterActor *aisleriot_slot_renderer_new (AisleriotCardCache *cache,
@@ -72,6 +79,10 @@
                                             guint hightlight_start);
 guint aisleriot_slot_renderer_get_highlight (AisleriotSlotRenderer *srend);
 
+void aisleriot_slot_renderer_set_animations (AisleriotSlotRenderer *srend,
+                                             guint n_anims,
+                                             const AisleriotAnimStart *anims);
+
 G_END_DECLS
 
 #endif /* __AISLERIOT_SLOT_RENDERER_H__ */



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