OLD | NEW |
1 /* ply-image.c - png file loader | 1 /* ply-image.c - png file loader |
2 * | 2 * |
3 * Copyright (C) 2006, 2007 Red Hat, Inc. | 3 * Copyright (C) 2006, 2007 Red Hat, Inc. |
4 * Copyright (C) 2003 University of Southern California | 4 * Copyright (C) 2003 University of Southern California |
5 * | 5 * |
6 * This program is free software; you can redistribute it and/or modify | 6 * This program is free software; you can redistribute it and/or modify |
7 * it under the terms of the GNU General Public License as published by | 7 * it under the terms of the GNU General Public License as published by |
8 * the Free Software Foundation; either version 2, or (at your option) | 8 * the Free Software Foundation; either version 2, or (at your option) |
9 * any later version. | 9 * any later version. |
10 * | 10 * |
(...skipping 24 matching lines...) Expand all Loading... |
35 #include <errno.h> | 35 #include <errno.h> |
36 #include <fcntl.h> | 36 #include <fcntl.h> |
37 #include <string.h> | 37 #include <string.h> |
38 #include <stdbool.h> | 38 #include <stdbool.h> |
39 #include <stdint.h> | 39 #include <stdint.h> |
40 #include <stdlib.h> | 40 #include <stdlib.h> |
41 #include <sys/ioctl.h> | 41 #include <sys/ioctl.h> |
42 #include <sys/mman.h> | 42 #include <sys/mman.h> |
43 #include <sys/stat.h> | 43 #include <sys/stat.h> |
44 #include <sys/types.h> | 44 #include <sys/types.h> |
| 45 #include <time.h> |
45 #include <unistd.h> | 46 #include <unistd.h> |
46 #include <math.h> | 47 #include <math.h> |
47 | 48 |
48 #include <png.h> | 49 #include <png.h> |
49 | 50 |
50 #include <linux/fb.h> | 51 #include <linux/fb.h> |
51 | 52 |
52 #include "ply-utils.h" | 53 #include "ply-utils.h" |
53 | 54 |
| 55 #define BILLION (1000 * 1000 * 1000) |
| 56 |
54 | 57 |
55 typedef union | 58 typedef union |
56 { | 59 { |
57 uint32_t *as_pixels; | 60 uint32_t *as_pixels; |
58 png_byte *as_png_bytes; | 61 png_byte *as_png_bytes; |
59 char *address; | 62 char *address; |
60 } ply_image_layout_t; | 63 } ply_image_layout_t; |
61 | 64 |
62 struct _ply_image | 65 struct _ply_image |
63 { | 66 { |
(...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
425 theta -= theta_offset; | 428 theta -= theta_offset; |
426 old_x = center_x + d * cos (theta); | 429 old_x = center_x + d * cos (theta); |
427 old_y = center_y + d * sin (theta); | 430 old_y = center_y + d * sin (theta); |
428 new_image->layout.as_pixels[x + y * width] = | 431 new_image->layout.as_pixels[x + y * width] = |
429 ply_image_interpolate (image, width, height, old_x, old_y); | 432 ply_image_interpolate (image, width, height, old_x, old_y); |
430 } | 433 } |
431 } | 434 } |
432 return new_image; | 435 return new_image; |
433 } | 436 } |
434 | 437 |
| 438 ply_image_t * |
| 439 ply_image_from_file(const char *path) |
| 440 { |
| 441 int exit_code; |
| 442 ply_image_t *image = ply_image_new (path); |
| 443 |
| 444 if (!ply_image_load (image)) |
| 445 { |
| 446 exit_code = errno; |
| 447 perror (path); |
| 448 exit (exit_code); |
| 449 } |
| 450 return image; |
| 451 } |
| 452 |
435 #include "ply-frame-buffer.h" | 453 #include "ply-frame-buffer.h" |
436 | 454 |
437 #include <math.h> | 455 #include <math.h> |
438 #include <signal.h> | 456 #include <signal.h> |
439 #include <stdio.h> | 457 #include <stdio.h> |
440 #include <sys/ioctl.h> | 458 #include <sys/ioctl.h> |
441 #include <sys/time.h> | 459 #include <sys/time.h> |
442 #include <values.h> | 460 #include <values.h> |
443 | 461 |
444 #include <linux/kd.h> | 462 #include <linux/kd.h> |
445 | 463 |
| 464 const int frame_rate = 20; /* Animation frames per second */ |
| 465 int bad_clock = 0; /* Set to 1 if the clock ever returns an error */ |
| 466 |
| 467 void |
| 468 ply_frame_buffer_show_file_at_xy(ply_frame_buffer_t *buffer, const char *path, |
| 469 long x, long y) |
| 470 { |
| 471 ply_image_t *image; |
| 472 uint32_t *data; |
| 473 long width, height; |
| 474 ply_frame_buffer_area_t area; |
| 475 |
| 476 image = ply_image_from_file (path); |
| 477 |
| 478 data = ply_image_get_data (image); |
| 479 width = ply_image_get_width (image); |
| 480 height = ply_image_get_height (image); |
| 481 |
| 482 ply_frame_buffer_get_size (buffer, &area); |
| 483 area.x = (area.width / 2) - (width / 2); // + x; |
| 484 area.y = (area.height / 2) - (height / 2); // + y; |
| 485 area.width = width; |
| 486 area.height = height; |
| 487 |
| 488 ply_frame_buffer_fill (buffer, &area, x, y, data); |
| 489 ply_image_free (image); |
| 490 } |
| 491 |
| 492 /* |
| 493 * Compute the difference in nanoseconds between two timevals. Return 0 if the |
| 494 * clock is not reliable. |
| 495 */ |
| 496 int64_t difference_nsec(struct timespec x, struct timespec y) |
| 497 { |
| 498 int64_t z; |
| 499 |
| 500 if (bad_clock) |
| 501 { |
| 502 return 0; |
| 503 } |
| 504 |
| 505 z = x.tv_sec - y.tv_sec; |
| 506 z *= BILLION; |
| 507 z += x.tv_nsec - y.tv_nsec; |
| 508 return z; |
| 509 } |
| 510 |
| 511 |
| 512 void gettime_check(struct timespec *ts) |
| 513 { |
| 514 int r = clock_gettime(CLOCK_MONOTONIC, ts); |
| 515 if (r) |
| 516 { |
| 517 bad_clock = 1; |
| 518 } |
| 519 } |
| 520 |
| 521 |
| 522 int usage(void) |
| 523 { |
| 524 fprintf(stderr, |
| 525 "usage: ply-image --clear\n" |
| 526 " ply-image <background> [<x-offset> <y-offset> " |
| 527 "<frame-1> ... <frame-n>]\n"); |
| 528 exit(1); |
| 529 } |
| 530 |
446 | 531 |
447 int | 532 int |
448 main (int argc, | 533 main (int argc, |
449 char **argv) | 534 char **argv) |
450 { | 535 { |
451 ply_image_t *image = NULL; | 536 int exit_code = 0; |
| 537 int clear = 0; |
| 538 int help = 0; |
452 ply_frame_buffer_t *buffer; | 539 ply_frame_buffer_t *buffer; |
453 int exit_code; | 540 int i; |
454 ply_frame_buffer_area_t area; | 541 int xoff, yoff; |
455 uint32_t *data; | 542 char *endptr; |
456 long width, height; | |
457 | |
458 exit_code = 0; | |
459 | 543 |
460 // hide_cursor (); | 544 // hide_cursor (); |
461 | 545 |
462 if (argc != 2 || strcasecmp(argv[1], "-h") == 0 || strcasecmp(argv[1], "--help
") == 0) | 546 /* |
| 547 * Ad-hoc arg parsing, to keep the program small. |
| 548 */ |
| 549 |
| 550 if (argc > 1) |
463 { | 551 { |
464 perror ("usage: ply-image [--clear | <pngImageFile>]"); | 552 clear = strcasecmp (argv[1], "--clear") == 0; |
465 return 1; | 553 help = strcasecmp (argv[1], "--help") == 0 || |
| 554 strcasecmp (argv[1], "-h") == 0; |
466 } | 555 } |
467 | 556 |
468 if (strcasecmp(argv[1], "--clear") != 0) | 557 if (help || argc == 1 || argc == 3 || argc == 4) |
469 { | 558 { |
470 image = ply_image_new (argv[1]); | 559 usage(); |
471 | |
472 if (!ply_image_load (image)) | |
473 { | |
474 exit_code = errno; | |
475 perror ("could not load image"); | |
476 return exit_code; | |
477 } | |
478 } | 560 } |
479 | 561 |
480 buffer = ply_frame_buffer_new (NULL); | 562 buffer = ply_frame_buffer_new (NULL); |
481 | 563 |
482 if (!ply_frame_buffer_open (buffer)) | 564 if (!ply_frame_buffer_open (buffer)) |
483 { | 565 { |
484 exit_code = errno; | 566 exit_code = errno; |
485 perror ("could not open framebuffer"); | 567 perror ("could not open framebuffer"); |
486 return exit_code; | 568 return exit_code; |
487 } | 569 } |
488 | 570 |
489 if (image == NULL) | 571 if (clear) |
490 { | 572 { |
491 ply_frame_buffer_clear (buffer); | 573 ply_frame_buffer_clear (buffer); |
492 } | 574 } |
493 else | 575 else |
494 { | 576 { |
495 data = ply_image_get_data (image); | 577 /* |
496 width = ply_image_get_width (image); | 578 * Display main image. |
497 height = ply_image_get_height (image); | 579 */ |
| 580 ply_frame_buffer_show_file_at_xy (buffer, argv[1], 0, 0); |
498 | 581 |
499 ply_frame_buffer_get_size (buffer, &area); | 582 if (argc >= 4) |
500 area.x = (area.width / 2) - (width / 2); | 583 { |
501 area.y = (area.height / 2) - (height / 2); | 584 /* |
502 area.width = width; | 585 * Animate frames. |
503 area.height = height; | 586 */ |
| 587 struct timespec then, now; |
| 588 int64_t error_nsec; |
| 589 int64_t interval_nsec; |
504 | 590 |
505 ply_frame_buffer_fill (buffer, &area, 0, 0, data); | 591 xoff = strtol (argv[2], &endptr, 10); |
506 ply_image_free (image); | 592 if (endptr == argv[2] || *endptr != '\0') |
| 593 { |
| 594 usage (); |
| 595 } |
| 596 yoff = strtol (argv[3], &endptr, 10); |
| 597 if (endptr == argv[3] || *endptr != '\0') |
| 598 { |
| 599 usage (); |
| 600 } |
| 601 |
| 602 /* |
| 603 * Begin animation. |
| 604 * |
| 605 * The first time around, we don't know how long it takes to draw a |
| 606 * frame, so we assume it's instantaneous. After that, we assume |
| 607 * that the drawing time for the previous cycle is a good estimate |
| 608 * for the next cycle. Errors may be introduced by different frame |
| 609 * size and complexity (PNG decoding). |
| 610 */ |
| 611 error_nsec = 0; |
| 612 interval_nsec = BILLION / frame_rate; |
| 613 gettime_check (&now); |
| 614 |
| 615 for (i = 4; i < argc; i++) |
| 616 { |
| 617 /* |
| 618 * Before displaying the next frame, sleep for the inter-frame |
| 619 * interval, adjusted by the error in the previous cycle. |
| 620 * Positive error means the last cycle took longer than desired. |
| 621 */ |
| 622 if (interval_nsec - error_nsec > 0) |
| 623 { |
| 624 struct timespec req; |
| 625 req.tv_sec = (interval_nsec - error_nsec) / BILLION; |
| 626 req.tv_nsec = (interval_nsec - error_nsec) % BILLION; |
| 627 nanosleep (&req, NULL); |
| 628 } |
| 629 ply_frame_buffer_show_file_at_xy (buffer, argv[i], xoff, yoff); |
| 630 then = now; |
| 631 gettime_check (&now); |
| 632 error_nsec = difference_nsec (now, then) - interval_nsec; |
| 633 } |
| 634 } |
507 } | 635 } |
508 | 636 |
509 ply_frame_buffer_close (buffer); | 637 // Skip these to save time. |
510 ply_frame_buffer_free (buffer); | 638 // ply_frame_buffer_close (buffer); |
| 639 // ply_frame_buffer_free (buffer); |
511 | 640 |
512 return exit_code; | 641 return exit_code; |
513 } | 642 } |
OLD | NEW |