| Index: src/ply-image.c
|
| diff --git a/src/ply-image.c b/src/ply-image.c
|
| index a9375ab9f97111794bf2df87ee1591b4a273be3c..58e1daea3d5050723e5024557fb555cbb1f46d1f 100644
|
| --- a/src/ply-image.c
|
| +++ b/src/ply-image.c
|
| @@ -42,6 +42,7 @@
|
| #include <sys/mman.h>
|
| #include <sys/stat.h>
|
| #include <sys/types.h>
|
| +#include <time.h>
|
| #include <unistd.h>
|
| #include <math.h>
|
|
|
| @@ -51,6 +52,8 @@
|
|
|
| #include "ply-utils.h"
|
|
|
| +#define BILLION (1000 * 1000 * 1000)
|
| +
|
|
|
| typedef union
|
| {
|
| @@ -432,6 +435,21 @@ ply_image_rotate (ply_image_t *image,
|
| return new_image;
|
| }
|
|
|
| +ply_image_t *
|
| +ply_image_from_file(const char *path)
|
| +{
|
| + int exit_code;
|
| + ply_image_t *image = ply_image_new (path);
|
| +
|
| + if (!ply_image_load (image))
|
| + {
|
| + exit_code = errno;
|
| + perror (path);
|
| + exit (exit_code);
|
| + }
|
| + return image;
|
| +}
|
| +
|
| #include "ply-frame-buffer.h"
|
|
|
| #include <math.h>
|
| @@ -443,38 +461,102 @@ ply_image_rotate (ply_image_t *image,
|
|
|
| #include <linux/kd.h>
|
|
|
| +const int frame_rate = 20; /* Animation frames per second */
|
| +int bad_clock = 0; /* Set to 1 if the clock ever returns an error */
|
| +
|
| +void
|
| +ply_frame_buffer_show_file_at_xy(ply_frame_buffer_t *buffer, const char *path,
|
| + long x, long y)
|
| +{
|
| + ply_image_t *image;
|
| + uint32_t *data;
|
| + long width, height;
|
| + ply_frame_buffer_area_t area;
|
| +
|
| + image = ply_image_from_file (path);
|
| +
|
| + data = ply_image_get_data (image);
|
| + width = ply_image_get_width (image);
|
| + height = ply_image_get_height (image);
|
| +
|
| + ply_frame_buffer_get_size (buffer, &area);
|
| + area.x = (area.width / 2) - (width / 2); // + x;
|
| + area.y = (area.height / 2) - (height / 2); // + y;
|
| + area.width = width;
|
| + area.height = height;
|
| +
|
| + ply_frame_buffer_fill (buffer, &area, x, y, data);
|
| + ply_image_free (image);
|
| +}
|
| +
|
| +/*
|
| + * Compute the difference in nanoseconds between two timevals. Return 0 if the
|
| + * clock is not reliable.
|
| + */
|
| +int64_t difference_nsec(struct timespec x, struct timespec y)
|
| +{
|
| + int64_t z;
|
| +
|
| + if (bad_clock)
|
| + {
|
| + return 0;
|
| + }
|
| +
|
| + z = x.tv_sec - y.tv_sec;
|
| + z *= BILLION;
|
| + z += x.tv_nsec - y.tv_nsec;
|
| + return z;
|
| +}
|
| +
|
| +
|
| +void gettime_check(struct timespec *ts)
|
| +{
|
| + int r = clock_gettime(CLOCK_MONOTONIC, ts);
|
| + if (r)
|
| + {
|
| + bad_clock = 1;
|
| + }
|
| +}
|
| +
|
| +
|
| +int usage(void)
|
| +{
|
| + fprintf(stderr,
|
| + "usage: ply-image --clear\n"
|
| + " ply-image <background> [<x-offset> <y-offset> "
|
| + "<frame-1> ... <frame-n>]\n");
|
| + exit(1);
|
| +}
|
| +
|
|
|
| int
|
| main (int argc,
|
| char **argv)
|
| {
|
| - ply_image_t *image = NULL;
|
| + int exit_code = 0;
|
| + int clear = 0;
|
| + int help = 0;
|
| ply_frame_buffer_t *buffer;
|
| - int exit_code;
|
| - ply_frame_buffer_area_t area;
|
| - uint32_t *data;
|
| - long width, height;
|
| -
|
| - exit_code = 0;
|
| + int i;
|
| + int xoff, yoff;
|
| + char *endptr;
|
|
|
| // hide_cursor ();
|
|
|
| - if (argc != 2 || strcasecmp(argv[1], "-h") == 0 || strcasecmp(argv[1], "--help") == 0)
|
| + /*
|
| + * Ad-hoc arg parsing, to keep the program small.
|
| + */
|
| +
|
| + if (argc > 1)
|
| {
|
| - perror ("usage: ply-image [--clear | <pngImageFile>]");
|
| - return 1;
|
| + clear = strcasecmp (argv[1], "--clear") == 0;
|
| + help = strcasecmp (argv[1], "--help") == 0 ||
|
| + strcasecmp (argv[1], "-h") == 0;
|
| }
|
|
|
| - if (strcasecmp(argv[1], "--clear") != 0)
|
| + if (help || argc == 1 || argc == 3 || argc == 4)
|
| {
|
| - image = ply_image_new (argv[1]);
|
| -
|
| - if (!ply_image_load (image))
|
| - {
|
| - exit_code = errno;
|
| - perror ("could not load image");
|
| - return exit_code;
|
| - }
|
| + usage();
|
| }
|
|
|
| buffer = ply_frame_buffer_new (NULL);
|
| @@ -486,28 +568,75 @@ main (int argc,
|
| return exit_code;
|
| }
|
|
|
| - if (image == NULL)
|
| + if (clear)
|
| {
|
| ply_frame_buffer_clear (buffer);
|
| }
|
| else
|
| {
|
| - data = ply_image_get_data (image);
|
| - width = ply_image_get_width (image);
|
| - height = ply_image_get_height (image);
|
| -
|
| - ply_frame_buffer_get_size (buffer, &area);
|
| - area.x = (area.width / 2) - (width / 2);
|
| - area.y = (area.height / 2) - (height / 2);
|
| - area.width = width;
|
| - area.height = height;
|
| -
|
| - ply_frame_buffer_fill (buffer, &area, 0, 0, data);
|
| - ply_image_free (image);
|
| + /*
|
| + * Display main image.
|
| + */
|
| + ply_frame_buffer_show_file_at_xy (buffer, argv[1], 0, 0);
|
| +
|
| + if (argc >= 4)
|
| + {
|
| + /*
|
| + * Animate frames.
|
| + */
|
| + struct timespec then, now;
|
| + int64_t error_nsec;
|
| + int64_t interval_nsec;
|
| +
|
| + xoff = strtol (argv[2], &endptr, 10);
|
| + if (endptr == argv[2] || *endptr != '\0')
|
| + {
|
| + usage ();
|
| + }
|
| + yoff = strtol (argv[3], &endptr, 10);
|
| + if (endptr == argv[3] || *endptr != '\0')
|
| + {
|
| + usage ();
|
| + }
|
| +
|
| + /*
|
| + * Begin animation.
|
| + *
|
| + * The first time around, we don't know how long it takes to draw a
|
| + * frame, so we assume it's instantaneous. After that, we assume
|
| + * that the drawing time for the previous cycle is a good estimate
|
| + * for the next cycle. Errors may be introduced by different frame
|
| + * size and complexity (PNG decoding).
|
| + */
|
| + error_nsec = 0;
|
| + interval_nsec = BILLION / frame_rate;
|
| + gettime_check (&now);
|
| +
|
| + for (i = 4; i < argc; i++)
|
| + {
|
| + /*
|
| + * Before displaying the next frame, sleep for the inter-frame
|
| + * interval, adjusted by the error in the previous cycle.
|
| + * Positive error means the last cycle took longer than desired.
|
| + */
|
| + if (interval_nsec - error_nsec > 0)
|
| + {
|
| + struct timespec req;
|
| + req.tv_sec = (interval_nsec - error_nsec) / BILLION;
|
| + req.tv_nsec = (interval_nsec - error_nsec) % BILLION;
|
| + nanosleep (&req, NULL);
|
| + }
|
| + ply_frame_buffer_show_file_at_xy (buffer, argv[i], xoff, yoff);
|
| + then = now;
|
| + gettime_check (&now);
|
| + error_nsec = difference_nsec (now, then) - interval_nsec;
|
| + }
|
| + }
|
| }
|
|
|
| - ply_frame_buffer_close (buffer);
|
| - ply_frame_buffer_free (buffer);
|
| + // Skip these to save time.
|
| + // ply_frame_buffer_close (buffer);
|
| + // ply_frame_buffer_free (buffer);
|
|
|
| return exit_code;
|
| }
|
|
|