=pod
=head1 NAME
examples/matrix.pl - A matrix screen-saver
=head1 FEATURES
Tests the paletted DeviceBitmap implementation
and large font output performance.
=cut
use strict;
use warnings;
use Prima;
use Prima::Application;
my $smp = "The Matrix has you";
my $maxstep = 40;
my $ymaxstep = 60;
my $widefactor = 0.05; # range 0.01 - 0.3
my $digitShades = 8; # range 1 - 20
my $textShades = 3; # range 1 - 20
my $shadesDepth = 4; # range 1 - 100
my $xshspeed = 0.2; # range 1 - 4
my $basicfsize = 10; # range 6 - 24
my $vlines = 40; # range 10 - 80
my $textToBMRatio = 0.3; # range 0.01 - 0.9
my $digitTicks = 150; # range 1-...
my $textTicks = 30; # range 1-...
my $maxln = length( $smp);
my @vlinst = map { int( rand( $ymaxstep))} 1..$vlines;
my @vlbminst = map { int( rand( $ymaxstep))} 1..$vlines;
my @vlsped = (( 1) x $vlines);
my @vlbmsped = (( 1) x $vlines);
my @vlbms = map { int( rand( 3))} 1..$vlines;
my @vlxcol = (( 0) x $vlines);
my @vlbmxcol = (( 0) x $vlines);
my $xshcnt = -100;
my $xshdir = 1;
my $xcol = 30;
my $yextraspeed = 0;
my $ticker = 10000000;
my $tickerMode = 0;
my $shades = 0;
my $showBigText = 1;
my $showSmallText = 1;
my $showBitmaps = 1;
my $fullScreen = 0;
my %fsh = ();
my %fhh = ();
my @dbms = ();
sub efont
{
my ( $c, $id) = @_;
my $oheight;
if ( exists $fsh{ $basicfsize}) {
$oheight = $fsh{ $basicfsize};
} else {
$c-> font-> size( $basicfsize);
$oheight = $c-> font-> height;
$fsh{ $basicfsize} = $oheight;
}
$oheight = int( $oheight * ( 2 ** ( $id / 6)));
my $owidth;
if ( exists $fhh{ $oheight}) {
$owidth = $fhh{ $oheight};
} else {
$c-> font-> height( $oheight);
$owidth = $c-> font-> width;
$fhh{$oheight} = $owidth;
}
$owidth = $owidth * $id * $widefactor;
$owidth = ( $owidth < 1) ? 1 : $owidth;
if ( $xshcnt > 100) {
$xshdir = -0.1;
} elsif ( $xshcnt < -100) {
$xshdir = 5;
}
$xshcnt += $xshdir * $xshspeed;
$c-> font-> set(
height => $oheight,
width => $owidth,
direction => ($xshcnt + $id / $maxstep * 6) / 10,
);
}
sub ecolor
{
my ( $c, $f, $b, $p) = @_;
$p = 1 if $p > 1;
$p = 0 if $p < 0;
$p =
(((( $f >> 16) * $p) + (( $b >> 16) * ( 1 - $p))) << 16) |
((((( $f >> 8) & 0xFF) * $p) + ((( $b >> 8) & 0xFF) * ( 1 - $p))) << 8)|
((( $f & 0xFF) * $p) + (( $b & 0xFF) * ( 1 - $p)));
$c-> color( $p);
}
my $i;
my @spal = ();
for ( $i = 0; $i < 256; $i++) {
push( @spal, 0, $i, 0);
};
my @gifs = map { Prima::Image-> load( 'matrix.gif', index => $_)} 0..2;
@gifs = () unless $gifs[0];
my @wsaverect;
sub resetfs
{
my $self = $_[0];
my @sz = $self-> size;
my $min = $sz[0] < $sz[1] ? $sz[0] : $sz[1];
$basicfsize = int( $min / 100);
$self-> font-> size( $basicfsize);
$ymaxstep = $sz[1] / $self-> font-> height + length( $smp) * 2;
@vlxcol = map { int(rand( $sz[0] - 30)) + 15 } 1..$vlines;
@vlbmxcol = map { int(rand( $sz[0] - 30)) + 15 } 1..$vlines;
my $fw = $self-> font-> height;
@dbms = map {
my $x = $_-> dup;
$x-> size( $fw, $_-> height * $fw / 21);
$x-> bitmap;
} @gifs;
}
my $w = Prima::MainWindow-> create(
palette => [@spal],
font => { name => 'Courier New', size => $basicfsize, },
backColor => 0x002000,
windowState => ws::Maximized,
color => cl::LightGreen,
menuItems => [
["~Options" => [
[ '@*bt' => 'Show ~big text' => sub { $showBigText = $_[2]; }],
[ '@*st' => 'Show ~small text' => sub { $showSmallText = $_[2]; }],
[ '@*bm' => 'Show bit~maps' => sub { $showBitmaps = $_[2] }],
[],
['~Full screen' => sub {
$fullScreen = 1;
@wsaverect = $_[0]-> rect;
$_[0]-> rect( 0, 0, $_[0]-> owner-> size);
}, ],
]],
],
onKeyDown => sub {
return unless $fullScreen;
$fullScreen = 0;
$_[0]-> rect( @wsaverect);
},
onMouseDown => sub {
return unless $fullScreen;
$fullScreen = 0;
$_[0]-> rect( @wsaverect);
},
onPaint => sub {
my ( $self, $c) = @_;
my @sz = $c-> size;
my $cc = $self-> color;
$ticker++;
my $lim = $tickerMode ? $digitTicks : $textTicks;
if ( $ticker > $lim) {
$ticker = 0;
$tickerMode = !$tickerMode;
$shades = $tickerMode ? $digitShades : $textShades;
}
if ( $tickerMode || ( $ticker % 2) || ( $ticker < $textTicks / 2)) {
$c-> color( $self-> backColor);
} else {
$c-> color( 0x00F000);
}
$c-> bar( 0,0,@sz);
$self-> {xcnt} = 1 if ++$self-> {xcnt} >= $maxstep;
my $ymans;
my $fh = $c-> font-> height;
if ( $showBitmaps) {
for ( $ymans = 0; $ymans < $vlines; $ymans++) {
my $y = $sz[1] - $vlbminst[ $ymans] * $fh;
$c-> put_image( $sz[0] - $vlbmxcol[ $ymans], $y,
$dbms[ $vlbms[ $ymans]]);
if ( ++$vlbminst[ $ymans] >= $ymaxstep) {
$vlbminst[ $ymans] = 1;
$vlbmxcol[ $ymans] = int( rand( $sz[0] - 30)) + 15;
$vlbmsped[ $ymans] = rand( 3) - 1;
$vlbmsped[ $ymans] = 0 if $vlbmsped[ $ymans] < 0;
$vlbmsped[ $ymans] *= 3;
}
$vlbminst[ $ymans] += $vlbmsped[ $ymans];
}
}
if ( $showBigText) {
for ( 0..$shades) {
my $x = $self-> {xcnt} - (( $shades - $_) * $shadesDepth);
$x += $maxstep if $x <= 0;
efont( $c, $x);
#$x -= ( $shades - $_);
#$x += $shades;
#next if $x <= 0;
$x = $x - (( $shades - $_) * $shadesDepth);
ecolor( $c, $cc, $self-> backColor, $x / 30);
my $mp;
if ( $tickerMode) {
$mp = abs( 10 * int( $c-> font-> direction));
if ( $mp < 100) {
$mp = $mp * 10 + $mp / 10;
} else {
$mp = $mp * 100 + reverse($mp / 10);
}
} else {
$mp = $smp;
}
$c-> text_out( $mp,
( $sz[0] - $c-> get_text_width( $mp)) / 2,
( $sz[1] - $c-> font-> height) / 2);
}
}
$c-> font-> set (
size => $basicfsize * 1.5,
style => fs::Bold,
direction => 0,
);
$c-> color( $cc);
$fh = $c-> font-> height;
if ( $showSmallText) {
for ( $ymans = 0; $ymans < $vlines * $textToBMRatio; $ymans++) {
if ( ++$vlinst[ $ymans] >= $ymaxstep) {
$vlinst[ $ymans] = 1;
$vlxcol[ $ymans] = int( rand( $sz[0] - 30)) + 15;
$vlsped[ $ymans] = rand( 3) - 1;
$vlsped[ $ymans] = 0 if $vlsped[ $ymans] < 0;
$vlsped[ $ymans] *= 3;
}
my $y = $sz[1] - ($vlinst[ $ymans] - $maxln) * $fh;
my $i;
$vlinst[ $ymans] += $vlsped[ $ymans];
ecolor( $c, $cc, cl::Yellow, 0.5) if $vlsped[ $ymans] > 1;
$y = $sz[1] - ($vlinst[ $ymans] - $maxln) * $fh;
for ( $i = 0; $i < $maxln; $i++) {
$c-> text_out( substr( $smp, $i, 1),
$vlxcol[ $ymans] / $textToBMRatio, $y);
$y -= $fh;
}
$c-> color( $cc) if $vlsped[ $ymans] > 1;
}
}
},
onSize => sub {
resetfs( $_[0]);
},
onCreate => sub {
resetfs( $_[0]);
},
buffered => 1,
);
$w-> insert( Timer =>
timeout => 50 => onTick => sub {
$w-> repaint;
})-> start;
run Prima;