Graphics-Framebuffer

 view release on metacpan or  search on metacpan

lib/Graphics/Framebuffer.pm  view on Meta::CPAN

                    if (col8 != 0) res8 = fb / col8;
                    break;
                default:
                    break;
            }
            *p = res8;
        } break;

        case 1: {
            /* Not supported yet; no-op */
        } break;

        default:
            break;
    }
}

/* Draws a line */
void c_line(char *framebuffer,
            short x1,
            short y1,
            short x2,
            short y2,
            short x_clip,
            short y_clip,
            short xx_clip,
            short yy_clip,
            unsigned int color,
            unsigned int bcolor,
            unsigned char alpha,
            unsigned char draw_mode,
            unsigned char bytes_per_pixel,
            unsigned char bits_per_pixel,
            unsigned int bytes_per_line,
            short xoffset,
            short yoffset,
            bool antialiased) {
    /* If antialiasing is requested, use Xiaolin Wu's algorithm... */
    if (antialiased) {
        double x0 = (double)x1;
        double y0 = (double)y1;
        double x1d = (double)x2;
        double y1d = (double)y2;

        int steep = fabs(y1d - y0) > fabs(x1d - x0);

        if (steep) {
            swap_(x0, y0);
            swap_(x1d, y1d);
        }

        if (x0 > x1d) {
            swap_(x0, x1d);
            swap_(y0, y1d);
        }

        double dx = x1d - x0;
        double dy = y1d - y0;
        double gradient = (dx == 0.0) ? 1.0 : dy / dx;

        /* handle first endpoint */
        double xend = roundd(x0);
        double yend = y0 + gradient * (xend - x0);
        double xgap = rfpart(x0 + 0.5);
        long xpxl1 = (long)xend;
        long ypxl1 = (long)floor(yend);

        /* plot first endpoint */
        double intery = yend + gradient; /* first y-intersection for the main loop */

        /* First endpoint pixels */
        plot_aa_pixel(framebuffer,
                      color,
                      bcolor,
                      alpha,
                      bytes_per_pixel,
                      bits_per_pixel,
                      bytes_per_line,
                      x_clip,
                      y_clip,
                      xx_clip,
                      yy_clip,
                      xoffset,
                      yoffset,
                      steep,
                      xpxl1,
                      ypxl1,
                      rfpart(yend) * xgap);
        plot_aa_pixel(framebuffer,
                      color,
                      bcolor,
                      alpha,
                      bytes_per_pixel,
                      bits_per_pixel,
                      bytes_per_line,
                      x_clip,
                      y_clip,
                      xx_clip,
                      yy_clip,
                      xoffset,
                      yoffset,
                      steep,
                      xpxl1,
                      ypxl1 + 1,
                      fpart(yend) * xgap);

        /* handle second endpoint */
        xend = roundd(x1d);
        yend = y1d + gradient * (xend - x1d);
        xgap = fpart(x1d + 0.5);
        long xpxl2 = (long)xend;
        long ypxl2 = (long)floor(yend);

        plot_aa_pixel(framebuffer,
                      color,
                      bcolor,
                      alpha,
                      bytes_per_pixel,
                      bits_per_pixel,
                      bytes_per_line,
                      x_clip,
                      y_clip,
                      xx_clip,
                      yy_clip,
                      xoffset,
                      yoffset,
                      steep,
                      xpxl2,
                      ypxl2,
                      rfpart(yend) * xgap);
        plot_aa_pixel(framebuffer,
                      color,
                      bcolor,
                      alpha,
                      bytes_per_pixel,
                      bits_per_pixel,
                      bytes_per_line,
                      x_clip,
                      y_clip,
                      xx_clip,
                      yy_clip,
                      xoffset,
                      yoffset,
                      steep,
                      xpxl2,
                      ypxl2 + 1,
                      fpart(yend) * xgap);

        /* main loop */
        long x;
        if (xpxl1 + 1 <= xpxl2 - 1) {
            for (x = xpxl1 + 1; x <= xpxl2 - 1; x++) {
                double iy = intery;
                long yint = (long)floor(iy);
                plot_aa_pixel(framebuffer,
                              color,
                              bcolor,
                              alpha,
                              bytes_per_pixel,
                              bits_per_pixel,
                              bytes_per_line,
                              x_clip,
                              y_clip,
                              xx_clip,
                              yy_clip,
                              xoffset,
                              yoffset,

lib/Graphics/Framebuffer.pm  view on Meta::CPAN

                    $self->plot({ 'x' => $start_x, 'y' => $start_y });
                    $start_x--;
                    $start_y--;
                }
            } ## end elsif (($start_x > $x_end...))

        } ## end else [ if (($x_end == $start_x...))]
    } ## end else [ if ($self->{'ACCELERATED'...})]
    $self->{'X'} = $XX;
    $self->{'Y'} = $YY;
} ## end sub drawto

