Chromium Code Reviews| Index: src/ply-image.c |
| diff --git a/src/ply-image.c b/src/ply-image.c |
| index a9375ab9f97111794bf2df87ee1591b4a273be3c..ae5c75a1408f1f98fad21b128c131f1a193655ef 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 |
|
Daniel Erat
2010/12/14 20:22:53
s/microseconds/nanoseconds/
|
| + * 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; |
|
Daniel Erat
2010/12/14 20:10:37
i still don't get it. this code would make sense
|
| + } |
| + } |
| } |
| - 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; |
| } |