diff options
Diffstat (limited to '_log/_site/matrix-digital-rain.html')
| -rw-r--r-- | _log/_site/matrix-digital-rain.html | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/_log/_site/matrix-digital-rain.html b/_log/_site/matrix-digital-rain.html new file mode 100644 index 0000000..85bac5d --- /dev/null +++ b/_log/_site/matrix-digital-rain.html @@ -0,0 +1,103 @@ +<p>The Matrix digital rain implemented in raw C using ANSI escape sequences with +zero dependencies—not even ncurses.</p> + +<video style="max-width:100%;" controls="" poster="poster.png"> + <source src="matrix.mp4" type="video/mp4" /> +</video> + +<p>This project began over three years ago as a fork of Domsson’s unique rendition +of the Matrix rain: <a href="https://github.com/domsson/fakesteak" class="external" target="_blank" rel="noopener noreferrer">Fakesteak</a>. I +aimed to modify the algorithm to produce a rain that resembled the original +with high visual fidelity.</p> + +<h2 id="unicode-support">Unicode support</h2> + +<p>Unicode support in the 2022 version lacked flexibility. The charset used in the +rain had to be a single contiguous block defined by <code class="language-plaintext highlighter-rouge">UNICODE_MIN</code> and +<code class="language-plaintext highlighter-rouge">UNICODE_MAX</code> settings:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#define UNICODE_MIN 0x0021 +#define UNICODE_MAX 0x007E + +static inline void insert_code(matrix *mat, + size_t row, size_t col) +{ + mat->code[index(mat, row, col)] = rand() + % (UNICODE_MAX - UNICODE_MIN) + + UNICODE_MIN; +} +</code></pre></div></div> + +<p>There was no way, for instance, to use both ASCII and Katakana at the same +time. The user had to pick one. In the new version, the user can use any number +of Unicode blocks using <code class="language-plaintext highlighter-rouge">glyphs</code> array. In fact, the default rain now includes +both ASCII and half-width Katakana characters:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#define UNICODE(min, max) (((uint64_t)max << 32) | min) + +static uint64_t glyphs[] = { + UNICODE(0x0021, 0x007E), /* ASCII */ + UNICODE(0xFF65, 0xFF9F), /* Half-width Katakana */ +}; + +static uint8_t glyphlen = (sizeof glyphs) / (sizeof glyphs[0]); + +static inline void insert_code(matrix *mat, + size_t row, size_t col) +{ + uint64_t block; + uint32_t unicode_min, unicode_max; + + block = glyphs[(rand() % glyphlen)]; + unicode_min = (uint32_t)block; + unicode_max = (uint32_t)(block >> 32); + + mat->code[index(mat, row, col)] = rand() + % (unicode_max - unicode_min) + + unicode_min; +} +</code></pre></div></div> + +<p>Entries in the <code class="language-plaintext highlighter-rouge">glyphs</code> array are Unicode blocks bit-packed in an 8-byte +container: the four low bytes forms the first codepoint and the four high bytes +the last.</p> + +<h2 id="phosphor-decay">Phosphor decay</h2> + +<p>The dim afterglow of monochrome CRT displays is achieved by carefully scaling +the RGB channels individually and mixing them:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#define DECAY_MPLIER 2 + +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; +} +</code></pre></div></div> + +<p>The blending function emulates the phosphor decay by gradually transitioning +each raindrop’s color towards the background color. The multiplier is the +number of passes over the rain track needed before the afterglow disappears.</p> + +<p>Nonetheless, the rain resembles the original with high visual fidelity. It’s +highly customizable and gentle on the CPU. On my 14” ThinkPad T490, which has a +resolution of 1920x1080 and 4GHz CPU, it uses 2-3% of the CPU with occasional +jumps of up to about 8%. Not too bad for a weekend project. The program has +been tested with xterm and urxvt terminal emulators on OpenBSD and Arch Linux +systems. Someone has managed to get it moving on a Raspberry Pi as well.</p> + +<p>Lastly, to compile and run:</p> + +<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cc -O3 main.c -o matrix +$ ./matrix +</code></pre></div></div> + +<p>“All I see is blonde, brunette, red head.”</p> + +<p>Files: <a href="source.tar.gz">source.tar.gz</a></p> |
