├── README ├── ascii8x8.py ├── effects.py ├── run.py └── wall.py /README: -------------------------------------------------------------------------------- 1 | ColorWall 2 | --------- 3 | 4 | ColorWall is a minimal implementation of the visualizer part of the allegro 5 | project (https://github.com/vishnubob/allegro). 6 | 7 | ColorWall is a simple framework for implementing and displaying effects for a 8 | wall of pixels. To add a new effect, create a class in effects.py inheriting 9 | from Effect and implement the run() method. Add the new effect to the Effects 10 | list at the bottom of the file. ColorWall comes with a few example effects. 11 | 12 | Watch an example ColorWall at http://vimeo.com/16522975. 13 | 14 | ColorWall's pixels speak HSV (http://en.wikipedia.org/wiki/HSL_and_HSV). 15 | 16 | 17 | Dependencies 18 | ------------ 19 | 20 | Tkinter, a GUI-programming toolkit for Python: http://wiki.python.org/moin/TkInter 21 | 22 | To see if you have Tkinter installed, at a Python prompt run: 23 | 24 | >>> import Tkinter 25 | 26 | 27 | Usage 28 | ----- 29 | 30 | To run the ColorWall: 31 | 32 | python run.py 33 | 34 | This will run your effects on the default 8x8 pixel wall. To change the width 35 | and height of the wall, pass the -w and -t options, e.g.: 36 | 37 | python run.py -w 5 -t 10 38 | 39 | To run only specific effects, pass the effect names on the commandline. e.g.: 40 | 41 | python run.py Rainbow Twinkle KnightMoves 42 | -------------------------------------------------------------------------------- /ascii8x8.py: -------------------------------------------------------------------------------- 1 | # This file is adapted from the ascii8x8.py in the Allegro project 2 | # hosted at https://github.com/vishnubob/allegro. 3 | 4 | def draw_chr(ch, wall, foreground, background, x_offset=0, y_offset=0): 5 | """ 6 | Draw an 8 x 8 ASCII character. 7 | 8 | ch: the ASCII integer for a character 9 | wall: Wall object 10 | foreground: a 3-element tuple of hsv values 11 | background: a 3-element tuple of hsv values 12 | x_offset: integer 13 | y_offset: integer 14 | """ 15 | font = Font8x8[ord(ch)] 16 | for y, row in enumerate(font): 17 | for x, col in enumerate(row): 18 | if col == '#': 19 | wall.set_pixel(x + x_offset, y + y_offset, background) 20 | else: 21 | wall.set_pixel(x + x_offset, y + y_offset, foreground) 22 | 23 | Font8x8 = ( 24 | ( 25 | ("########"), 26 | ("########"), 27 | ("########"), 28 | ("########"), 29 | ("########"), 30 | ("########"), 31 | ("########"), 32 | ("########") 33 | ), 34 | ( 35 | ("########"), 36 | ("########"), 37 | ("########"), 38 | ("########"), 39 | ("########"), 40 | ("########"), 41 | ("########"), 42 | ("########") 43 | ), 44 | ( 45 | ("########"), 46 | ("########"), 47 | ("########"), 48 | ("########"), 49 | ("########"), 50 | ("########"), 51 | ("########"), 52 | ("########") 53 | ), 54 | ( 55 | ("########"), 56 | ("########"), 57 | ("########"), 58 | ("########"), 59 | ("########"), 60 | ("########"), 61 | ("########"), 62 | ("########") 63 | ), 64 | ( 65 | ("########"), 66 | ("########"), 67 | ("########"), 68 | ("########"), 69 | ("########"), 70 | ("########"), 71 | ("########"), 72 | ("########") 73 | ), 74 | ( 75 | ("########"), 76 | ("########"), 77 | ("########"), 78 | ("########"), 79 | ("########"), 80 | ("########"), 81 | ("########"), 82 | ("########") 83 | ), 84 | ( 85 | ("########"), 86 | ("########"), 87 | ("########"), 88 | ("########"), 89 | ("########"), 90 | ("########"), 91 | ("########"), 92 | ("########") 93 | ), 94 | ( 95 | ("########"), 96 | ("########"), 97 | ("########"), 98 | ("########"), 99 | ("########"), 100 | ("########"), 101 | ("########"), 102 | ("########") 103 | ), 104 | ( 105 | ("########"), 106 | ("########"), 107 | ("########"), 108 | ("########"), 109 | ("########"), 110 | ("########"), 111 | ("########"), 112 | ("########") 113 | ), 114 | ( 115 | ("########"), 116 | ("########"), 117 | ("########"), 118 | ("########"), 119 | ("########"), 120 | ("########"), 121 | ("########"), 122 | ("########") 123 | ), 124 | ( 125 | ("########"), 126 | ("########"), 127 | ("########"), 128 | ("########"), 129 | ("########"), 130 | ("########"), 131 | ("########"), 132 | ("########") 133 | ), 134 | ( 135 | ("########"), 136 | ("########"), 137 | ("########"), 138 | ("########"), 139 | ("########"), 140 | ("########"), 141 | ("########"), 142 | ("########") 143 | ), 144 | ( 145 | ("########"), 146 | ("########"), 147 | ("########"), 148 | ("########"), 149 | ("########"), 150 | ("########"), 151 | ("########"), 152 | ("########") 153 | ), 154 | ( 155 | ("########"), 156 | ("########"), 157 | ("########"), 158 | ("########"), 159 | ("########"), 160 | ("########"), 161 | ("########"), 162 | ("########") 163 | ), 164 | ( 165 | ("########"), 166 | ("########"), 167 | ("########"), 168 | ("########"), 169 | ("########"), 170 | ("########"), 171 | ("########"), 172 | ("########") 173 | ), 174 | ( 175 | ("########"), 176 | ("########"), 177 | ("########"), 178 | ("########"), 179 | ("########"), 180 | ("########"), 181 | ("########"), 182 | ("########") 183 | ), 184 | ( 185 | ("########"), 186 | ("########"), 187 | ("########"), 188 | ("########"), 189 | ("########"), 190 | ("########"), 191 | ("########"), 192 | ("########") 193 | ), 194 | ( 195 | ("########"), 196 | ("########"), 197 | ("########"), 198 | ("########"), 199 | ("########"), 200 | ("########"), 201 | ("########"), 202 | ("########") 203 | ), 204 | ( 205 | ("########"), 206 | ("########"), 207 | ("########"), 208 | ("########"), 209 | ("########"), 210 | ("########"), 211 | ("########"), 212 | ("########") 213 | ), 214 | ( 215 | ("########"), 216 | ("########"), 217 | ("########"), 218 | ("########"), 219 | ("########"), 220 | ("########"), 221 | ("########"), 222 | ("########") 223 | ), 224 | ( 225 | ("########"), 226 | ("########"), 227 | ("########"), 228 | ("########"), 229 | ("########"), 230 | ("########"), 231 | ("########"), 232 | ("########") 233 | ), 234 | ( 235 | ("########"), 236 | ("########"), 237 | ("########"), 238 | ("########"), 239 | ("########"), 240 | ("########"), 241 | ("########"), 242 | ("########") 243 | ), 244 | ( 245 | ("########"), 246 | ("########"), 247 | ("########"), 248 | ("########"), 249 | ("########"), 250 | ("########"), 251 | ("########"), 252 | ("########") 253 | ), 254 | ( 255 | ("########"), 256 | ("########"), 257 | ("########"), 258 | ("########"), 259 | ("########"), 260 | ("########"), 261 | ("########"), 262 | ("########") 263 | ), 264 | ( 265 | ("########"), 266 | ("########"), 267 | ("########"), 268 | ("########"), 269 | ("########"), 270 | ("########"), 271 | ("########"), 272 | ("########") 273 | ), 274 | ( 275 | ("########"), 276 | ("########"), 277 | ("########"), 278 | ("########"), 279 | ("########"), 280 | ("########"), 281 | ("########"), 282 | ("########") 283 | ), 284 | ( 285 | ("########"), 286 | ("########"), 287 | ("########"), 288 | ("########"), 289 | ("########"), 290 | ("########"), 291 | ("########"), 292 | ("########") 293 | ), 294 | ( 295 | ("########"), 296 | ("########"), 297 | ("########"), 298 | ("########"), 299 | ("########"), 300 | ("########"), 301 | ("########"), 302 | ("########") 303 | ), 304 | ( 305 | ("########"), 306 | ("########"), 307 | ("########"), 308 | ("########"), 309 | ("########"), 310 | ("########"), 311 | ("########"), 312 | ("########") 313 | ), 314 | ( 315 | ("########"), 316 | ("########"), 317 | ("########"), 318 | ("########"), 319 | ("########"), 320 | ("########"), 321 | ("########"), 322 | ("########") 323 | ), 324 | ( 325 | ("########"), 326 | ("########"), 327 | ("########"), 328 | ("########"), 329 | ("########"), 330 | ("########"), 331 | ("########"), 332 | ("########") 333 | ), 334 | ( 335 | ("########"), 336 | ("########"), 337 | ("########"), 338 | ("########"), 339 | ("########"), 340 | ("########"), 341 | ("########"), 342 | ("########") 343 | ), 344 | ( 345 | ("########"), 346 | ("########"), 347 | ("########"), 348 | ("########"), 349 | ("########"), 350 | ("########"), 351 | ("########"), 352 | ("########") 353 | ), 354 | ( 355 | ("#### ###"), 356 | ("#### ###"), 357 | ("#### ###"), 358 | ("#### ###"), 359 | ("#### ###"), 360 | ("########"), 361 | ("#### ###"), 362 | ("########") 363 | ), 364 | ( 365 | ("### # ##"), 366 | ("### # ##"), 367 | ("########"), 368 | ("########"), 369 | ("########"), 370 | ("########"), 371 | ("########"), 372 | ("########") 373 | ), 374 | ( 375 | ("### # ##"), 376 | ("### # ##"), 377 | ("# "), 378 | ("### # ##"), 379 | ("# "), 380 | ("### # ##"), 381 | ("### # ##"), 382 | ("########") 383 | ), 384 | ( 385 | ("#### ###"), 386 | ("### #"), 387 | ("## # ###"), 388 | ("### ##"), 389 | ("#### # #"), 390 | ("## ##"), 391 | ("#### ###"), 392 | ("########") 393 | ), 394 | ( 395 | ("########"), 396 | ("## ## #"), 397 | ("## # ##"), 398 | ("#### ###"), 399 | ("### # #"), 400 | ("## ## #"), 401 | ("########"), 402 | ("########") 403 | ), 404 | ( 405 | ("### ###"), 406 | ("## # ###"), 407 | ("### ####"), 408 | ("## # ###"), 409 | ("# ### #"), 410 | ("# ### ##"), 411 | ("## # #"), 412 | ("########") 413 | ), 414 | ( 415 | ("#### ###"), 416 | ("#### ###"), 417 | ("########"), 418 | ("########"), 419 | ("########"), 420 | ("########"), 421 | ("########"), 422 | ("########") 423 | ), 424 | ( 425 | ("##### ##"), 426 | ("#### ###"), 427 | ("### ####"), 428 | ("### ####"), 429 | ("### ####"), 430 | ("#### ###"), 431 | ("##### ##"), 432 | ("########") 433 | ), 434 | ( 435 | ("### ####"), 436 | ("#### ###"), 437 | ("##### ##"), 438 | ("##### ##"), 439 | ("##### ##"), 440 | ("#### ###"), 441 | ("### ####"), 442 | ("########") 443 | ), 444 | ( 445 | ("#### ###"), 446 | ("# ## ## "), 447 | ("## # # #"), 448 | ("### ##"), 449 | ("## # # #"), 450 | ("# ## ## "), 451 | ("#### ###"), 452 | ("########") 453 | ), 454 | ( 455 | ("#### ###"), 456 | ("#### ###"), 457 | ("#### ###"), 458 | ("# "), 459 | ("#### ###"), 460 | ("#### ###"), 461 | ("#### ###"), 462 | ("########") 463 | ), 464 | ( 465 | ("########"), 466 | ("########"), 467 | ("########"), 468 | ("########"), 469 | ("#### ##"), 470 | ("#### ##"), 471 | ("##### ##"), 472 | ("#### ###") 473 | ), 474 | ( 475 | ("########"), 476 | ("########"), 477 | ("########"), 478 | ("# "), 479 | ("########"), 480 | ("########"), 481 | ("########"), 482 | ("########") 483 | ), 484 | ( 485 | ("########"), 486 | ("########"), 487 | ("########"), 488 | ("########"), 489 | ("########"), 490 | ("#### ##"), 491 | ("#### ##"), 492 | ("########") 493 | ), 494 | ( 495 | ("####### "), 496 | ("###### #"), 497 | ("##### ##"), 498 | ("#### ###"), 499 | ("### ####"), 500 | ("## #####"), 501 | ("# ######"), 502 | ("########") 503 | ), 504 | ( 505 | ("### ##"), 506 | ("## ### #"), 507 | ("## ### #"), 508 | ("## # # #"), 509 | ("## ### #"), 510 | ("## ### #"), 511 | ("### ##"), 512 | ("########") 513 | ), 514 | ( 515 | ("#### ###"), 516 | ("### ###"), 517 | ("#### ###"), 518 | ("#### ###"), 519 | ("#### ###"), 520 | ("#### ###"), 521 | ("### ##"), 522 | ("########") 523 | ), 524 | ( 525 | ("### ##"), 526 | ("## ### #"), 527 | ("###### #"), 528 | ("##### ##"), 529 | ("#### ###"), 530 | ("### ####"), 531 | ("## #"), 532 | ("########") 533 | ), 534 | ( 535 | ("### ##"), 536 | ("## ### #"), 537 | ("###### #"), 538 | ("#### ##"), 539 | ("###### #"), 540 | ("## ### #"), 541 | ("### ##"), 542 | ("########") 543 | ), 544 | ( 545 | ("#### ##"), 546 | ("### # ##"), 547 | ("## ## ##"), 548 | ("## #"), 549 | ("##### ##"), 550 | ("##### ##"), 551 | ("#### #"), 552 | ("########") 553 | ), 554 | ( 555 | ("## #"), 556 | ("## #####"), 557 | ("## #####"), 558 | ("## ##"), 559 | ("###### #"), 560 | ("## ### #"), 561 | ("### ##"), 562 | ("########") 563 | ), 564 | ( 565 | ("### ##"), 566 | ("## ### #"), 567 | ("## #####"), 568 | ("## ##"), 569 | ("## ### #"), 570 | ("## ### #"), 571 | ("### ##"), 572 | ("########") 573 | ), 574 | ( 575 | ("## #"), 576 | ("###### #"), 577 | ("##### ##"), 578 | ("#### ###"), 579 | ("### ####"), 580 | ("### ####"), 581 | ("### ####"), 582 | ("########") 583 | ), 584 | ( 585 | ("### ##"), 586 | ("## ### #"), 587 | ("## ### #"), 588 | ("### ##"), 589 | ("## ### #"), 590 | ("## ### #"), 591 | ("### ##"), 592 | ("########") 593 | ), 594 | ( 595 | ("### ##"), 596 | ("## ### #"), 597 | ("## ### #"), 598 | ("### #"), 599 | ("###### #"), 600 | ("## ### #"), 601 | ("### ##"), 602 | ("########") 603 | ), 604 | ( 605 | ("########"), 606 | ("#### ##"), 607 | ("#### ##"), 608 | ("########"), 609 | ("#### ##"), 610 | ("#### ##"), 611 | ("########"), 612 | ("########") 613 | ), 614 | ( 615 | ("########"), 616 | ("#### ##"), 617 | ("#### ##"), 618 | ("########"), 619 | ("#### ##"), 620 | ("#### ##"), 621 | ("##### ##"), 622 | ("#### ###") 623 | ), 624 | ( 625 | ("##### ##"), 626 | ("#### ###"), 627 | ("### ####"), 628 | ("## #####"), 629 | ("### ####"), 630 | ("#### ###"), 631 | ("##### ##"), 632 | ("########") 633 | ), 634 | ( 635 | ("########"), 636 | ("########"), 637 | ("# "), 638 | ("########"), 639 | ("# "), 640 | ("########"), 641 | ("########"), 642 | ("########") 643 | ), 644 | ( 645 | ("## #####"), 646 | ("### ####"), 647 | ("#### ###"), 648 | ("##### ##"), 649 | ("#### ###"), 650 | ("### ####"), 651 | ("## #####"), 652 | ("########") 653 | ), 654 | ( 655 | ("### ##"), 656 | ("## ### #"), 657 | ("###### #"), 658 | ("##### ##"), 659 | ("#### ###"), 660 | ("########"), 661 | ("#### ###"), 662 | ("########") 663 | ), 664 | ( 665 | ("### ##"), 666 | ("## ### #"), 667 | ("## # #"), 668 | ("## # # #"), 669 | ("## # #"), 670 | ("## #####"), 671 | ("### ##"), 672 | ("########") 673 | ), 674 | ( 675 | ("### ##"), 676 | ("## ### #"), 677 | ("## ### #"), 678 | ("## #"), 679 | ("## ### #"), 680 | ("## ### #"), 681 | ("## ### #"), 682 | ("########") 683 | ), 684 | ( 685 | ("## ##"), 686 | ("## ### #"), 687 | ("## ### #"), 688 | ("## ##"), 689 | ("## ### #"), 690 | ("## ### #"), 691 | ("## ##"), 692 | ("########") 693 | ), 694 | ( 695 | ("### ##"), 696 | ("## ### #"), 697 | ("## #####"), 698 | ("## #####"), 699 | ("## #####"), 700 | ("## ### #"), 701 | ("### ##"), 702 | ("########") 703 | ), 704 | ( 705 | ("## ##"), 706 | ("## ### #"), 707 | ("## ### #"), 708 | ("## ### #"), 709 | ("## ### #"), 710 | ("## ### #"), 711 | ("## ##"), 712 | ("########") 713 | ), 714 | ( 715 | ("## #"), 716 | ("## #####"), 717 | ("## #####"), 718 | ("## ##"), 719 | ("## #####"), 720 | ("## #####"), 721 | ("## #"), 722 | ("########") 723 | ), 724 | ( 725 | ("## #"), 726 | ("## #####"), 727 | ("## #####"), 728 | ("## #"), 729 | ("## #####"), 730 | ("## #####"), 731 | ("## #####"), 732 | ("########") 733 | ), 734 | ( 735 | ("### ##"), 736 | ("## ### #"), 737 | ("## #####"), 738 | ("## # #"), 739 | ("## ### #"), 740 | ("## ### #"), 741 | ("### ##"), 742 | ("########") 743 | ), 744 | ( 745 | ("## ### #"), 746 | ("## ### #"), 747 | ("## ### #"), 748 | ("## #"), 749 | ("## ### #"), 750 | ("## ### #"), 751 | ("## ### #"), 752 | ("########") 753 | ), 754 | ( 755 | ("### ##"), 756 | ("#### ###"), 757 | ("#### ###"), 758 | ("#### ###"), 759 | ("#### ###"), 760 | ("#### ###"), 761 | ("### ##"), 762 | ("########") 763 | ), 764 | ( 765 | ("#### #"), 766 | ("##### ##"), 767 | ("##### ##"), 768 | ("##### ##"), 769 | ("## ## ##"), 770 | ("## ## ##"), 771 | ("### ###"), 772 | ("########") 773 | ), 774 | ( 775 | ("## ### #"), 776 | ("## ### #"), 777 | ("## ## ##"), 778 | ("## ###"), 779 | ("## ## ##"), 780 | ("## ### #"), 781 | ("## ### #"), 782 | ("########") 783 | ), 784 | ( 785 | ("### ####"), 786 | ("### ####"), 787 | ("### ####"), 788 | ("### ####"), 789 | ("### ####"), 790 | ("### ####"), 791 | ("### #"), 792 | ("########") 793 | ), 794 | ( 795 | ("# ##### "), 796 | ("# ### "), 797 | ("# # # # "), 798 | ("# ## ## "), 799 | ("# ##### "), 800 | ("# ##### "), 801 | ("# ##### "), 802 | ("########") 803 | ), 804 | ( 805 | ("## ### #"), 806 | ("## ## #"), 807 | ("## # # #"), 808 | ("## # # #"), 809 | ("## ## #"), 810 | ("## ### #"), 811 | ("## ### #"), 812 | ("########") 813 | ), 814 | ( 815 | ("### ##"), 816 | ("## ### #"), 817 | ("## ### #"), 818 | ("## ### #"), 819 | ("## ### #"), 820 | ("## ### #"), 821 | ("### ##"), 822 | ("########") 823 | ), 824 | ( 825 | ("### ##"), 826 | ("### ## #"), 827 | ("### ## #"), 828 | ("### ##"), 829 | ("### ####"), 830 | ("### ####"), 831 | ("### ####"), 832 | ("########") 833 | ), 834 | ( 835 | ("### ##"), 836 | ("## ### #"), 837 | ("## ### #"), 838 | ("## ### #"), 839 | ("## ### #"), 840 | ("## ### #"), 841 | ("### ##"), 842 | ("##### #") 843 | ), 844 | ( 845 | ("## ##"), 846 | ("## ### #"), 847 | ("## ### #"), 848 | ("## ##"), 849 | ("## # ###"), 850 | ("## ## ##"), 851 | ("## ### #"), 852 | ("########") 853 | ), 854 | ( 855 | ("### ##"), 856 | ("## ### #"), 857 | ("## #####"), 858 | ("### ##"), 859 | ("###### #"), 860 | ("## ### #"), 861 | ("### ##"), 862 | ("########") 863 | ), 864 | ( 865 | ("## #"), 866 | ("#### ###"), 867 | ("#### ###"), 868 | ("#### ###"), 869 | ("#### ###"), 870 | ("#### ###"), 871 | ("#### ###"), 872 | ("########") 873 | ), 874 | ( 875 | ("## ### #"), 876 | ("## ### #"), 877 | ("## ### #"), 878 | ("## ### #"), 879 | ("## ### #"), 880 | ("## ### #"), 881 | ("### ##"), 882 | ("########") 883 | ), 884 | ( 885 | ("## ### #"), 886 | ("## ### #"), 887 | ("## ### #"), 888 | ("### # ##"), 889 | ("### # ##"), 890 | ("#### ###"), 891 | ("#### ###"), 892 | ("########") 893 | ), 894 | ( 895 | ("# ##### "), 896 | ("# ##### "), 897 | ("# ##### "), 898 | ("## # # #"), 899 | ("## # # #"), 900 | ("### # ##"), 901 | ("### # ##"), 902 | ("########") 903 | ), 904 | ( 905 | ("## ### #"), 906 | ("## ### #"), 907 | ("### # ##"), 908 | ("#### ###"), 909 | ("### # ##"), 910 | ("## ### #"), 911 | ("## ### #"), 912 | ("########") 913 | ), 914 | ( 915 | ("## ### #"), 916 | ("## ### #"), 917 | ("### # ##"), 918 | ("#### ###"), 919 | ("#### ###"), 920 | ("#### ###"), 921 | ("#### ###"), 922 | ("########") 923 | ), 924 | ( 925 | ("## #"), 926 | ("###### #"), 927 | ("##### ##"), 928 | ("#### ###"), 929 | ("### ####"), 930 | ("## #####"), 931 | ("## #"), 932 | ("########") 933 | ), 934 | ( 935 | ("### ##"), 936 | ("### ####"), 937 | ("### ####"), 938 | ("### ####"), 939 | ("### ####"), 940 | ("### ####"), 941 | ("### ##"), 942 | ("########") 943 | ), 944 | ( 945 | ("# ######"), 946 | ("## #####"), 947 | ("### ####"), 948 | ("#### ###"), 949 | ("##### ##"), 950 | ("###### #"), 951 | ("####### "), 952 | ("########") 953 | ), 954 | ( 955 | ("### ##"), 956 | ("##### ##"), 957 | ("##### ##"), 958 | ("##### ##"), 959 | ("##### ##"), 960 | ("##### ##"), 961 | ("### ##"), 962 | ("########") 963 | ), 964 | ( 965 | ("#### ###"), 966 | ("### # ##"), 967 | ("## ### #"), 968 | ("########"), 969 | ("########"), 970 | ("########"), 971 | ("########"), 972 | ("########") 973 | ), 974 | ( 975 | ("########"), 976 | ("########"), 977 | ("########"), 978 | ("########"), 979 | ("########"), 980 | ("########"), 981 | ("########"), 982 | ("# ") 983 | ), 984 | ( 985 | ("### ####"), 986 | ("#### ###"), 987 | ("########"), 988 | ("########"), 989 | ("########"), 990 | ("########"), 991 | ("########"), 992 | ("########") 993 | ), 994 | ( 995 | ("########"), 996 | ("### ##"), 997 | ("###### #"), 998 | ("### #"), 999 | ("## ### #"), 1000 | ("## ### #"), 1001 | ("### # "), 1002 | ("########") 1003 | ), 1004 | ( 1005 | ("### ####"), 1006 | ("### ####"), 1007 | ("### ##"), 1008 | ("### ## #"), 1009 | ("### ## #"), 1010 | ("### ## #"), 1011 | ("## # ##"), 1012 | ("########") 1013 | ), 1014 | ( 1015 | ("########"), 1016 | ("########"), 1017 | ("### ##"), 1018 | ("## #####"), 1019 | ("## #####"), 1020 | ("## #####"), 1021 | ("### ##"), 1022 | ("########") 1023 | ), 1024 | ( 1025 | ("###### #"), 1026 | ("###### #"), 1027 | ("#### #"), 1028 | ("### ## #"), 1029 | ("### ## #"), 1030 | ("### ## #"), 1031 | ("#### # "), 1032 | ("########") 1033 | ), 1034 | ( 1035 | ("########"), 1036 | ("########"), 1037 | ("### ##"), 1038 | ("## ### #"), 1039 | ("## #"), 1040 | ("## #####"), 1041 | ("### ##"), 1042 | ("########") 1043 | ), 1044 | ( 1045 | ("#### ##"), 1046 | ("### ## #"), 1047 | ("### ####"), 1048 | ("## ###"), 1049 | ("### ####"), 1050 | ("### ####"), 1051 | ("### ####"), 1052 | ("########") 1053 | ), 1054 | ( 1055 | ("########"), 1056 | ("########"), 1057 | ("### # "), 1058 | ("## ### #"), 1059 | ("## ### #"), 1060 | ("### #"), 1061 | ("###### #"), 1062 | ("### ##") 1063 | ), 1064 | ( 1065 | ("## #####"), 1066 | ("## #####"), 1067 | ("## # ##"), 1068 | ("## ## #"), 1069 | ("## ### #"), 1070 | ("## ### #"), 1071 | ("## ### #"), 1072 | ("########") 1073 | ), 1074 | ( 1075 | ("########"), 1076 | ("#### ###"), 1077 | ("########"), 1078 | ("#### ###"), 1079 | ("#### ###"), 1080 | ("#### ###"), 1081 | ("#### ###"), 1082 | ("########") 1083 | ), 1084 | ( 1085 | ("########"), 1086 | ("#### ###"), 1087 | ("########"), 1088 | ("#### ###"), 1089 | ("#### ###"), 1090 | ("#### ###"), 1091 | ("#### ###"), 1092 | ("## ####") 1093 | ), 1094 | ( 1095 | ("## #####"), 1096 | ("## #####"), 1097 | ("## ## ##"), 1098 | ("## # ###"), 1099 | ("## ####"), 1100 | ("## # ###"), 1101 | ("## ## ##"), 1102 | ("########") 1103 | ), 1104 | ( 1105 | ("### ###"), 1106 | ("#### ###"), 1107 | ("#### ###"), 1108 | ("#### ###"), 1109 | ("#### ###"), 1110 | ("#### ###"), 1111 | ("#### ###"), 1112 | ("########") 1113 | ), 1114 | ( 1115 | ("########"), 1116 | ("########"), 1117 | (" # # #"), 1118 | ("# ## ## "), 1119 | ("# ## ## "), 1120 | ("# ##### "), 1121 | ("# ##### "), 1122 | ("########") 1123 | ), 1124 | ( 1125 | ("########"), 1126 | ("########"), 1127 | ("## # ##"), 1128 | ("### ## #"), 1129 | ("### ## #"), 1130 | ("### ## #"), 1131 | ("### ## #"), 1132 | ("########") 1133 | ), 1134 | ( 1135 | ("########"), 1136 | ("########"), 1137 | ("### ##"), 1138 | ("## ### #"), 1139 | ("## ### #"), 1140 | ("## ### #"), 1141 | ("### ##"), 1142 | ("########") 1143 | ), 1144 | ( 1145 | ("########"), 1146 | ("########"), 1147 | ("## # ##"), 1148 | ("### ## #"), 1149 | ("### ## #"), 1150 | ("### ##"), 1151 | ("### ####"), 1152 | ("### ####") 1153 | ), 1154 | ( 1155 | ("########"), 1156 | ("########"), 1157 | ("### # #"), 1158 | ("## ## ##"), 1159 | ("## ## ##"), 1160 | ("### ##"), 1161 | ("##### ##"), 1162 | ("##### ##") 1163 | ), 1164 | ( 1165 | ("########"), 1166 | ("########"), 1167 | ("## # ##"), 1168 | ("## ####"), 1169 | ("## #####"), 1170 | ("## #####"), 1171 | ("## #####"), 1172 | ("########") 1173 | ), 1174 | ( 1175 | ("########"), 1176 | ("########"), 1177 | ("### ##"), 1178 | ("## #####"), 1179 | ("### ###"), 1180 | ("##### ##"), 1181 | ("## ###"), 1182 | ("########") 1183 | ), 1184 | ( 1185 | ("########"), 1186 | ("#### ###"), 1187 | ("### ##"), 1188 | ("#### ###"), 1189 | ("#### ###"), 1190 | ("#### ###"), 1191 | ("#### ###"), 1192 | ("########") 1193 | ), 1194 | ( 1195 | ("########"), 1196 | ("########"), 1197 | ("## ## ##"), 1198 | ("## ## ##"), 1199 | ("## ## ##"), 1200 | ("## ## ##"), 1201 | ("### # #"), 1202 | ("########") 1203 | ), 1204 | ( 1205 | ("########"), 1206 | ("########"), 1207 | ("## ### #"), 1208 | ("## ### #"), 1209 | ("## ### #"), 1210 | ("### # ##"), 1211 | ("#### ###"), 1212 | ("########") 1213 | ), 1214 | ( 1215 | ("########"), 1216 | ("########"), 1217 | ("# ##### "), 1218 | ("# ##### "), 1219 | ("# ## ## "), 1220 | ("# # # # "), 1221 | ("## ### #"), 1222 | ("########") 1223 | ), 1224 | ( 1225 | ("########"), 1226 | ("########"), 1227 | ("## ### #"), 1228 | ("### # ##"), 1229 | ("#### ###"), 1230 | ("### # ##"), 1231 | ("## ### #"), 1232 | ("########") 1233 | ), 1234 | ( 1235 | ("########"), 1236 | ("########"), 1237 | ("### ## #"), 1238 | ("### ## #"), 1239 | ("### ## #"), 1240 | ("#### #"), 1241 | ("###### #"), 1242 | ("### ##") 1243 | ), 1244 | ( 1245 | ("########"), 1246 | ("########"), 1247 | ("## ##"), 1248 | ("##### ##"), 1249 | ("#### ###"), 1250 | ("### ####"), 1251 | ("## ##"), 1252 | ("########") 1253 | ), 1254 | ( 1255 | ("#### ##"), 1256 | ("### ####"), 1257 | ("### ####"), 1258 | ("## #####"), 1259 | ("### ####"), 1260 | ("### ####"), 1261 | ("#### ##"), 1262 | ("########") 1263 | ), 1264 | ( 1265 | ("#### ###"), 1266 | ("#### ###"), 1267 | ("#### ###"), 1268 | ("#### ###"), 1269 | ("#### ###"), 1270 | ("#### ###"), 1271 | ("#### ###"), 1272 | ("########") 1273 | ), 1274 | ( 1275 | ("## ####"), 1276 | ("#### ###"), 1277 | ("#### ###"), 1278 | ("##### ##"), 1279 | ("#### ###"), 1280 | ("#### ###"), 1281 | ("## ####"), 1282 | ("########") 1283 | ), 1284 | ( 1285 | ("########"), 1286 | ("########"), 1287 | ("## ####"), 1288 | ("# ## ## "), 1289 | ("##### #"), 1290 | ("########"), 1291 | ("########"), 1292 | ("########") 1293 | ), 1294 | ( 1295 | ("########"), 1296 | ("########"), 1297 | ("########"), 1298 | ("########"), 1299 | ("########"), 1300 | ("########"), 1301 | ("########"), 1302 | ("########") 1303 | ) 1304 | ) 1305 | 1306 | -------------------------------------------------------------------------------- /effects.py: -------------------------------------------------------------------------------- 1 | import random 2 | import time 3 | import ascii8x8 4 | 5 | # A dictionary of hsv values for some common colors. 6 | colors = {"black":(0, 0, 0), "white":(0, 0, 1), "gray":(0, 0, 0.5), 7 | "red":(0, 1, 1), "blue":(0.66, 1, 1), "yellow":(0.16, 1, 1), 8 | "purple":(0.85, 1, 0.5), "green":(0.33, 1, 0.5), 9 | "orange":(0.083, 1, 1), "pink":(0.9, 1, 1), "lime":(0.33, 1, 1), 10 | "baby blue":(0.66, 0.5, 1), "cyan":(0.5, 1, 1), 11 | "brown":(0.07, 0.86, 0.54), "beige":(0.083, 0.32, 1), 12 | "indigo":(0.75, 1, 0.5), "dark gray":(0, 0, 0.15), 13 | "light gray":(0, 0, 0.75), "maroon":(0, 1, 0.5), 14 | "navy":(0.66, 1, 0.25)} 15 | 16 | class Effect(object): 17 | def __init__(self, wall): 18 | self.wall = wall 19 | self.wall.clear() 20 | 21 | def run(self): 22 | pass 23 | 24 | class SolidColorTest(Effect): 25 | def run(self): 26 | hue = 1 27 | saturation = 1 28 | value = 1 29 | 30 | hsv = (hue, saturation, value) 31 | for x in range(self.wall.width): 32 | for y in range(self.wall.height): 33 | self.wall.set_pixel(x, y, hsv) 34 | 35 | self.wall.draw() 36 | time.sleep(2) 37 | 38 | class HueTest(Effect): 39 | def run(self): 40 | hue = random.random() 41 | start_time = time.time() 42 | while time.time() - start_time < 5: 43 | hsv = (hue, 1, 1) 44 | for x in range(self.wall.width): 45 | for y in range(self.wall.height): 46 | self.wall.set_pixel(x, y, hsv) 47 | self.wall.draw() 48 | hue = (hue + .01) % 1 49 | time.sleep(.05) 50 | 51 | class SaturationTest(Effect): 52 | def run(self): 53 | hue = random.random() 54 | saturation = 0 55 | start_time = time.time() 56 | while time.time() - start_time < 5: 57 | hsv = (hue, saturation, 1) 58 | for x in range(self.wall.width): 59 | for y in range(self.wall.height): 60 | self.wall.set_pixel(x, y, hsv) 61 | self.wall.draw() 62 | saturation = (saturation + .05) % 1 63 | time.sleep(.05) 64 | 65 | class ValueTest(Effect): 66 | def run(self): 67 | hue = random.random() 68 | value = 0 69 | start_time = time.time() 70 | while time.time() - start_time < 5: 71 | hsv = (hue, 1, value) 72 | for x in range(self.wall.width): 73 | for y in range(self.wall.height): 74 | self.wall.set_pixel(x, y, hsv) 75 | self.wall.draw() 76 | value = (value + .05) % 1 77 | time.sleep(.05) 78 | 79 | class DictionaryTest(Effect): 80 | def run(self): 81 | for color in colors.keys(): 82 | for x in range(self.wall.width): 83 | for y in range(self.wall.height): 84 | self.wall.set_pixel(x, y, colors[color]) 85 | self.wall.draw() 86 | time.sleep(0.5) 87 | 88 | class Checkerboards(Effect): 89 | def run(self): 90 | for i in range(10): 91 | for x in range(self.wall.width): 92 | for y in range(self.wall.height): 93 | if (x + y + i) % 2 == 0: 94 | self.wall.set_pixel(x, y, colors["black"]) 95 | else: 96 | self.wall.set_pixel(x, y, colors["yellow"]) 97 | self.wall.draw() 98 | time.sleep(0.5) 99 | 100 | class Columns(Effect): 101 | def run(self): 102 | hue = random.random() 103 | start_time = time.time() 104 | while time.time() - start_time < 5: 105 | for x in range(self.wall.width): 106 | for y in range(self.wall.height): 107 | hsv = (hue, 1, 1) 108 | self.wall.set_pixel(x, y, hsv) 109 | self.wall.draw() 110 | time.sleep(.02) 111 | self.wall.clear() 112 | hue = (hue + .05) % 1 113 | 114 | class Rainbow(Effect): 115 | def run(self): 116 | hue = random.random() 117 | hue_spacing = 1.0/(self.wall.width * self.wall.height) 118 | delay = .1 119 | 120 | # Draw rainbow stripes from right to left. 121 | for i in range(self.wall.width - 1, -1, -1): 122 | for j in range(self.wall.height - 1, -1, -1): 123 | hsv = (hue, 1, 1) 124 | self.wall.set_pixel(i, j, hsv) 125 | hue += hue_spacing 126 | # on python 2.5, having a hue value of > 1 will return None 127 | # when you try to convert HSV to RGB using colorsys 128 | # 129 | # in later versions, colorsys will treat a hue value of 130 | # > 1 as *just the truncated fractional part*, e.g. 131 | # 1.29 becomes 0.29. 132 | # 133 | # neither of these particularly make sense, but let's 134 | # emulate the behaviour of python 2.6+ here for compatibility's 135 | # sake. 136 | if hue > 1: 137 | hue -= int(hue) 138 | time.sleep(delay) 139 | self.wall.draw() 140 | 141 | time.sleep(1) 142 | 143 | # Shift the wall hues for a few seconds. 144 | start_time = time.time() 145 | while time.time() - start_time < 5: 146 | for i in range(self.wall.width): 147 | for j in range(self.wall.height): 148 | hsv = self.wall.get_pixel(i, j) 149 | new_hue = (hsv[0] + hue_spacing/4) % 1 150 | new_hsv = (new_hue, hsv[1], hsv[2]) 151 | self.wall.set_pixel(i, j, new_hsv) 152 | self.wall.draw() 153 | 154 | time.sleep(1) 155 | 156 | 157 | class Twinkle(Effect): 158 | def run(self): 159 | start_time = time.time() 160 | while time.time() - start_time < 5: 161 | x = random.randint(0, self.wall.width - 1) 162 | y = random.randint(0, self.wall.height - 1) 163 | # Stick to blueish colors. 164 | hue = .65 + random.uniform(-1, 1) * .1 165 | value = random.random() 166 | hsv = (hue, 1, value) 167 | self.wall.set_pixel(x, y, hsv) 168 | self.wall.draw() 169 | time.sleep(.01) 170 | 171 | class KnightMoves(Effect): 172 | def __init__(self, wall): 173 | self.wall = wall 174 | self.wall.clear() 175 | for x in range(self.wall.width): 176 | for y in range(self.wall.height): 177 | if (x + y) % 2 == 0: 178 | self.wall.set_pixel(x, y, colors["black"]) 179 | else: 180 | self.wall.set_pixel(x, y, colors["white"]) 181 | # Pick a random starting location for the knight 182 | self.knight_x = random.randint(0, self.wall.width - 1) 183 | self.knight_y = random.randint(0, self.wall.height - 1) 184 | self.wall.set_pixel(self.knight_x, self.knight_y, colors["red"]) 185 | 186 | def run(self): 187 | if self.wall.width < 2 or self.wall.height < 2: 188 | return 189 | 190 | self.wall.draw() 191 | start_time = time.time() 192 | while time.time() - start_time < 12: 193 | self.move() 194 | self.wall.draw() 195 | time.sleep(0.75) 196 | 197 | def move(self): 198 | """ 199 | Move the knight. 200 | """ 201 | if (self.knight_x + self.knight_y) % 2 == 0: 202 | self.wall.set_pixel(self.knight_x, self.knight_y, colors["black"]) 203 | else: 204 | self.wall.set_pixel(self.knight_x, self.knight_y, colors["white"]) 205 | moves = self.getMoves() 206 | # Select a move at random from the possible moves 207 | self.knight_x, self.knight_y = moves[random.randint(0, len(moves) - 1)] 208 | self.wall.set_pixel(self.knight_x, self.knight_y, colors["red"]) 209 | 210 | def getMoves(self): 211 | """ 212 | Get all possible moves that the knight can make. 213 | """ 214 | moves = [] 215 | # Don't want knight to wrap around the board because you can't 216 | # do that in chess 217 | if (self.knight_x - 2) >= 0 and (self.knight_y - 1) >= 0: 218 | moves.append((self.knight_x - 2, self.knight_y - 1)) 219 | if (self.knight_x - 1) >= 0 and (self.knight_y - 2) >= 0: 220 | moves.append((self.knight_x - 1, self.knight_y - 2)) 221 | if (self.knight_x - 2) >= 0 and (self.knight_y + 1) < self.wall.height: 222 | moves.append((self.knight_x - 2, self.knight_y + 1)) 223 | if (self.knight_x + 1) < self.wall.width and (self.knight_y - 2) >= 0: 224 | moves.append((self.knight_x + 1, self.knight_y - 2)) 225 | if (self.knight_x - 1) >= 0 and (self.knight_y + 2) < self.wall.height: 226 | moves.append((self.knight_x - 1, self.knight_y + 2)) 227 | if (self.knight_x + 2) < self.wall.width and (self.knight_y - 1) >= 0: 228 | moves.append((self.knight_x + 2, self.knight_y - 1)) 229 | if (self.knight_x + 2) < self.wall.width and \ 230 | (self.knight_y + 1) < self.wall.height: 231 | moves.append((self.knight_x + 2, self.knight_y + 1)) 232 | if (self.knight_x + 1) < self.wall.width and \ 233 | (self.knight_y + 2) < self.wall.height: 234 | moves.append((self.knight_x + 1, self.knight_y + 2)) 235 | return moves 236 | 237 | class Matrix(Effect): 238 | class Column(object): 239 | def __init__(self, wall): 240 | self.wall = wall 241 | self.cache = [] 242 | # Tail must be at least 1 pixel long 243 | self.tail = max(1, random.randint( 244 | self.wall.height / 2, self.wall.height * 2)) 245 | # Get a position somewhere above the wall (so it can trickle down 246 | # onto the wall) 247 | self.pos = (random.randint(0, self.wall.width - 1), 248 | random.randint(-(self.wall.height * 3), 0)) 249 | self.green = .35 250 | 251 | def step(self): 252 | """ 253 | Advance the location of the head of the column and all pixels in the 254 | tail. 255 | """ 256 | self.cache.append(self.pos) 257 | self.cache = self.cache[-self.tail:] 258 | self.pos = [self.pos[0], self.pos[1] + 1] 259 | 260 | def inside_wall(self, x, y, wall): 261 | if x >= 0 and x < wall.width and y >= 0 and y < wall.height: 262 | return True 263 | return False 264 | 265 | def draw(self, wall): 266 | """ 267 | Set the pixel colors in this column for this step. 268 | 269 | Returns the number of pixels making up this column that were 270 | actually within the scope of the wall. 271 | """ 272 | draw_cnt = 0 273 | # Prepare the tail colors. The further from the head, the dimmer the 274 | # pixel. 275 | for index, pos in enumerate(self.cache): 276 | x = pos[0] 277 | y = pos[1] 278 | if self.inside_wall(x, y, wall): 279 | hsv = (self.green, 1, float(index)/self.tail) 280 | wall.set_pixel(x, y, hsv) 281 | draw_cnt += 1 282 | 283 | # Prepare the head color 284 | x = self.pos[0] 285 | y = self.pos[1] 286 | if self.inside_wall(x, y, wall): 287 | hsv = (self.green, 1, 1) 288 | wall.set_pixel(x, y, hsv) 289 | draw_cnt += 1 290 | 291 | return draw_cnt 292 | 293 | def run(self): 294 | cols = [] 295 | # Initialize 15 - 30 Matrix columns. 296 | for i in range(random.randint(15, 30)): 297 | col = self.Column(self.wall) 298 | cols.append(col) 299 | # Run the columns down the wall. 300 | self.draw(cols) 301 | 302 | def draw(self, cols): 303 | """ 304 | Draw the advancing columns until no parts of any columns are left on the 305 | wall. 306 | """ 307 | timeout = 4 308 | drawing = 0 309 | while drawing or timeout: 310 | self.wall.clear() 311 | for col in cols: 312 | col.step() 313 | drawing += col.draw(self.wall) 314 | self.wall.draw() 315 | time.sleep(.05) 316 | if not drawing: 317 | timeout -= 1 318 | drawing = 0 319 | 320 | class LetterTest(Effect): 321 | """ 322 | Cycle through the letters of the alphabet. 323 | 324 | Minimum wall size: 8 x 8. 325 | """ 326 | def run(self): 327 | if self.wall.width < 8 or self.wall.height < 8: 328 | return 329 | 330 | color = random.random() 331 | foreground = (color, 1, 1) 332 | # Make the foreground and background complementary colors. 333 | background = ((color + .5) % 1, 1, 1) 334 | 335 | # Center the letters on the wall 336 | x_offset = int((self.wall.width - 8) / 2) 337 | y_offset = int((self.wall.height - 8) / 2) 338 | 339 | # Display upper and lower case letters. The break between 90 and 97 is 340 | # for non-letter keyboard characters. 341 | for ord in range(65, 91) + range(97, 123): 342 | self.wall.clear() 343 | 344 | # Set every pixel to the background color, since ascii8x8 will only 345 | # color an 8x8 section. 346 | for x in range(self.wall.width): 347 | for y in range(self.wall.height): 348 | self.wall.set_pixel(x, y, background) 349 | 350 | # Color the letter. 351 | ascii8x8.draw_chr(chr(ord), self.wall, foreground, background, 352 | x_offset, y_offset) 353 | self.wall.draw() 354 | time.sleep(.1) 355 | 356 | class Bouncer(Effect): 357 | class Ball(object): 358 | def __init__(self, wall): 359 | self.wall = wall 360 | self.x = random.randint(0, self.wall.width - 1) 361 | self.y = random.randint(0, self.wall.height - 1) 362 | self.hue = random.random() 363 | self.dx = self.dy = 0 364 | while self.dx == 0 and self.dy == 0: 365 | self.dx = random.choice([-1, 0, 1]) 366 | self.dy = random.choice([-1, 0, 1]) 367 | self.tail = [] 368 | self.tail_len = 4 369 | 370 | def draw(self): 371 | self.wall.set_pixel(self.x, self.y, (self.hue, 1, 1)) 372 | value = 0.6 373 | val_step = float(value/(self.tail_len+1)) 374 | for x, y in self.tail: 375 | value -= val_step 376 | self.wall.set_pixel(x, y, (self.hue, 1, value)) 377 | 378 | def advance(self): 379 | self.tail = [(self.x, self.y)] + self.tail[:self.tail_len-1] 380 | self.x += self.dx 381 | if self.x < 0: 382 | self.x = 1 383 | self.dx = -self.dx 384 | elif self.x >= self.wall.width: 385 | self.x = self.wall.width - 2 386 | self.dx = -self.dx 387 | 388 | self.y += self.dy 389 | if self.y < 0: 390 | self.y = 1 391 | self.dy = -self.dy 392 | elif self.y >= self.wall.height: 393 | self.y = self.wall.height - 2 394 | self.dy = -self.dy 395 | 396 | def run(self): 397 | if self.wall.width < 2 or self.wall.height < 2: 398 | return 399 | 400 | balls = [] 401 | for i in range(3): 402 | balls.append(self.Ball(self.wall)) 403 | 404 | start_time = time.time() 405 | while time.time() - start_time < 5: 406 | self.wall.clear() 407 | for ball in balls: 408 | ball.draw() 409 | ball.advance() 410 | self.wall.draw() 411 | time.sleep(.1) 412 | 413 | class Message(Effect): 414 | message = [ 415 | ' ', 416 | ' ** * * *** * * ** * * * ** ** ** ** * * * ', 417 | ' * * * * * * * * * ** * * * * * * * * * * * ', 418 | ' ** * * *** * * * ** * * * * * * * * * * ', 419 | ' * * * * * * * * * * * * * * * * * ', 420 | ' * * * * * ** * * * ** ** ** ** *** * * ', 421 | ] 422 | 423 | def run(self): 424 | if self.wall.height < 6 or self.wall.width < 2: 425 | return 426 | 427 | col = 0 428 | start_time = time.time() 429 | while time.time() - start_time < 10: 430 | self.wall.clear() 431 | for x in range(self.wall.width): 432 | for y in range(self.wall.height): 433 | if y >= len(self.message): 434 | break 435 | dot = self.message[y][(x+col) % len(self.message[0])] 436 | if dot != ' ': 437 | self.wall.set_pixel(x, y, (.333, 1, 1)) 438 | self.wall.draw() 439 | col += 1 440 | time.sleep(0.07) 441 | 442 | Effects = [SolidColorTest, HueTest, SaturationTest, ValueTest, DictionaryTest, 443 | LetterTest, Checkerboards, Columns, Rainbow, Twinkle, KnightMoves, 444 | Matrix, Bouncer, Message] 445 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import argparse, sys 4 | 5 | from wall import Wall 6 | import effects 7 | 8 | """ 9 | """ 10 | 11 | if __name__ == "__main__": 12 | parser = argparse.ArgumentParser() 13 | parser.add_argument("-w", "--width", type=int, 14 | action="store", dest="width", 15 | default=8, help="wall width") 16 | parser.add_argument("-t", "--height", type=int, 17 | action="store", dest="height", 18 | default=8, help="wall height") 19 | parser.add_argument("-e", "--effects", 20 | nargs='+', dest="effects", 21 | help="specific effects you wish to run") 22 | args = parser.parse_args() 23 | 24 | wall = Wall(args.width, args.height) 25 | 26 | if args.effects: 27 | effects_to_run = [getattr(effects, a) for a in args.effects \ 28 | if hasattr(effects, a)] 29 | 30 | else: 31 | effects_to_run = effects.Effects 32 | 33 | for effect in effects_to_run: 34 | new_effect = effect(wall) 35 | print new_effect.__class__.__name__ 36 | new_effect.run() 37 | -------------------------------------------------------------------------------- /wall.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from Tkinter import ALL, Canvas, Frame, SUNKEN, Tk 4 | import colorsys 5 | 6 | """ 7 | A Color Wall of configurable size. Each pixel on the color wall expects a 8 | 3-element tuple representing the HSV (hue, saturation, value) for that 9 | pixel. Each element is a float between 0 and 1. 10 | 11 | For bright colors, vary the hue and set the saturation and value to 1. 12 | 13 | For more information on HSV, see: 14 | http://en.wikipedia.org/wiki/HSL_and_HSV 15 | 16 | Interface: 17 | 18 | set_pixel(): Set the HSV values for the pixel at x-offset x and y-offset y. 0,0 19 | is the upper-left corner. 20 | 21 | get_pixel(): Get the HSV values for the pixel at x-offset x and y-offset y. 22 | 23 | draw(): Re-draw every pixel on the wall based on the pixel's HSV tuple. 24 | 25 | clear(): Set every pixel on the wall to black (HSV (0, 0, 0)). This does not 26 | re-draw the pixels. 27 | """ 28 | 29 | class Wall(object): 30 | MIN_RED = MIN_GREEN = MIN_BLUE = 0x0 31 | MAX_RED = MAX_GREEN = MAX_BLUE = 0xFF 32 | 33 | PIXEL_WIDTH = 50 34 | 35 | def __init__(self, width, height): 36 | self.width = width 37 | self.height = height 38 | self._tk_init() 39 | self.pixels = [(0, 0, 0) for i in range(self.width * self.height)] 40 | 41 | def _tk_init(self): 42 | self.root = Tk() 43 | self.root.title("ColorWall %d x %d" % (self.width, self.height)) 44 | self.root.resizable(0, 0) 45 | self.frame = Frame(self.root, bd=5, relief=SUNKEN) 46 | self.frame.pack() 47 | 48 | self.canvas = Canvas(self.frame, 49 | width=self.PIXEL_WIDTH * self.width, 50 | height=self.PIXEL_WIDTH * self.height, 51 | bd=0, highlightthickness=0) 52 | self.canvas.pack() 53 | self.root.update() 54 | 55 | def set_pixel(self, x, y, hsv): 56 | self.pixels[self.width * y + x] = hsv 57 | 58 | def get_pixel(self, x, y): 59 | return self.pixels[self.width * y + x] 60 | 61 | def draw(self): 62 | self.canvas.delete(ALL) 63 | for x in range(len(self.pixels)): 64 | x_0 = (x % self.width) * self.PIXEL_WIDTH 65 | y_0 = (x / self.width) * self.PIXEL_WIDTH 66 | x_1 = x_0 + self.PIXEL_WIDTH 67 | y_1 = y_0 + self.PIXEL_WIDTH 68 | hue = "#%02x%02x%02x" % self._get_rgb(self.pixels[x]) 69 | self.canvas.create_rectangle(x_0, y_0, x_1, y_1, fill=hue) 70 | self.canvas.update() 71 | 72 | def clear(self): 73 | for i in range(self.width * self.height): 74 | self.pixels[i] = (0, 0, 0) 75 | 76 | def _hsv_to_rgb(self, hsv): 77 | rgb = colorsys.hsv_to_rgb(*hsv) 78 | red = self.MAX_RED * rgb[0] 79 | green = self.MAX_GREEN * rgb[1] 80 | blue = self.MAX_BLUE * rgb[2] 81 | return (red, green, blue) 82 | 83 | def _get_rgb(self, hsv): 84 | red, green, blue = self._hsv_to_rgb(hsv) 85 | red = int(float(red) / (self.MAX_RED - self.MIN_RED) * 0xFF) 86 | green = int(float(green) / (self.MAX_GREEN - self.MIN_GREEN) * 0xFF) 87 | blue = int(float(blue) / (self.MAX_BLUE - self.MIN_BLUE) * 0xFF) 88 | return (red, green, blue) 89 | --------------------------------------------------------------------------------