#!/usr/bin/perl -w use strict; use constant SIZE => 256; use constant SCALE => SIZE / 1024; if( -t STDOUT ) { die "Giving up early because stdout is a tty\n"; } # Edge definition (bezier curve control points in absolute coordinates). my @points = ( [128,896], [128,512],[640,256],[896,128], [1024,384],[768,640],[896,896], [640,1024],[512,896],[128,896] ); # Output image buffer. my $image = chr(0) x (SIZE * SIZE); # Interpolate between two values. sub interpolate($$$) { my ($a, $b, $t) = @_; return $a + ($b - $a) * $t; } # Syntactic sugar. sub min($$) { my ($a, $b) = @_; return $a < $b ? $a : $b; } sub max($$) { my ($a, $b) = @_; return $a > $b ? $a : $b; } # Draw outlined shape. sub draw_outline($) { my ($color) = @_; for(my $i = 0; $i + 3 < scalar @points; $i += 3) { my $x0 = SCALE * $points[$i][0]; my $x1 = SCALE * $points[$i + 1][0]; my $x2 = SCALE * $points[$i + 2][0]; my $x3 = SCALE * $points[$i + 3][0]; my $y0 = SCALE * $points[$i][1]; my $y1 = SCALE * $points[$i + 1][1]; my $y2 = SCALE * $points[$i + 2][1]; my $y3 = SCALE * $points[$i + 3][1]; for(my $j = 0; $j < (SIZE * 2); $j++) { my $t = $j / (SIZE * 2); my $x = interpolate(interpolate(interpolate($x0, $x1, $t), interpolate($x1, $x2, $t), $t), interpolate(interpolate($x1, $x2, $t), interpolate($x2, $x3, $t), $t), $t); my $y = interpolate(interpolate(interpolate($y0, $y1, $t), interpolate($y1, $y2, $t), $t), interpolate(interpolate($y1, $y2, $t), interpolate($y2, $y3, $t), $t), $t); my $ix = int($x); my $iy = int($y); if( $ix >= 0 && $ix < SIZE && $iy >= 0 && $iy < SIZE ) { substr($image, $iy * SIZE + $ix, 1) = $color; } } } } # Draw filled shape by scanlines. sub draw_scanlines($) { my ($color) = @_; my @ranges = (); for(my $i = 0; $i < SIZE; $i++) { push @ranges, [undef, undef]; } # Collect ranges. for(my $i = 0; $i + 3 < scalar @points; $i += 3) { my $x0 = SCALE * $points[$i][0]; my $x1 = SCALE * $points[$i + 1][0]; my $x2 = SCALE * $points[$i + 2][0]; my $x3 = SCALE * $points[$i + 3][0]; my $y0 = SCALE * $points[$i][1]; my $y1 = SCALE * $points[$i + 1][1]; my $y2 = SCALE * $points[$i + 2][1]; my $y3 = SCALE * $points[$i + 3][1]; for(my $j = 0; $j < SIZE * 2; $j++) { my $t = $j / (SIZE * 2); my $x = interpolate(interpolate(interpolate($x0, $x1, $t), interpolate($x1, $x2, $t), $t), interpolate(interpolate($x1, $x2, $t), interpolate($x2, $x3, $t), $t), $t); my $y = interpolate(interpolate(interpolate($y0, $y1, $t), interpolate($y1, $y2, $t), $t), interpolate(interpolate($y1, $y2, $t), interpolate($y2, $y3, $t), $t), $t); my $ix = int($x); my $iy = int($y); if( $ix >= 0 && $ix < SIZE && $iy >= 0 && $iy < SIZE ) { if( defined($ranges[$iy][0]) ) { $ranges[$iy][0] = min($ranges[$iy][0], $ix); $ranges[$iy][1] = max($ranges[$iy][1], $ix); } else { $ranges[$iy][0] = $ranges[$iy][1] = $ix; } } } } # Draw scanlines. for(my $y = 0; $y < SIZE; $y++) { if( defined($ranges[$y][0]) ) { my $w = $ranges[$y][1] - $ranges[$y][0] + 1; substr($image, $y * SIZE + $ranges[$y][0], $w) = $color x $w; } } } draw_scanlines(chr(0x40)); draw_outline(chr(0xff)); print "P5\n", SIZE, " ", SIZE, "\n255\n", $image;