[PATCH 3/5] add simple one time animation helper
William Jon McCann
william.jon.mccann at gmail.com
Wed Mar 4 12:22:24 PST 2009
From: William Jon McCann <jmccann at redhat.com>
This will play a sequence of images from beginning to end at
a fixed frame rate. It differs from the throbber in that it starts
at the 0th image and does not repeat.
---
src/libplybootsplash/Makefile.am | 5 +-
src/libplybootsplash/ply-animator.c | 396 +++++++++++++++++++++++++++++++++++
src/libplybootsplash/ply-animator.h | 56 +++++
3 files changed, 455 insertions(+), 2 deletions(-)
create mode 100644 src/libplybootsplash/ply-animator.c
create mode 100644 src/libplybootsplash/ply-animator.h
diff --git a/src/libplybootsplash/Makefile.am b/src/libplybootsplash/Makefile.am
index 54feb0e..3fa644b 100644
--- a/src/libplybootsplash/Makefile.am
+++ b/src/libplybootsplash/Makefile.am
@@ -6,7 +6,7 @@ INCLUDES = -I$(top_srcdir) \
lib_LTLIBRARIES = libplybootsplash.la
libplybootsplashdir = $(includedir)/plymouth-1/plybootsplash
-libplybootsplash_HEADERS = ply-entry.h ply-image.h ply-progress-bar.h ply-text-progress-bar.h ply-text-pulser.h ply-throbber.h ply-window.h ply-label.h ply-boot-splash-plugin.h ply-label-plugin.h
+libplybootsplash_HEADERS = ply-entry.h ply-image.h ply-progress-bar.h ply-text-progress-bar.h ply-text-pulser.h ply-throbber.h ply-animator.h ply-window.h ply-label.h ply-boot-splash-plugin.h ply-label-plugin.h
libplybootsplash_la_CFLAGS = $(PLYMOUTH_CFLAGS) \
$(IMAGE_CFLAGS) \
@@ -25,8 +25,9 @@ libplybootsplash_la_SOURCES = \
ply-label.c \
ply-progress-bar.c \
ply-throbber.c \
+ ply-animator.c \
ply-text-progress-bar.c \
ply-text-pulser.c \
- ply-window.c
+ ply-window.c
MAINTAINERCLEANFILES = Makefile.in
diff --git a/src/libplybootsplash/ply-animator.c b/src/libplybootsplash/ply-animator.c
new file mode 100644
index 0000000..03dc2bc
--- /dev/null
+++ b/src/libplybootsplash/ply-animator.c
@@ -0,0 +1,396 @@
+/* animator.c - boot animator
+ *
+ * Copyright (C) 2007, 2008 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written by: Ray Strode <rstrode at redhat.com>
+ */
+#include "config.h"
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <values.h>
+#include <unistd.h>
+#include <wchar.h>
+
+#include "ply-animator.h"
+#include "ply-event-loop.h"
+#include "ply-array.h"
+#include "ply-logger.h"
+#include "ply-frame-buffer.h"
+#include "ply-image.h"
+#include "ply-utils.h"
+#include "ply-window.h"
+
+#include <linux/kd.h>
+
+#ifndef FRAMES_PER_SECOND
+#define FRAMES_PER_SECOND 30
+#endif
+
+struct _ply_animator
+{
+ ply_array_t *frames;
+ ply_event_loop_t *loop;
+ char *image_dir;
+ char *frames_prefix;
+
+ ply_window_t *window;
+ ply_frame_buffer_t *frame_buffer;
+ ply_frame_buffer_area_t frame_area;
+ ply_trigger_t *stop_trigger;
+
+ int frame_number;
+ long x, y;
+ long width, height;
+ double start_time, previous_time, now;
+ uint32_t is_stopped : 1;
+};
+
+ply_animator_t *
+ply_animator_new (const char *image_dir,
+ const char *frames_prefix)
+{
+ ply_animator_t *animator;
+
+ assert (image_dir != NULL);
+ assert (frames_prefix != NULL);
+
+ animator = calloc (1, sizeof (ply_animator_t));
+
+ animator->frames = ply_array_new ();
+ animator->frames_prefix = strdup (frames_prefix);
+ animator->image_dir = strdup (image_dir);
+ animator->frame_number = 0;
+ animator->is_stopped = true;
+ animator->width = 0;
+ animator->height = 0;
+ animator->frame_area.width = 0;
+ animator->frame_area.height = 0;
+ animator->frame_area.x = 0;
+ animator->frame_area.y = 0;
+
+ return animator;
+}
+
+static void
+ply_animator_remove_frames (ply_animator_t *animator)
+{
+ int i;
+ ply_image_t **frames;
+
+ frames = (ply_image_t **) ply_array_steal_elements (animator->frames);
+ for (i = 0; frames[i] != NULL; i++)
+ ply_image_free (frames[i]);
+ free (frames);
+}
+
+void
+ply_animator_free (ply_animator_t *animator)
+{
+ if (animator == NULL)
+ return;
+
+ ply_animator_remove_frames (animator);
+ ply_array_free (animator->frames);
+
+ free (animator->frames_prefix);
+ free (animator->image_dir);
+ free (animator);
+}
+
+static void
+draw_background (ply_animator_t *animator)
+{
+ ply_window_erase_area (animator->window,
+ animator->x, animator->y,
+ animator->frame_area.width,
+ animator->frame_area.height);
+}
+
+static bool
+animate_at_time (ply_animator_t *animator,
+ double time)
+{
+ int number_of_frames;
+ ply_image_t * const * frames;
+ uint32_t *frame_data;
+ bool should_continue;
+
+ ply_window_set_mode (animator->window, PLY_WINDOW_MODE_GRAPHICS);
+
+ number_of_frames = ply_array_get_size (animator->frames);
+
+ if (number_of_frames == 0)
+ return true;
+
+ should_continue = true;
+
+ if (animator->frame_number >= number_of_frames - 1)
+ animator->frame_number = number_of_frames - 1;
+
+ if (animator->stop_trigger != NULL)
+ {
+ should_continue = false;
+ }
+
+ ply_frame_buffer_pause_updates (animator->frame_buffer);
+ if (animator->frame_area.width > 0)
+ draw_background (animator);
+
+ frames = (ply_image_t * const *) ply_array_get_elements (animator->frames);
+
+ animator->frame_area.x = animator->x;
+ animator->frame_area.y = animator->y;
+ animator->frame_area.width = ply_image_get_width (frames[animator->frame_number]);
+ animator->frame_area.height = ply_image_get_height (frames[animator->frame_number]);
+ frame_data = ply_image_get_data (frames[animator->frame_number]);
+
+ ply_frame_buffer_fill_with_argb32_data (animator->frame_buffer,
+ &animator->frame_area, 0, 0,
+ frame_data);
+ ply_frame_buffer_unpause_updates (animator->frame_buffer);
+
+ animator->frame_number++;
+
+ return should_continue;
+}
+
+static void
+on_timeout (ply_animator_t *animator)
+{
+ double sleep_time;
+ bool should_continue;
+ animator->previous_time = animator->now;
+ animator->now = ply_get_timestamp ();
+
+#ifdef REAL_TIME_ANIMATION
+ should_continue = animate_at_time (animator,
+ animator->now - animator->start_time);
+#else
+ static double time = 0.0;
+ time += 1.0 / FRAMES_PER_SECOND;
+ should_continue = animate_at_time (animator, time);
+#endif
+
+ sleep_time = 1.0 / FRAMES_PER_SECOND;
+ sleep_time = MAX (sleep_time - (ply_get_timestamp () - animator->now),
+ 0.005);
+
+ if (!should_continue)
+ {
+
+ draw_background (animator);
+
+ if (animator->stop_trigger != NULL)
+ {
+ ply_trigger_pull (animator->stop_trigger, NULL);
+ animator->stop_trigger = NULL;
+ }
+ }
+ else
+ {
+ ply_event_loop_watch_for_timeout (animator->loop,
+ sleep_time,
+ (ply_event_loop_timeout_handler_t)
+ on_timeout, animator);
+ }
+}
+
+static bool
+ply_animator_add_frame (ply_animator_t *animator,
+ const char *filename)
+{
+ ply_image_t *image;
+
+ image = ply_image_new (filename);
+
+ if (!ply_image_load (image))
+ {
+ ply_image_free (image);
+ return false;
+ }
+
+ ply_array_add_element (animator->frames, image);
+
+ animator->width = MAX (animator->width, ply_image_get_width (image));
+ animator->height = MAX (animator->height, ply_image_get_height (image));
+
+ return true;
+}
+
+static bool
+ply_animator_add_frames (ply_animator_t *animator)
+{
+ struct dirent **entries;
+ int number_of_entries;
+ int i;
+ bool load_finished;
+
+ entries = NULL;
+
+ number_of_entries = scandir (animator->image_dir, &entries, NULL, versionsort);
+
+ if (number_of_entries < 0)
+ return false;
+
+ load_finished = false;
+ for (i = 0; i < number_of_entries; i++)
+ {
+ if (strncmp (entries[i]->d_name,
+ animator->frames_prefix,
+ strlen (animator->frames_prefix)) == 0
+ && (strlen (entries[i]->d_name) > 4)
+ && strcmp (entries[i]->d_name + strlen (entries[i]->d_name) - 4, ".png") == 0)
+ {
+ char *filename;
+
+ filename = NULL;
+ asprintf (&filename, "%s/%s", animator->image_dir, entries[i]->d_name);
+
+ if (!ply_animator_add_frame (animator, filename))
+ goto out;
+
+ free (filename);
+ }
+
+ free (entries[i]);
+ entries[i] = NULL;
+ }
+ load_finished = true;
+
+out:
+ if (!load_finished)
+ {
+ ply_animator_remove_frames (animator);
+
+ while (entries[i] != NULL)
+ {
+ free (entries[i]);
+ i++;
+ }
+ }
+ free (entries);
+
+ return load_finished;
+}
+
+bool
+ply_animator_load (ply_animator_t *animator)
+{
+ if (ply_array_get_size (animator->frames) != 0)
+ ply_animator_remove_frames (animator->frames);
+
+ if (!ply_animator_add_frames (animator))
+ return false;
+
+ return true;
+}
+
+bool
+ply_animator_start (ply_animator_t *animator,
+ ply_event_loop_t *loop,
+ ply_window_t *window,
+ long x,
+ long y)
+{
+ assert (animator != NULL);
+ assert (animator->loop == NULL);
+
+ animator->loop = loop;
+ animator->window = window;
+ animator->frame_buffer = ply_window_get_frame_buffer (window);;
+ animator->is_stopped = false;
+
+ animator->x = x;
+ animator->y = y;
+
+ animator->start_time = ply_get_timestamp ();
+
+ ply_event_loop_watch_for_timeout (animator->loop,
+ 1.0 / FRAMES_PER_SECOND,
+ (ply_event_loop_timeout_handler_t)
+ on_timeout, animator);
+
+ return true;
+}
+
+static void
+ply_animator_stop_now (ply_animator_t *animator)
+{
+ if (animator->frame_area.width > 0)
+ draw_background (animator);
+
+ animator->frame_buffer = NULL;
+ animator->window = NULL;
+ animator->is_stopped = true;
+
+ if (animator->loop != NULL)
+ {
+ ply_event_loop_stop_watching_for_timeout (animator->loop,
+ (ply_event_loop_timeout_handler_t)
+ on_timeout, animator);
+ animator->loop = NULL;
+ }
+}
+
+void
+ply_animator_stop (ply_animator_t *animator,
+ ply_trigger_t *stop_trigger)
+{
+
+ if (stop_trigger == NULL)
+ {
+ ply_animator_stop_now (animator);
+ return;
+ }
+
+ animator->stop_trigger = stop_trigger;
+}
+
+bool
+ply_animator_is_stopped (ply_animator_t *animator)
+{
+ return animator->is_stopped;
+}
+
+long
+ply_animator_get_width (ply_animator_t *animator)
+{
+ return animator->width;
+}
+
+long
+ply_animator_get_height (ply_animator_t *animator)
+{
+ return animator->height;
+}
+
+/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
diff --git a/src/libplybootsplash/ply-animator.h b/src/libplybootsplash/ply-animator.h
new file mode 100644
index 0000000..08e0560
--- /dev/null
+++ b/src/libplybootsplash/ply-animator.h
@@ -0,0 +1,56 @@
+/* animator.h - simple animator animation
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written By: Ray Strode <rstrode at redhat.com>
+ */
+#ifndef ANIMATOR_H
+#define ANIMATOR_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include "ply-event-loop.h"
+#include "ply-frame-buffer.h"
+#include "ply-trigger.h"
+#include "ply-window.h"
+
+typedef struct _ply_animator ply_animator_t;
+
+#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
+ply_animator_t *ply_animator_new (const char *image_dir,
+ const char *frames_prefix);
+void ply_animator_free (ply_animator_t *animator);
+
+bool ply_animator_load (ply_animator_t *animator);
+bool ply_animator_start (ply_animator_t *animator,
+ ply_event_loop_t *loop,
+ ply_window_t *window,
+ long x,
+ long y);
+void ply_animator_stop (ply_animator_t *animator,
+ ply_trigger_t *stop_trigger);
+bool ply_animator_is_stopped (ply_animator_t *animator);
+
+long ply_animator_get_width (ply_animator_t *animator);
+long ply_animator_get_height (ply_animator_t *animator);
+#endif
+
+#endif /* ANIMATOR_H */
+/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
--
1.6.1.3
More information about the plymouth
mailing list