Index: src/ply-image.c |
diff --git a/src/ply-image.c b/src/ply-image.c |
index a9375ab9f97111794bf2df87ee1591b4a273be3c..afe2a7766dd32c9e6bc7ac59236258ed2cc8b831 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 microseconds 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,66 @@ 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 (); |
+ } |
+ |
+ error_nsec = 0; |
+ interval_nsec = BILLION / frame_rate; |
+ gettime_check (&now); |
+ |
+ for (i = 4; i < argc; i++) |
+ { |
+ struct timespec req; |
+ /* |
+ * 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. |
+ */ |
+ req.tv_sec = (interval_nsec - error_nsec) / BILLION; |
+ req.tv_nsec = (interval_nsec - error_nsec) % BILLION; |
+ if (req.tv_nsec > 0) |
Daniel Erat
2010/12/14 19:11:02
this is wrong if e.g. tv_sec is 1 and tv_nsec is 0
|
+ { |
+ 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; |
Daniel Erat
2010/12/14 19:11:02
i'm not sure i understand this. say that 'frame_r
|
+ } |
+ } |
} |
- 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; |
} |