diff options
| author | Sadeep Madurange <sadeep@asciimx.com> | 2025-12-21 09:14:53 +0800 |
|---|---|---|
| committer | Sadeep Madurange <sadeep@asciimx.com> | 2025-12-26 13:32:43 +0800 |
| commit | 69a888a5b0bc4ef4bce4f86c1556a06f0f131fda (patch) | |
| tree | 3ebe8443d487f6c9ef52ca07bc7c7cd7abb252b0 | |
| parent | ff887d9189c93f585ba9969a20d61acd4cc59176 (diff) | |
| download | matrix-digital-rain-69a888a5b0bc4ef4bce4f86c1556a06f0f131fda.tar.gz | |
| -rw-r--r-- | .clang-format | 178 | ||||
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | LICENSE | 339 | ||||
| -rw-r--r-- | Makefile.am | 5 | ||||
| -rw-r--r-- | README.md | 40 | ||||
| -rw-r--r-- | README.txt | 39 | ||||
| -rw-r--r-- | configure.ac | 15 | ||||
| -rw-r--r-- | example.png | bin | 522305 -> 0 bytes | |||
| -rw-r--r-- | katakana.png | bin | 133709 -> 0 bytes | |||
| -rw-r--r-- | main.c | 377 | ||||
| -rw-r--r-- | matrix.mp4 | bin | 0 -> 696574 bytes | |||
| -rw-r--r-- | screenshot.png | bin | 0 -> 233077 bytes | |||
| -rw-r--r-- | src/main.c | 321 |
13 files changed, 418 insertions, 898 deletions
diff --git a/.clang-format b/.clang-format deleted file mode 100644 index cb2c02a..0000000 --- a/.clang-format +++ /dev/null @@ -1,178 +0,0 @@ ---- -Language: Cpp -# BasedOnStyle: LLVM -AccessModifierOffset: -2 -AlignAfterOpenBracket: Align -AlignArrayOfStructures: None -AlignConsecutiveMacros: None -AlignConsecutiveAssignments: None -AlignConsecutiveBitFields: None -AlignConsecutiveDeclarations: None -AlignEscapedNewlines: Right -AlignOperands: Align -AlignTrailingComments: true -AllowAllArgumentsOnNextLine: true -AllowAllConstructorInitializersOnNextLine: true -AllowAllParametersOfDeclarationOnNextLine: true -AllowShortEnumsOnASingleLine: true -AllowShortBlocksOnASingleLine: Never -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: All -AllowShortLambdasOnASingleLine: All -AllowShortIfStatementsOnASingleLine: Never -AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterDefinitionReturnType: None -AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: MultiLine -AttributeMacros: - - __capability -BinPackArguments: true -BinPackParameters: true -BraceWrapping: - AfterCaseLabel: false - AfterClass: false - AfterControlStatement: Never - AfterEnum: false - AfterFunction: false - AfterNamespace: false - AfterObjCDeclaration: false - AfterStruct: false - AfterUnion: false - AfterExternBlock: false - BeforeCatch: false - BeforeElse: false - BeforeLambdaBody: false - BeforeWhile: false - IndentBraces: false - SplitEmptyFunction: true - SplitEmptyRecord: true - SplitEmptyNamespace: true -BreakBeforeBinaryOperators: None -BreakBeforeConceptDeclarations: true -BreakBeforeBraces: Attach -BreakBeforeInheritanceComma: false -BreakInheritanceList: BeforeColon -BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: false -BreakConstructorInitializers: BeforeColon -BreakAfterJavaFieldAnnotations: false -BreakStringLiterals: true -ColumnLimit: 80 -CommentPragmas: '^ IWYU pragma:' -CompactNamespaces: false -ConstructorInitializerAllOnOneLineOrOnePerLine: false -ConstructorInitializerIndentWidth: 4 -ContinuationIndentWidth: 2 -Cpp11BracedListStyle: true -DeriveLineEnding: true -DerivePointerAlignment: false -DisableFormat: false -EmptyLineAfterAccessModifier: Never -EmptyLineBeforeAccessModifier: LogicalBlock -ExperimentalAutoDetectBinPacking: false -FixNamespaceComments: true -ForEachMacros: - - foreach - - Q_FOREACH - - BOOST_FOREACH -IfMacros: - - KJ_IF_MAYBE -IncludeBlocks: Preserve -IncludeCategories: - - Regex: '^"(llvm|llvm-c|clang|clang-c)/' - Priority: 2 - SortPriority: 0 - CaseSensitive: false - - Regex: '^(<|"(gtest|gmock|isl|json)/)' - Priority: 3 - SortPriority: 0 - CaseSensitive: false - - Regex: '.*' - Priority: 1 - SortPriority: 0 - CaseSensitive: false -IncludeIsMainRegex: '(Test)?$' -IncludeIsMainSourceRegex: '' -IndentAccessModifiers: false -IndentCaseLabels: false -IndentCaseBlocks: false -IndentGotoLabels: true -IndentPPDirectives: None -IndentExternBlock: AfterExternBlock -IndentRequires: false -IndentWidth: 2 -IndentWrappedFunctionNames: false -InsertTrailingCommas: None -JavaScriptQuotes: Leave -JavaScriptWrapImports: true -KeepEmptyLinesAtTheStartOfBlocks: true -LambdaBodyIndentation: Signature -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -ObjCBinPackProtocolList: Auto -ObjCBlockIndentWidth: 2 -ObjCBreakBeforeNestedBlockParam: true -ObjCSpaceAfterProperty: false -ObjCSpaceBeforeProtocolList: true -PenaltyBreakAssignment: 2 -PenaltyBreakBeforeFirstCallParameter: 19 -PenaltyBreakComment: 300 -PenaltyBreakFirstLessLess: 120 -PenaltyBreakString: 1000 -PenaltyBreakTemplateDeclaration: 10 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 60 -PenaltyIndentedWhitespace: 0 -PointerAlignment: Right -PPIndentWidth: -1 -ReferenceAlignment: Pointer -ReflowComments: true -ShortNamespaceLines: 1 -SortIncludes: CaseSensitive -SortJavaStaticImport: Before -SortUsingDeclarations: true -SpaceAfterCStyleCast: false -SpaceAfterLogicalNot: false -SpaceAfterTemplateKeyword: true -SpaceBeforeAssignmentOperators: true -SpaceBeforeCaseColon: false -SpaceBeforeCpp11BracedList: false -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true -SpaceBeforeParens: ControlStatements -SpaceAroundPointerQualifiers: Default -SpaceBeforeRangeBasedForLoopColon: true -SpaceInEmptyBlock: false -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 1 -SpacesInAngles: Never -SpacesInConditionalStatement: false -SpacesInContainerLiterals: true -SpacesInCStyleCastParentheses: false -SpacesInLineCommentPrefix: - Minimum: 1 - Maximum: -1 -SpacesInParentheses: false -SpacesInSquareBrackets: false -SpaceBeforeSquareBrackets: false -BitFieldColonSpacing: Both -Standard: Latest -StatementAttributeLikeMacros: - - Q_EMIT -StatementMacros: - - Q_UNUSED - - QT_REQUIRE_VERSION -TabWidth: 2 -UseCRLF: false -UseTab: ForIndentation -WhitespaceSensitiveMacros: - - STRINGIZE - - PP_STRINGIZE - - BOOST_PP_STRINGIZE - - NS_SWIFT_NAME - - CF_SWIFT_NAME -... - @@ -9,3 +9,5 @@ build/* autom4te.cache/* **/*a.out +**/*.swp +**/*.core diff --git a/LICENSE b/LICENSE deleted file mode 100644 index d159169..0000000 --- a/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 102e0fc..0000000 --- a/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ -ACLOCAL_AMFLAGS = -I m4 - -bin_PROGRAMS = amx - -amx_SOURCES = src/main.c diff --git a/README.md b/README.md deleted file mode 100644 index 89cdaea..0000000 --- a/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Matrix Digital Rain - - - -> Do not try and bend the spoon, that's impossble. Instead, only try to realize the truth. There is no spoon. - - -- _Spoon Boy_ - -## Overview - -Pure C implementation of the famous [digital rain](https://en.wikipedia.org/wiki/Matrix_digital_rain) effect from _The Matrix_ series for Linux inspired by [fakesteak](https://github.com/domsson/fakesteak). While trying to keep the simplicity and lightweightness of fakesteak as much as possible, I have added the following characteristics. - - - Simulation pattern is closer to the one seen in the background while Neo and Cypher were talking in the first Matrix movie. - - Ghosting effect of monochrome displays. - - Truecolor support and simple colour customisation options to match the theme of the setup for ricing. - - Unicode support. - -## Requirements and Dependencies - - - Terminal emulator with support for 24-bit RGB colours and unicode characters. - -## Customisation - - - Character set: set `UNICODE_MIN` and `UNICODE_MAX` for the [unicode block](https://en.wikipedia.org/wiki/List_of_Unicode_characters) you like to use (e.g. 0x30A1 and 0x30F6 for Katakana): - - - - - Colours: set the RGB values of `COLOR_BG_*`, `COLOR_HD_*` and `COLOR_TL_*` for background, head and the tail characters respectively. - - Rain attributes: set `RAIN_RATE` and `RAIN_DENSITY` to change the speed and the density of the rain. - -## Building and Running - -All the code is in a single file (src/main.c) and has no external dependencies. You can compile it any way you like. If you have autotools installed you can build and run using the following commands. -``` -autoreconf -i -cd build/ -../configure -make -./amx -``` diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..46ce196 --- /dev/null +++ b/README.txt @@ -0,0 +1,39 @@ +MATRIX DIGITAL RAIN + +Pure C implementation of the famous digital rain effect from The Matrix, +inspired [fakesteak](https://github.com/domsson/fakesteak). While trying to +keep the simplicity and lightweightness of fakesteak as much as possible, I +have added the following characteristics. + + - Simulation pattern is closer to the one seen during Neo and Cypher's + conversation in the first Matrix movie. + - Ghosting effect of monochrome CRT displays. + - Truecolor support. + - Unicode support. + +REQUIREMENTS + + - Terminal emulator with support for 24-bit RGB colours and unicode + characters. + +CUSTOMISATION + + - Character set: add [unicode + blocks](https://en.wikipedia.org/wiki/List_of_Unicode_characters) (Katakana: font ja-sazanami-ttf). + you'd like to use to glyphs. ASCII and Katakana are included by default. + - Colours: set the RGB values of `COLOR_BG_*`, `COLOR_HD_*` and `COLOR_TL_*` + for background, head and the tail characters respectively. + - Rain attributes: set `RHO` to change the density of the rain. + +BUILDING AND RUNNING + +With Katakana: + + $ cc -O3 main.c -o matrix + $ ./matrix + +Without Katakana: + + $ cc -O3 -DNOKANA main.c -o matrix + $ ./matrix + diff --git a/configure.ac b/configure.ac deleted file mode 100644 index e86bb66..0000000 --- a/configure.ac +++ /dev/null @@ -1,15 +0,0 @@ -AC_PREREQ([2.71]) -AC_INIT([matrix],[0.0.1],[sadeep@asciimx.com]) -AC_CONFIG_AUX_DIR([build]) -AC_CONFIG_MACRO_DIRS([m4]) -AC_CONFIG_SRCDIR([src/main.c]) -AC_CONFIG_HEADERS([config.h]) -AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) -AM_PROG_AR - -LT_INIT - -AC_PROG_CC - -AC_CONFIG_FILES([Makefile]) -AC_OUTPUT diff --git a/example.png b/example.png Binary files differdeleted file mode 100644 index 1dedacf..0000000 --- a/example.png +++ /dev/null diff --git a/katakana.png b/katakana.png Binary files differdeleted file mode 100644 index b9df873..0000000 --- a/katakana.png +++ /dev/null @@ -0,0 +1,377 @@ +#include <locale.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <termios.h> +#include <time.h> +#include <unistd.h> +#include <uchar.h> +#include <wchar.h> +#include <sys/ioctl.h> + +#define RHO 0.7 /* Rain density: (0, 1) */ + +#define RGB_BG_RED 34 /* Background color */ +#define RGB_BG_GRN 34 +#define RGB_BG_BLU 34 + +#define RGB_HD_RED 255 /* Color of the first raindrop */ +#define RGB_HD_GRN 255 +#define RGB_HD_BLU 255 + +#define RGB_TL_RED 40 /* Color of the rain */ +#define RGB_TL_GRN 254 +#define RGB_TL_BLU 20 + +#define DECAY_MPLIER 2 /* Phosphor decay multiplier */ +#define DELAY_US 60000 /* Delay between frames: increase to slow the rain */ + +#define ANSI_CRSR_HIDE "\e[?25l" +#define ANSI_CRSR_SHOW "\e[?25h" +#define ANSI_CRSR_RESET "\x1b[H" +#define ANSI_FONT_BOLD "\x1b[1m" +#define ANSI_FONT_RESET "\x1b[0m" +#define ANSI_SCRN_CLEAR "\x1b[2J" + +#define UNICODE(min, max) (((uint64_t)max << 32) | min) + +static uint64_t glyphs[] = { + UNICODE(0x0021, 0x007E), /* ASCII */ +#ifndef NOKANA + UNICODE(0xFF65, 0xFF9F), /* Half-width Katakana */ +#endif +}; + +static uint8_t glyphlen = (sizeof glyphs) / (sizeof glyphs[0]); + +enum { + R, /* Red */ + G, /* Green */ + B, /* Blue */ + PD /* Phosphor decay multiplier */ +}; + +typedef union color_tag { + uint32_t value; + unsigned char color[4]; +} color; + +typedef struct matrix_tag { + size_t rowlen; /* Row count: terminal screen height */ + size_t collen; /* Column count: terminal screen width */ + size_t *col; /* Column indices in random order (shuffle()) */ + size_t *row; /* Current row index of columns: 1-1 map with col */ + color *rgb; /* RGB color of the cell */ + char32_t *code; /* Code point */ +} matrix; + +static inline size_t index(const matrix *mat, + size_t row, size_t col) +{ + return mat->collen * row + col; +} + +static inline void print(const matrix *mat, + size_t row, size_t col) +{ + size_t idx; + + idx = index(mat, row, col); + wprintf(L"\x1b[%d;%dH\x1b[38;2;%d;%d;%dm%lc", row, col, + mat->rgb[idx].color[R], mat->rgb[idx].color[G], + mat->rgb[idx].color[B], mat->code[idx]); +} + +static inline void insert_code(matrix *mat, + size_t row, size_t col) +{ + uint64_t blk; + uint32_t min, max; + + blk = glyphs[(rand() % glyphlen)]; + min = (uint32_t)blk; + max = (uint32_t)(blk >> 32); + mat->code[index(mat, row, col)] = rand() % (max - min) + min; +} + +static inline void delete_code(matrix *mat, + size_t row, size_t col) +{ + mat->code[index(mat, row, col)] = ' '; + print(mat, row, col); +} + +static inline void recolor_head(matrix *mat, + size_t row, size_t col) +{ + unsigned char *sc, *tc; + + sc = mat->rgb[index(mat, 0, col)].color; + tc = mat->rgb[index(mat, row, col)].color; + tc[R] = sc[R]; + tc[G] = sc[G]; + tc[B] = sc[B]; + print(mat, row, col); +} + +static inline void draw_tail(matrix *mat, + size_t row, size_t col) +{ + unsigned char *color; + + color = mat->rgb[index(mat, row, col)].color; + color[R] = RGB_TL_RED; + color[G] = RGB_TL_GRN; + color[B] = RGB_TL_BLU; + print(mat, row, col); +} + +static inline void draw_head(matrix *mat, + size_t row, size_t col) +{ + unsigned char *color; + + color = mat->rgb[index(mat, row, col)].color; + color[R] = RGB_HD_RED; + color[G] = RGB_HD_GRN; + color[B] = RGB_HD_BLU; + + insert_code(mat, row, col); + print(mat, row, col); +} + +static inline void blend(matrix *mat, + size_t row, size_t col) +{ + unsigned char *color; + + color = mat->rgb[index(mat, row, col)].color; + color[R] = color[R] - (color[R] - RGB_BG_RED) / DECAY_MPLIER; + color[G] = color[G] - (color[G] - RGB_BG_GRN) / DECAY_MPLIER; + color[B] = color[B] - (color[B] - RGB_BG_BLU) / DECAY_MPLIER; +} + +static inline void swap_col(matrix *mat, size_t i, size_t max) +{ + size_t j; + + mat->row[i] = 0; + mat->rgb[i].color[PD] = 0; + + j = rand() % (mat->collen - max) + max; + mat->col[i] = mat->col[i] ^ mat->col[j]; + mat->col[j] = mat->col[i] ^ mat->col[j]; + mat->col[i] = mat->col[i] ^ mat->col[j]; +} + +static inline uint8_t is_tail(matrix *mat, + size_t row, size_t col) +{ + unsigned char *color; + + color = mat->rgb[index(mat, row, col)].color; + return color[R] == RGB_TL_RED + && color[G] == RGB_TL_GRN + && color[B] == RGB_TL_BLU; +} + +static inline void glitch(matrix *mat) +{ + size_t i, j; + + i = rand() % (mat->rowlen - 1); + j = rand() % mat->collen; + if (mat->code[index(mat, i, j)] != ' ' + && is_tail(mat, i, j)) { + insert_code(mat, i, j); + print(mat, i, j); + } +} + +static inline void shuffle(size_t *a, size_t n) +{ + size_t i, j; + + for (i = n - 1; i > 0; i--) { + j = rand() % (i + 1); + a[j] = a[i] ^ a[j]; + a[i] = a[i] ^ a[j]; + a[j] = a[i] ^ a[j]; + } +} + +static inline int init_matrix(matrix *mat, + const struct winsize *ws) +{ + size_t i; + + mat->collen = ws->ws_col; + mat->rowlen = ws->ws_row + 1; + + mat->code = realloc(mat->code, + sizeof mat->code[0] * mat->rowlen * mat->collen); + if (!mat->code) + return 0; + + mat->rgb = realloc(mat->rgb, + sizeof mat->rgb[0] * mat->rowlen * mat->collen); + if (!mat->rgb) + return 0; + + mat->col = realloc(mat->col, + sizeof mat->col[0] * mat->collen); + if (!mat->col) + return 0; + + mat->row = realloc(mat->row, + sizeof mat->row[0] * mat->collen); + if (!mat->row) + return 0; + + for (i = 0; i < mat->collen; i++) { + mat->row[i] = 0; + mat->col[i] = i; + } + + shuffle(mat->col, mat->collen); + return 1; +} + +static inline void destroy_matrix(matrix *mat) +{ + free(mat->code); + free(mat->col); + free(mat->row); + free(mat->rgb); +} + +static inline int init_term(const struct winsize *ws) +{ + struct termios ta; + + if (tcgetattr(STDIN_FILENO, &ta) == 0) { + ta.c_lflag &= ~ECHO; + if (tcsetattr(STDIN_FILENO, TCSANOW, &ta) == 0) { + wprintf(L"\x1b[48;2;%d;%d;%dm", + RGB_BG_RED, RGB_BG_GRN, RGB_BG_BLU); + wprintf(L"%s", ANSI_FONT_BOLD); + wprintf(L"%s", ANSI_CRSR_HIDE); + wprintf(L"%s", ANSI_CRSR_RESET); + wprintf(L"%s", ANSI_SCRN_CLEAR); + setvbuf(stdout, 0, _IOFBF, 0); + ioctl(STDOUT_FILENO, TIOCGWINSZ, ws); + return 1; + } + } + return 0; +} + +static inline void reset_term() +{ + struct termios ta; + + wprintf(L"%s", ANSI_FONT_RESET); + wprintf(L"%s", ANSI_CRSR_SHOW); + wprintf(L"%s", ANSI_SCRN_CLEAR); + wprintf(L"%s", ANSI_CRSR_RESET); + + if (tcgetattr(STDIN_FILENO, &ta) == 0) { + ta.c_lflag |= ECHO; + if (tcsetattr(STDIN_FILENO, TCSANOW, &ta) != 0) + perror("reset_term()"); + } + setvbuf(stdout, 0, _IOLBF, 0); +} + +static volatile int run; + +static void handle_signal(int sa) +{ + switch (sa) { + case SIGINT: + case SIGQUIT: + case SIGTERM: + run = 0; + break; + } +} + +int main(int argc, char *argv[]) +{ + matrix mat; + struct winsize ws; + struct sigaction sa; + size_t i, j, n, nmax; + + setlocale(LC_CTYPE, ""); + + sa.sa_handler = handle_signal; + sigaction(SIGINT, &sa, 0); + sigaction(SIGQUIT, &sa, 0); + sigaction(SIGTERM, &sa, 0); + + srand(time(0)); + + if (!init_term(&ws)) + return 1; + + mat = (matrix){0}; + if (!init_matrix(&mat, &ws)) { + reset_term(); + return 1; + } + + run = 1; + n = 1; /* Used to ramp up the tracks from 1 to nmax to stagger the tracks. */ + nmax = mat.collen * RHO; /* Number of rain tracks. */ + + while (run) { + for (i = 0; run && i < n; i++) { + if (mat.row[i] == mat.rowlen) { + recolor_head(&mat, mat.row[i] - 1, mat.col[i]); + mat.row[i] = 0; + } + + if (mat.rgb[i].color[PD] == 0) { + if (mat.row[i] > 0) + draw_tail(&mat, mat.row[i] - 1, mat.col[i]); + draw_head(&mat, mat.row[i], mat.col[i]); + if (mat.row[i] == mat.rowlen - 1) + mat.rgb[i].color[PD] = 1; + mat.row[i]++; + } else if (mat.rgb[i].color[PD] > 0 && + mat.rgb[i].color[PD] <= DECAY_MPLIER) { + blend(&mat, mat.row[i], mat.col[i]); + print(&mat, mat.row[i], mat.col[i]); + if (mat.row[i] == mat.rowlen - 1) + mat.rgb[i].color[PD]++; + mat.row[i]++; + } else { + delete_code(&mat, mat.row[i], mat.col[i]); + if (mat.row[i] == mat.rowlen - 1) + /* Track complete, start a new one. */ + swap_col(&mat, i, nmax); + else + mat.row[i]++; + } + glitch(&mat); + } + + if (n < nmax && + /* Track ramp up: add a new one when the first track + * exceeds a random distance beyond 25% of the screen + * length. Do that until we reach the target density. */ + mat.row[n - 1] >= rand() % (int)(mat.rowlen * 0.25)) { + mat.row[n++] = 0; + } + + fflush(stdout); + usleep(DELAY_US); + } + + reset_term(); + destroy_matrix(&mat); + return 0; +} + diff --git a/matrix.mp4 b/matrix.mp4 Binary files differnew file mode 100644 index 0000000..7edf5d6 --- /dev/null +++ b/matrix.mp4 diff --git a/screenshot.png b/screenshot.png Binary files differnew file mode 100644 index 0000000..1f68ca4 --- /dev/null +++ b/screenshot.png diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 44a0955..0000000 --- a/src/main.c +++ /dev/null @@ -1,321 +0,0 @@ -#define _XOPEN_SOURCE 700 - -#include <locale.h> -#include <signal.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/ioctl.h> -#include <termios.h> -#include <time.h> -#include <unistd.h> -#include <wchar.h> - -#define UNICODE_MIN 0x0021 -#define UNICODE_MAX 0x007E - -#define RAIN_DENSITY 0.6 - -#define COLOR_BG_RED 0 -#define COLOR_BG_GRN 0 -#define COLOR_BG_BLU 0 -#define COLOR_HD_RED 255 -#define COLOR_HD_GRN 255 -#define COLOR_HD_BLU 255 -#define COLOR_TL_RED 40 -#define COLOR_TL_GRN 254 -#define COLOR_TL_BLU 20 - -#define ANSI_CUR_HIDE "\e[?25l" -#define ANSI_CUR_SHOW "\e[?25h" -#define ANSI_CUR_RESET "\x1b[H" -#define ANSI_FONT_BOLD "\x1b[1m" -#define ANSI_FONT_RESET "\x1b[0m" -#define ANSI_SCRN_CLEAR "\x1b[2J" - -enum { red, green, blue }; - -typedef union color_tag { - uint32_t rgb; - unsigned char color[4]; -} color; - -typedef struct matrix_tag { - size_t rows; - size_t cols; - size_t *col; - size_t *row; - char *shade; - wchar_t *code; - color *rgb; -} matrix; - -static size_t mat_idx(const matrix *mat, size_t row, size_t col) { - return mat->cols * row + col; -} - -static void mat_put_code(matrix *mat, size_t row, size_t col) { - mat->code[mat_idx(mat, row, col)] = - rand() % (UNICODE_MAX - UNICODE_MIN) + UNICODE_MIN; -} - -static void shuffle(size_t *a, size_t n) { - size_t i, j; - - for (i = n - 1; i > 0; i--) { - j = rand() % (i + 1); - a[j] = a[i] ^ a[j]; - a[i] = a[i] ^ a[j]; - a[j] = a[i] ^ a[j]; - } -} - -static int mat_init(matrix *mat, const struct winsize *ws) { - size_t i; - - mat->cols = ws->ws_col; - mat->rows = ws->ws_row + 1; - - mat->code = realloc(mat->code, sizeof mat->code[0] * mat->rows * mat->cols); - if (!mat->code) - return 0; - - mat->rgb = realloc(mat->rgb, sizeof mat->rgb[0] * mat->rows * mat->cols); - if (!mat->rgb) - return 0; - - mat->shade = realloc(mat->shade, sizeof mat->shade[0] * mat->cols); - if (!mat->shade) - return 0; - - mat->col = realloc(mat->col, sizeof mat->col[0] * mat->cols); - if (!mat->col) - return 0; - - mat->row = realloc(mat->row, sizeof mat->row[0] * mat->cols); - if (!mat->row) - return 0; - - for (i = 0; i < mat->cols; i++) { - mat->row[i] = 0; - mat->col[i] = i; - mat->shade[i] = 0; - } - - shuffle(mat->col, mat->cols); - return 1; -} - -static void mat_reset_head(matrix *mat, size_t row, size_t col) { - unsigned char *sc, *tc; - - sc = mat->rgb[mat_idx(mat, 0, col)].color; - tc = mat->rgb[mat_idx(mat, row, col)].color; - - tc[red] = sc[red]; - tc[green] = sc[green]; - tc[blue] = sc[blue]; -} - -static void mat_set_tail(matrix *mat, size_t row, size_t col) { - unsigned char *color; - - color = mat->rgb[mat_idx(mat, row, col)].color; - - color[red] = COLOR_TL_RED; - color[green] = COLOR_TL_GRN; - color[blue] = COLOR_TL_BLU; -} - -static void mat_set_head(matrix *mat, size_t row, size_t col) { - unsigned char *color; - - color = mat->rgb[mat_idx(mat, row, col)].color; - color[red] = COLOR_HD_RED; - color[green] = COLOR_HD_GRN; - - color[blue] = COLOR_HD_BLU; -} - -static void mat_shade(matrix *mat, size_t row, size_t col) { - unsigned char *color; - - color = mat->rgb[mat_idx(mat, row, col)].color; - - color[red] = color[red] - (color[red] - COLOR_BG_RED) / 2; - color[green] = color[green] - (color[green] - COLOR_BG_GRN) / 2; - color[blue] = color[blue] - (color[blue] - COLOR_BG_BLU) / 2; -} - -static void mat_free(matrix *mat) { - free(mat->code); - free(mat->col); - free(mat->row); - free(mat->rgb); - free(mat->shade); -} - -static int term_init() { - struct termios ta; - - if (tcgetattr(STDIN_FILENO, &ta) == 0) { - ta.c_lflag &= ~ECHO; - - if (tcsetattr(STDIN_FILENO, TCSANOW, &ta) == 0) { - wprintf(L"\x1b[48;2;%d;%d;%dm", COLOR_BG_RED, COLOR_BG_GRN, COLOR_BG_BLU); - - wprintf(L"%s", ANSI_FONT_BOLD); - wprintf(L"%s", ANSI_CUR_HIDE); - wprintf(L"%s", ANSI_CUR_RESET); - wprintf(L"%s", ANSI_SCRN_CLEAR); - - setvbuf(stdout, 0, _IOFBF, 0); - return 1; - } - } - return 0; -} - -static void term_reset() { - struct termios ta; - - wprintf(L"%s", ANSI_FONT_RESET); - wprintf(L"%s", ANSI_CUR_SHOW); - wprintf(L"%s", ANSI_SCRN_CLEAR); - wprintf(L"%s", ANSI_CUR_RESET); - - if (tcgetattr(STDIN_FILENO, &ta) == 0) { - ta.c_lflag |= ECHO; - if (tcsetattr(STDIN_FILENO, TCSANOW, &ta) != 0) - perror("term_reset()"); - } - - setvbuf(stdout, 0, _IOLBF, 0); -} - -static void term_size(const struct winsize *ws) { - ioctl(STDOUT_FILENO, TIOCGWINSZ, ws); -} - -static void term_print(const matrix *mat, size_t row, size_t col) { - size_t idx; - - idx = mat_idx(mat, row, col); - - wprintf(L"\x1b[%d;%dH\x1b[38;2;%d;%d;%dm%lc", row, col, - mat->rgb[idx].color[red], mat->rgb[idx].color[green], - mat->rgb[idx].color[blue], mat->code[idx]); -} - -static volatile int run; - -static void handle_signal(int sa) { - switch (sa) { - case SIGINT: - case SIGQUIT: - case SIGTERM: - run = 0; - break; - } -} - -int main(int argc, char *argv[]) { - matrix mat; - - struct winsize ws; - struct sigaction sa; - size_t i, j, len, maxlen; - - setlocale(LC_CTYPE, ""); - - sa.sa_handler = handle_signal; - sigaction(SIGINT, &sa, 0); - sigaction(SIGQUIT, &sa, 0); - sigaction(SIGTERM, &sa, 0); - - srand(time(0)); - - if (!term_init()) - return 1; - - term_size(&ws); - - mat = (matrix){0}; - if (!mat_init(&mat, &ws)) { - term_reset(); - return 1; - } - - run = 1, len = 1; - maxlen = mat.cols * RAIN_DENSITY; - - while (run) { - for (i = 0; run && i < len; i++) { - if (mat.row[i] == mat.rows) { - mat_reset_head(&mat, mat.row[i] - 1, mat.col[i]); - term_print(&mat, mat.rows - 1, mat.col[i]); - mat.row[i] = 0; - } - - if (mat.shade[i] == 0) { - if (mat.row[i] > 0) { - mat_set_tail(&mat, mat.row[i] - 1, mat.col[i]); - term_print(&mat, mat.row[i] - 1, mat.col[i]); - } - - mat_set_head(&mat, mat.row[i], mat.col[i]); - mat_put_code(&mat, mat.row[i], mat.col[i]); - term_print(&mat, mat.row[i], mat.col[i]); - - if (mat.row[i] > 0 && rand() % 6 == 0) { - j = rand() % mat.row[i]; - if (mat.code[mat_idx(&mat, j, mat.col[i])] != ' ') { - mat_put_code(&mat, j, mat.col[i]); - term_print(&mat, j, mat.col[i]); - } - } - - if (mat.row[i] == mat.rows - 1) - mat.shade[i] = 1; - - mat.row[i]++; - } else if (mat.shade[i] == 1 || mat.shade[i] == 2) { - mat_shade(&mat, mat.row[i], mat.col[i]); - term_print(&mat, mat.row[i], mat.col[i]); - - if (mat.row[i] == mat.rows - 1) - mat.shade[i]++; - - mat.row[i]++; - } else { - mat.code[mat_idx(&mat, mat.row[i], mat.col[i])] = ' '; - term_print(&mat, mat.row[i], mat.col[i]); - - if (mat.row[i] == mat.rows - 1) { - mat.row[i] = 0; - mat.shade[i] = 0; - - j = rand() % (mat.cols - maxlen) + maxlen; - mat.col[i] = mat.col[i] ^ mat.col[j]; - mat.col[j] = mat.col[i] ^ mat.col[j]; - mat.col[i] = mat.col[i] ^ mat.col[j]; - } else - mat.row[i]++; - } - } - - if (len < maxlen && - mat.row[len - 1] >= rand() % (int)(mat.rows * 0.25)) { - mat.row[len] = 0; - mat.shade[len++] = 0; - } - - fflush(stdout); - usleep(50000); - } - - term_reset(); - mat_free(&mat); - - return 0; -} |
