#!perl
#
# eg/bench - benchmark Bresenham versus pure perl and C versions of the
# linear interpolation algorithm. results are down at the bottom

use 5.22.0;
use warnings;
use constant {
    XX => 0,
    YY => 1,
};

use Algorithm::Line::Lerp 'line';
use Benchmark 'cmpthese';
use POSIX 'lround';    # >= perl 5.22 (2015)

package Bresenham {
    use integer;
    use constant {
        XX => 0,
        YY => 1,
    };

    sub line {
        my ( $x, $y ) = @{ $_[0] };
        my $dx  = abs( $_[1][XX] - $x );
        my $sx  = $x < $_[1][XX] ? 1 : -1;
        my $dy  = abs( $_[1][YY] - $y );
        my $sy  = $y < $_[1][YY] ? 1 : -1;
        my $err = ( $dx > $dy ? $dx : -$dy ) / 2;
        my @points;
        while (1) {
            push @points, [ $x, $y ];
            last if $x == $_[1][XX] and $y == $_[1][YY];
            my $e2 = $err;
            if ( $e2 > -$dx ) {
                $err -= $dy;
                $x   += $sx;
            }
            if ( $e2 < $dy ) {
                $err += $dx;
                $y   += $sy;
            }
        }
        return \@points;
    }
}

sub ppline {
    my ( $x, $y ) = @{ $_[0] };
    my $dx = $_[1][XX] - $x;
    my $dy = $_[1][YY] - $y;

    my $distance = abs($dx);
    my $m        = abs($dy);
    $distance = $m if $m > $distance;
    return [ 0, 0 ] if $distance == 0;

    my @points;
    my $divn  = 1.0 / $distance;
    my $xstep = $dx * $divn;
    my $ystep = $dy * $divn;
    my $step  = 0;
    while ( $step <= $distance ) {
        push @points, [ lround($x), lround($y) ];
        $step++;
        $x += $xstep;
        $y += $ystep;
    }
    return \@points;
}

sub points_of {
    join ' ', map { "$_->[0],$_->[1]" } @{ $_[0] };
}

my $first = [ 0, 0 ];
my $last  = [ 2, 11 ];

# are the results sane for each? (there may be slight variance if lround
# does something different than Bresenham does?)
say "B  ", points_of( Bresenham::line( $first, $last ) );
say "C  ", points_of( line( $first, $last ) );
say "PP ", points_of( ppline( $first, $last ) );

cmpthese(
    -10,
    {   bresenham => sub { Bresenham::line( $first, $last ) },
        lerp_c    => sub { line( $first, $last ) },
        lerp_pp   => sub { ppline( $first, $last ) },
    }
);

__END__

	B  0,0 0,1 0,2 1,3 1,4 1,5 1,6 1,7 1,8 2,9 2,10 2,11
	C  0,0 0,1 0,2 1,3 1,4 1,5 1,6 1,7 1,8 2,9 2,10 2,11
	PP 0,0 0,1 0,2 1,3 1,4 1,5 1,6 1,7 1,8 2,9 2,10 2,11
				  Rate   lerp_pp bresenham    lerp_c
	lerp_pp    49508/s        --      -10%      -70%
	bresenham  55192/s       11%        --      -67%
	lerp_c    166387/s      236%      201%        --

so on my system Bresenham actually comes in a bit faster than the pure
perl linear interpolation, maybe due to Bresenham doing `use integer`?
Game::Xomb has a C version of Bresenham that might be good to compare
against lerp, but that code uses a callback instead of returning the
points and is customized to stay within the game bounds