sub _flush_screen {
    # Since the framebuffer is mappeed as a string device, Perl buffers the output, and this must be flushed.
    my $self = shift;

	if ($self->{'DEVICE'} eq 'EMULATED') {
		select(STDERR);
		$| = 1;
	} elsif (defined($self->{'FB'})) {
		select($self->{'FB'});
		$| = 1;
		$self->{'FB'}->flush();
		eval {sync $self->{'SCREEN'}, TRUE;};
		$self->vsync();
	}
	$self->{'LAST_FLUSHED'} = time;
} ## end sub _flush_screen

sub _adj_plot {
    # Part of antialiased drawing
    my ($self, $x, $y, $c, $s) = @_;

    $self->set_color({ 'red' => $s->{'red'} * $c, 'green' => $s->{'green'} * $c, 'blue' => $s->{'blue'} * $c });
    $self->plot({ 'x' => $x, 'y' => $y });
} ## end sub _adj_plot

sub _draw_line_antialiased {
    my ($self, $x0, $y0, $x1, $y1) = @_;

    my $saved = { %{ $self->{'SET_RAW_FOREGROUND_COLOR'} } };

    my $plot = \&_adj_plot;

    if (abs($y1 - $y0) > abs($x1 - $x0)) {
        $plot = sub { _adj_plot(@_[0, 2, 1, 3, 4]) };
        ($x0, $y0, $x1, $y1) = ($y0, $x0, $y1, $x1);
    }

    if ($x0 > $x1) {
        ($x0, $x1, $y0, $y1) = ($x1, $x0, $y1, $y0);
    }

    my $dx       = $x1 - $x0;
    my $dy       = $y1 - $y0;
    my $gradient = $dy / $dx;

    my @xends;
    my $intery;

    # handle the endpoints
    foreach my $xy ([$x0, $y0], [$x1, $y1]) {
        my ($x, $y) = @{$xy};
        my $xend = int($x + 0.5);                   # POSIX::lround($x);
        my $yend = $y + $gradient * ($xend - $x);
        my $xgap = _rfpart($x + 0.5);

        my $x_pixel = $xend;
        my $y_pixel = int($yend);
        push(@xends, $x_pixel);

        $plot->($self, $x_pixel, $y_pixel,     _rfpart($yend) * $xgap, $saved);
        $plot->($self, $x_pixel, $y_pixel + 1, _fpart($yend) * $xgap,  $saved);
        next if (defined($intery));

        # first y-intersection for the main loop
        $intery = $yend + $gradient;
    } ## end foreach my $xy ([$x0, $y0],...)

    # main loop

    foreach my $x ($xends[0] + 1 .. $xends[1] - 1) {
        $plot->($self, $x, int($intery),     _rfpart($intery), $saved);
        $plot->($self, $x, int($intery) + 1, _fpart($intery),  $saved);
        $intery += $gradient;
    }
    $self->set_color($saved);
} ## end sub _draw_line_antialiased

=head2 bezier

Draws a Bezier curve, based on a list of control points.

=over 4

 $fb->bezier(
     {
         'coordinates' => [
             x0,y0,
             x1,y1,
             ...              # As many as needed, there MUST be an even number of elements
         ],
         'points'     => 100, # Number of total points plotted for curve
                              # The higher the number, the smoother the curve.
         'closed'     => 1,   # optional, close it and make it a full shape.
         'filled'     => 1    # Results may vary, optional
         'gradient' => {
              'direction' => 'horizontal', # or vertical
              'colors'    => { # 2 to any number of transitions allowed
                  'red'   => [255,255,0], # Red to yellow to cyan
                  'green' => [0,255,255],
                  'blue'  => [0,0,255]
              }
          }
     }
 );

=back

* This is not affected by the Acceleration setting



( run in 1.774 second using v1.01-cache-2.11-cpan-524268b4103 )