diff --git a/Prima/Drawable/Antialias.pm b/Prima/Drawable/Antialias.pm index adca2c53f..387537fce 100644 --- a/Prima/Drawable/Antialias.pm +++ b/Prima/Drawable/Antialias.pm @@ -88,11 +88,28 @@ sub polyline my ($x, $y, $w, $h) = $self->calc_poly_extents($poly); return 0 unless defined $x; - my $bitmap = $self->alloc_surface($w, $h) or goto FALLBACK; my $canvas = $self->{canvas}; + my $lp = $canvas->linePattern; + my $r2 = $canvas->rop2; + my $lw = $canvas->lineWidth; + my $solid_line; + if ($lp eq lp::Null) { + return 1 if $r2 == rop::NoOper; + return 0 unless $canvas-> graphic_context_push; + $canvas->color($canvas->backColor); + $canvas->linePattern(lp::Solid); + my $ok = $self->polyline($poly); + $canvas->graphic_context_pop; + return $ok; + } elsif ( $lp ne lp::Solid && $r2 == rop::CopyPut ) { + $solid_line = 1; + } + + + my $bitmap = $self->alloc_surface($w, $h) or goto FALLBACK; - if ($canvas-> lineWidth > 1 ) { - $bitmap->region( + if ($lw > 1 ) { + my $line = $bitmap->new_path-> scale($self->{factor})-> translate(-$x, -$y)-> @@ -103,12 +120,55 @@ sub polyline linePattern lineJoin lineEnd miterLimit ) )-> - region(fm::Winding) - ); + region(fm::Winding); + + if ( $solid_line ) { + my $solid = $bitmap->new_path-> + scale($self->{factor})-> + translate(-$x, -$y)-> + line($poly)-> + widen( + lineWidth => $self->{factor} * ($canvas-> lineWidth - 1), + map { $_ => $canvas->$_() } qw( + lineJoin lineEnd miterLimit + ) + )-> + region(fm::Winding); + + my $base = $self->alloc_surface( $w, $h ) or goto FALLBACK; + $solid->combine($line, rgnop::Xor); + $base->region($solid); + my $c = $canvas->color; + $canvas->color($canvas->backColor); + $base->bar( 0, 0, $base->size); + my $ok = $self->apply_surface($x, $y, $base); + $canvas->color($c); + return 0 unless $ok; + } + + $bitmap->region($line); $bitmap->bar( 0, 0, $bitmap->size); } else { $bitmap->translate(map { -1 * $self->{factor} * $_ } $x, $y); - $poly = Prima::Drawable->render_polyline( $poly, matrix => [$self->{factor},0,0,$self->{factor},0,0], integer => 1); + $poly = Prima::Drawable->render_polyline( $poly, + matrix => [($self->{factor},0,0) x 2], + integer => 1 + ); + + if ( $solid_line ) { + my $base = $self->alloc_surface( $w, $h ) or goto FALLBACK; + my $lp = $canvas->linePattern; + $lp =~ s/(.)(.)/$2$1/gsm; + $base->linePattern($lp); + $base->polyline($poly); + my $c = $canvas->color; + $canvas->color($canvas->backColor); + $base->polyline($poly); + my $ok = $self->apply_surface($x, $y, $base); + $canvas->color($c); + return 0 unless $ok; + } + $bitmap->linePattern( $canvas->linePattern ); $bitmap->polyline($poly); } return $self->apply_surface($x, $y, $bitmap); @@ -140,10 +200,12 @@ sub fillpoly $bitmap->region( $rgn ); my $colors; + my $restore_color; my $fp = $canvas->fillPattern; if ( ref($fp) ne 'ARRAY') { goto STIPPLE if $fp->type == im::BW && !$fp->isa('Prima::Icon'); + IMAGE: my @fp = $canvas->fillPatternOffset; $fp[0] -= $x; $fp[1] -= $y; @@ -157,13 +219,26 @@ sub fillpoly ); $colors->bar( 0, 0, $colors->size ); - } elsif ( !fp::is_solid($fp) && !fp::is_empty($fp) ) { + } elsif ( fp::is_empty($fp)) { + return 1 if $canvas->rop2 == rop::NoOper; + $restore_color = $canvas->color; + $canvas->color($canvas->backColor); + } elsif ( !fp::is_solid($fp)) { STIPPLE: $fp = Prima::Image->new( type => im::BW, size => [8,8], data => join('000', map { chr } @$fp), ) if ref($fp) eq 'ARRAY'; + + if ($canvas->rop2 == rop::CopyPut) { + if ($fp->type == im::BW) { + $fp->type(im::bpp1); + $fp->colormap( $canvas->backColor, $canvas->color ); + } + goto IMAGE; + } + $fp = $fp->clone( size => [ map { $_ * $self->{factor} } $fp-> size ] ); $bitmap->fillPattern($fp); @@ -174,7 +249,9 @@ sub fillpoly } $bitmap->bar( 0, 0, $bitmap->size); - return $self->apply_surface($x, $y, $bitmap, $colors); + my $ok = $self->apply_surface($x, $y, $bitmap, $colors); + $canvas->color($restore_color) if defined $restore_color; + return $ok; FALLBACK: return $self->{canvas}->fillpoly($poly); @@ -193,9 +270,9 @@ Prima::Drawable::Antialias - plot antialiased shapes Prima offers drawing antialiased lines and shapes, which is rather slow but provides better visual feedback. -The module augments the C drawing functionality by -adding C function, and contains two plotting functions, -C and C, identical to the ones in C. +The module augments the C drawing functionality by adding the +C function, which features two plotting methods, C +and C, identical to the ones in C. =head1 SYNOPSIS @@ -219,15 +296,13 @@ Creates a new AA surface object. The object is cheap to keep and reuse. =item fillpoly $POLY [ $FILLMODE ] -Paints an antialiased polygon shape. The following properties from C<$CANVAS> are respected: -color, fillPattern, fillPatternOffset. Does not plot opaque -patterned lines. +Paints an antialiased polygon shape. The following properties from the C<$CANVAS> +are respected: color, backColor, fillPattern, fillPatternOffset, rop2. =item polyline $POLY -Plots an antialiased polyline. The following properties from C<$CANVAS> are respected: -color, linePattern, lineWidth, lineEnd, lineJoin, miterLimit. Does not plot opaque -patterned lines. +Plots an antialiased polyline. The following properties from the C<$CANVAS> are respected: +color, backColor, linePattern, lineWidth, lineEnd, lineJoin, miterLimit, rop2 =back diff --git a/examples/antialias.pl b/examples/antialias.pl index a38813dd3..72a74836a 100644 --- a/examples/antialias.pl +++ b/examples/antialias.pl @@ -39,7 +39,12 @@ sub redraw $canvas-> new_path(antialias => 1)-> ellipse(100,100,100)->fill; $canvas-> fillPattern(fp::Solid); $canvas->lineWidth(5); - $canvas-> new_aa_surface(alpha => 128)-> polyline([ 0, 0, $canvas->size ]); + $canvas-> graphic_context( + backColor => cl::Yellow, + rop2 => rop::CopyPut, + linePattern => lp::Dash, + sub { $canvas-> new_aa_surface(alpha => 128)-> polyline([ 0, 0, $canvas->size ]) }, + ); if ( $canvas->can_draw_alpha ) { $canvas->color(cl::Green);