TTY Quake uses AALib, which is from 1997. There's a a demo called "bb" to show off its features, as well as Text::AAlib perl bindings.

I have no idea how many Terminals support full RGB color, but it seems more and more do these days. I was able to double the vertical resolution by printing a Unicode Upper Half Block character and setting both it's foreground and background color.

The escape codes are quite bulky, though. To increase FPS, i remember the last colors used and only send color changes when needed. Nevertheless, screens with lots of color changes result in a much lower FPS that ones with a uniform background and only a few, big colored areas. To make a colored "doublepixel", this is essentially how it looks:

my $halfblock = chr(9600); utf8::encode($halfblock); # Needs to be UTF8-encoded ... print "\e[38;2;255;255;255m"; # White foreground print "\e[48;2;0;0;0m"; # Black background print $halfblock; ...

In reality, i internally hold an array of pixels (basically, my graphics memory), then render the whole screen into a big string, THEN output the string all at once. This avoids flickering the cursor all over the screen and increases the framerate as well.

sub render($self) { my $lastfgcolor = ''; my $lastbgcolor = ''; my $out = '' . $self->{home}; my ($r, $g, $b); # Color vars for(my $y = 0; $y < $self->{rows}; $y+=2) { for(my $x = 0; $x < $self->{cols}; $x++) { # Foreground color ($r,$g,$b) = @{$self->{img}->[$x + ($y * $self->{cols})]}; my $newfgcolor = "\e[38;2;" . join(';', $r, $g, $b) . "m"; if($newfgcolor ne $lastfgcolor) { $lastfgcolor = $newfgcolor; $out .= $newfgcolor; } # Background color my $lowy = $y + 1; if($lowy == $self->{rows}) { # End of image. need a black half-line ($r, $g, $b) = (0, 0, 0); } else { ($r,$g,$b) = @{$self->{img}->[$x + ($lowy * $self->{co +ls})]}; } my $newbgcolor = "\e[48;2;" . join(';', $r, $g, $b) . "m"; if($newbgcolor ne $lastbgcolor) { $lastbgcolor = $newbgcolor; $out .= $newbgcolor; } $out .= $halfblock; #print utf8::encode("\N{FULL BLOCK}"); } ($r, $g, $b) = (0, 0, 0); $lastfgcolor = "\e[38;2;" . join(';', 255, 255, 255) . "m"; $lastbgcolor = "\e[48;2;" . join(';', 0, 0, 0) . "m"; $out .= $lastfgcolor . $lastbgcolor . "\n"; } my $now = time; my $fps = 0; if($self->{lastrender}) { $fps = (int((1 / ($now - $self->{lastrender})) * 100)/100); } $self->{lastrender} = $now; # Status line my ($pre, $post) = split/\./o, $fps; if(!defined($post)) { $post = '00'; } while(length($pre) < 4) { $pre = ' ' . $pre; } while(length($post) < 2) { $post .= '0'; } $fps = 'FPS: ' . $pre . '.' . $post; $fps .= ' ' x (18 - length($fps)); $out .= $fps; $out .= $self->{statustext}; if($self->{info} ne '') { $out .= $self->{info}; $out .= ' ' x (220 - length($self->{info})); } elsif($self->{progress} == -1) { $out .= ' ' x 220; } elsif($self->{info} ne '') { $out .= $self->{info}; $out .= ' ' x (220 - length($self->{info})); } else { $out .= $fullblock; my $full = int(218 * $self->{progress}); $out .= $darkshade x $full; $out .= $lightshade x (218-$full); $out .= $fullblock; } print $out; my $key = ReadKey(-1); if(defined($key)) { $key = ord($key); #croak("\n\n\n ** $key **\n"); if($key == 32) { return 1; } elsif($key == 27 || $key == 113) { return -1; } } return 0; }

My code is far from optimized, because i keep tinkering with it and optimization would make that much harder. If i reorganize how the data is layed out in memory, i could (potentially) rewrite the output function in C for better performance. But i'm currently not sure if one of the bottlenecks isn't simply the STDOUT output pipe to the Terminal. But potentially, with optimized code on a modern computer (mine is 12 years old), you could get 100s of frames per second. (Edit: Flattened image structure, pushed to mercurial. Still have to look into doing something with Inline::C)

There's also the possibility to go pure black&white, but increase the resolution to 4 pixels per character with the clever use of a combination of Unicode block characters. This would work quite well for line graphics and pencil sketches.

Another possible optimization would be to basically diff the current and previous image and only update the areas that have changed by jumping the cursor directly to that area. And example where that would be quite effective is the scroller in my demo. Frame-by-Frame, only about roughly 30% on average (probably less) of the screen lines change, and even those might have long stretches of unchanged characters. Basically, what you would do is to paint an interframe instead of a keyframe, to borrow from mpeg terminology. (Edit: Implemented the line-by-line buffering and pushed it to mercurial. It gives a somewhat higher framerate when not much is changing on screen. The "partial rows" update doesn't seem worth the hassle at the moment)

Additional links:

PerlMonks XP is useless? Not anymore: XPD - Do more with your PerlMonks XP

In reply to Re^2: Fun with terminal color by cavac
in thread Fun with terminal color by cavac

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.