# Raster bars

As there is no reference implementation, and rather sketchy task instructions, this may or may not fulfill the original task authors intent.

Not really sure what is meant by "swaying", perhaps this will suffice.

Generate random colored bars and display them. (They ended up looking more plastic than metallic; ah well.)

```perl
unit sub MAIN (
    Int :b(:$bar-height) is copy = 60; #= Height of the individual "Raster bars", minimum 32 (pixels)
    Int :d(:$dir) is copy        = -1; #= Scroll direction: -1 is "up" 1 is "down"
    Int :s(:$step) is copy       = 4;  #= Scroll speed (pixels per step
    Int :g(:$gap) is copy        = $bar-height + 50; #= Gap between bars (pixels)
    Int :a(:$angle) is copy      = 0; #= Angle to orient bars off horizontal (-60 to 60 degrees)
    Int :sw(:$sway) is copy      = 0; #= Swaying on / off
    Real :r(:$rnd) is copy       = 0; #= Delay between randomize events
);

say q:to/END/;

    Use Up / Down arrows to change the scroll speed.
    Use Left / Right arrows to adjust the gap between the raster bars.
    Use Pg Up / Pg Dn to adjust raster bar height.
    Use Z / X to change the angle of the raster bars.
    Use Space bar to pause / resume scrolling.
    Use Left Ctrl to toggle the scroll direction.
    Press R to toggle Randomize on / off.
    If Randomize is active, adjust the randomize delay with < / >
    Press S to toggle Swaying on / off.
    If Swaying is active, adjust the period with D / F
    Press Q to exit.
    END

use SDL2::Raw;
use Cairo;

my $width  = 800;
my $height = 800;

SDL_Init(VIDEO);

my $window = SDL_CreateWindow(
    'Raster Bars - Raku',
    SDL_WINDOWPOS_CENTERED_MASK,
    SDL_WINDOWPOS_CENTERED_MASK,
    $width, $height, RESIZABLE
);

my $render = SDL_CreateRenderer($window, -1, ACCELERATED +| PRESENTVSYNC);

my @bars = (^128).map: { gen-bar( rand xx 3 ) };

my $event = SDL_Event.new;

enum KEY_CODES (
    K_UP     => 82,
    K_DOWN   => 81,
    K_LEFT   => 80,
    K_RIGHT  => 79,
    K_SPACE  => 44,
    K_PGUP   => 75,
    K_PGDN   => 78,
    K_LCTRL  => 224,
    K_Z      => 29,
    K_X      => 27,
    K_Q      => 20,
    K_R      => 21,
    K_S      => 22,
    K_D      => 7,
    K_F      => 9,
    K_LT     => 54,
    K_GT     => 55,
);

my $port  = +@bars * $gap;
my $y     = $dir > 0 ?? $height - $port !! $height ;
my $now   = now;
my $period = 2;

main: loop {
    handle-event($event) while SDL_PollEvent($event);

    randomize if $rnd and now - $now > $rnd;

    if $dir > 0 {
        $y = $height - $port if $y > 0 - ceiling $height / cos(π * $angle / 180).abs
    } else {
        $y = 0 - ceiling $height / cos(π * $angle / 180).abs if $y < $height - $port
    }

    $y = $step * $dir + $y;

    $angle = (((now * $period) % τ).sin * 35).Int if $sway;

    for ^@bars {
        my $offset = $sway ?? $gap !! ceiling $gap / cos(π * $angle / 180).abs;
        SDL_RenderCopyEx( $render, @bars[$_], Nil,
          SDL_Rect.new( -($width*4), $y + $offset * $_, $width * 10, $bar-height),
          $angle.Num, SDL_Point.new(:x((4.5*$width).Int),:y($y + $offset * $_)), 0

        )
    }

    SDL_RenderPresent($render);

    SDL_RenderClear($render);

    print fps;
}

put '';

SDL_Quit();

sub gen-bar (@color) {
    my $bar = Cairo::Image.create( Cairo::FORMAT_ARGB32, 1, 128 );
    given Cairo::Context.new($bar) {
        my Cairo::Pattern::Gradient::Linear $lpat .= create(0.0, 0.0,  0.0, 128.0);
        $lpat.add_color_stop_rgba(  1, |(@color »*» .3), 1);
        $lpat.add_color_stop_rgba( .2, |(@color),        1);
        $lpat.add_color_stop_rgba(.75, |(@color),        1);
        $lpat.add_color_stop_rgba(  0, |(@color »+» .5), 1);
        .rectangle(0, 0, 1, 128);
        .pattern($lpat);
        .fill;
        $lpat.destroy;
    }

    my $bar_texture = SDL_CreateTexture(
        $render, %PIXELFORMAT<ARGB8888>,
        STATIC, 1, 128
    );

    SDL_UpdateTexture(
        $bar_texture,
        SDL_Rect.new(:x(0), :y(0), :w(1), :h(128)),
        $bar.data, $bar.stride // 1
    );

    $bar_texture
}

sub handle-event ($event) {
    my $casted_event = SDL_CastEvent($event);
    given $casted_event {
        when *.type == QUIT    { last main }
        when *.type == KEYDOWN {
            if KEY_CODES(.scancode) -> $comm {
                given $comm {
                    when 'K_UP'     { $step += 1 }
                    when 'K_DOWN'   { $step -= 1 if $step > 1 }
                    when 'K_LEFT'   { $gap = $gap < 32 ?? $gap !! $gap - 1; $port = +@bars * $gap; }
                    when 'K_RIGHT'  { $gap++; $port += +@bars; }
                    when 'K_PGUP'   { $bar-height += 2 }
                    when 'K_PGDN'   { $bar-height = $bar-height >= 34 ?? $bar-height - 2 !! $bar-height }
                    when 'K_SPACE'  { $step = $step ?? 0 !! 1 }
                    when 'K_LCTRL'  { $dir  *= -1 }
                    when 'K_Z'      { $angle = $angle > -45 ?? $angle - 5 !! $angle }
                    when 'K_X'      { $angle = $angle <  45 ?? $angle + 5 !! $angle }
                    when 'K_R'      { $rnd = $rnd ?? 0 !! 1 }
                    when 'K_S'      { $sway xor= 1 }
                    when 'K_F'      { $period += .1 }
                    when 'K_D'      { $period = $period - .1 max .1;  }
                    when 'K_GT'     { $rnd += .2 }
                    when 'K_LT'     { $rnd = $rnd > .2 ?? $rnd -.2 !! .2 }
                    when 'K_Q'      { last main }
                }
            } #else { say .scancode, "\n" }
        }
        when *.type == WINDOWEVENT {
            if .event == RESIZED {
                $width  = .data1;
                $height = .data2 + $bar-height;
            }
        }
    }
}

sub randomize {
    $dir   = (-1,1).pick;
    $step  = (4..8).pick;
    $bar-height   = (32..200).pick;
    $gap   = $bar-height + (1..100).pick;
    $angle = (-45, *+5 ... 45).pick;

    $port = +@bars * $gap;

    if $dir > 0 {
        $y = $height - $port;
    } else {
        $y = 0 - ceiling ($height max $width) / cos(π * $angle / 180).abs;
    }
    $now = now;
}

sub fps {
    state $fps-frames = 0;
    state $fps-now    = now;
    state $fps        = '';
    $fps-frames++;
    if now - $fps-now >= 1 {
        $fps = [~] "\b" x 40, ' ' x 20, "\b" x 20 ,
            sprintf "FPS: %5.2f  ", ($fps-frames / (now - $fps-now)).round(.01);
        $fps-frames = 0;
        $fps-now = now;
    }
    $fps
}
```

Screenshot still of typical run: [(offsite .png image)](https://github.com/thundergnat/rc/blob/master/img/Raster-bars-Perl6.png)

(Small) Moving gif of swaying bars: [(offsite .gif image)](https://github.com/thundergnat/rc/blob/master/img/Raster-bars-swaying-Raku.gif)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://trizen.gitbook.io/perl6-rosettacode/programming_tasks/r/raster_bars.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
