Index: src/ply-image.c |
diff --git a/src/ply-image.c b/src/ply-image.c |
index a9375ab9f97111794bf2df87ee1591b4a273be3c..eae8f551b207f248684d74e587de06f790b98ccd 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> |
@@ -432,6 +433,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 +459,97 @@ ply_image_rotate (ply_image_t *image, |
#include <linux/kd.h> |
+const int frame_rate = 15; /* Animation frames per second */ |
+int bad_gettimeofday = 0; /* Set to 1 if gettimeofday 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 microseconds between two timevals. Return 0 if |
+ * gettimeofday is not reliable. Don't worry about overflows. |
+ */ |
+int difference_usec(struct timeval x, struct timeval y) |
+{ |
+ if (bad_gettimeofday) |
+ { |
+ return 0; |
+ } |
+ |
+ return (x.tv_sec - y.tv_sec) * (1000 * 1000) + x.tv_usec - y.tv_usec; |
+} |
+ |
+ |
+void gettimeofday_check(struct timeval *tv) |
+{ |
+ int r = gettimeofday(tv, NULL); |
Daniel Erat
2010/12/14 00:41:15
If there's any danger of the system clock being ch
|
+ if (r) |
+ { |
+ bad_gettimeofday = 1; |
+ } |
+} |
+ |
+ |
+int usage(void) |
+{ |
+ fprintf(stderr, |
+ "usage: ply-image --clear\n" |
+ " ply-image <background> [<x-offset> <y-offset> " |
+ "<frame-1> ... <frame-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 +561,57 @@ 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 timeval then, now; |
+ |
+ 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 (); |
+ } |
+ |
+ gettimeofday_check (&then); |
+ for (i = 4; i < argc; i++) |
+ { |
+ struct timespec req; |
+ int elapsed_usec; |
+ gettimeofday_check (&now); |
+ elapsed_usec = difference_usec (now, then); |
+ req.tv_sec = 0; |
+ req.tv_nsec = ((1000 * 1000) / frame_rate - elapsed_usec) * 1000; |
+ if (req.tv_nsec > 0) |
+ { |
+ nanosleep (&req, NULL); |
+ } |
+ gettimeofday_check (&then); |
+ ply_frame_buffer_show_file_at_xy (buffer, argv[i], xoff, yoff); |
+ } |
+ } |
} |
- 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; |
} |