1use strict; 2use warnings; 3 4use Test::More; 5use Prima::sys::Test; 6use Prima::Application; 7 8my $dbm = Prima::DeviceBitmap->new( size => [5, 5], monochrome => 1); 9my $r; 10 11sub try($$) 12{ 13 my ( $name, $expected ) = @_; 14 $dbm->region(undef); 15 $dbm->clear; 16 $dbm->region($r); 17 $dbm->bar(0,0,$dbm->size); 18 19 my $i = $dbm->image; 20 $i->type(im::Byte); 21 $i->mirror(1); 22 my $data = $i->data; 23 $data =~ s/(.{5}).{3}/$1/gs; 24 $data =~ s/[^\x00]/ /g; 25 $data =~ s/\x00/*/g; 26 is( $data, $expected, $name); 27} 28 29# empty 30try('empty undef',"*" x 25); 31$r = Prima::Region->new; 32ok($r, 'empty rgn'); 33ok($r->is_empty, 'is empty'); 34try('empty def'," " x 25); 35is_deeply([$r->box], [0,0,0,0], 'empty/box'); 36 37# rect 38$r = Prima::Region->new( box => [0, 0, 1, 1]); 39ok(!$r->is_empty, 'not empty'); 40try('box 1x1', 41 " ". 42 " ". 43 " ". 44 " ". 45 "* " 46); 47is_deeply([$r->box], [0,0,1,1], 'box 1x1/box'); 48$r->offset(2,2); 49try('box 1x1 + 2.2', 50 " ". 51 " ". 52 " * ". 53 " ". 54 " " 55); 56is_deeply([$r->box], [2,2,1,1], 'box 1x1/box + 2.2'); 57$r->offset(-4,-4); 58is_deeply([$r->box], [-2,-2,1,1], 'box 1x1/box - 2.2'); 59 60$r = Prima::Region->new( box => [1, 1, 3, 3]); 61try('box 3x3', 62 " ". 63 " *** ". 64 " *** ". 65 " *** ". 66 " " 67); 68is_deeply([$r->box], [1,1,3,3], 'box 3x3/box'); 69 70my $r2 = Prima::Region->new( rect => [1, 1, 4, 4]); 71ok( $r->equals($r2), 'equals'); 72 73my @star = (0, 0, 2, 5, 5, 0, 0, 3, 5, 3); 74$r = Prima::Region->new(polygon => \@star, fillMode => fm::Alternate); 75my @box = $r->box; 76ok($box[0] < $box[2] && $box[1] < $box[3], 'star 1'); 77 78$r2 = Prima::Region->new(polygon => \@star, fillMode => fm::Winding); 79@box = $r->box; 80ok($box[0] < $box[2] && $box[1] < $box[3], 'star 2'); 81ok( !$r-> equals($r2), 'poly winding'); 82 83my $image = Prima::Image->new( 84 size => [4,4], 85 type => im::Byte, 86 data => 87 "\xff\xff\xff\x00". # y=0 88 "\xff\xff\xff\x00". 89 "\xff\xff\xff\x00". 90 "\x00\x00\x00\x00" # y=3 91); 92$r = Prima::Region->new(image => $image); 93is_deeply([$r->box], [0,0,3,3], 'image'); 94 95ok( $r-> point_inside(0,0), "point inside 0,0"); 96ok( $r-> point_inside(2,2), "point inside 2,2"); 97ok( !$r-> point_inside(2,3), "point inside 2,3"); 98ok( !$r-> point_inside(3,2), "point inside 3,2"); 99 100is( $r-> rect_inside(0,0,0,0), rgn::Inside, "rect inside 0,0,0,0"); 101is( $r-> rect_inside(1,1,2,2), rgn::Inside, "rect inside 1,1,2,2"); 102is( $r-> rect_inside(2,2,3,3), rgn::Partially, "rect partially inside 2,2,3,3"); 103is( $r-> rect_inside(3,3,3,3), rgn::Outside, "rect outside 3,3,3,3"); 104 105$dbm->region($image); 106@box = $dbm->clipRect; 107is_deeply(\@box, [0,0,2,2], 'region clip rect'); 108 109my $dbm2 = Prima::DeviceBitmap->new( size => [5,5], type => dbt::Pixmap ); 110$dbm2->region($image); 111@box = $dbm->clipRect; 112is_deeply(\@box, [0,0,2,2], 'region clip rect on pixmap'); 113 114if ( $::application->get_system_value(sv::LayeredWidgets)) { 115 $dbm2 = Prima::DeviceBitmap->new( size => [5,5], type => dbt::Layered ); 116 $dbm2->region($image); 117 @box = $dbm->clipRect; 118 is_deeply(\@box, [0,0,2,2], 'region box on layered'); 119} 120 121$r2 = $dbm->region; 122is_deeply([$r2->box], [0,0,3,3], 'region reused'); 123$r = $r2; 124try('reused check 2', 125 " ". 126 " ". 127 "*** ". 128 "*** ". 129 "*** " 130); 131 132 133$dbm->region( undef ); 134@box = $dbm->clipRect; 135is_deeply(\@box, [0,0,4,4], 'empty clip rect'); 136 137$r2 = Prima::Region->new( box => [1, 1, 2, 2]); 138$r = $r2->dup; 139try('rgnop::Copy', 140 " ". 141 " ". 142 " ** ". 143 " ** ". 144 " " 145); 146 147my $r3 = Prima::Region->new( box => [2, 2, 2, 2]); 148$r = $r2->dup; 149$r->combine( $r3, rgnop::Union); 150try('rgnop::Union', 151 " ". 152 " ** ". 153 " *** ". 154 " ** ". 155 " " 156); 157 158$r = $r2->dup; 159$r->combine( $r3, rgnop::Intersect); 160try('rgnop::Intersect', 161 " ". 162 " ". 163 " * ". 164 " ". 165 " " 166); 167 168$r = $r2->dup; 169$r->combine( $r3, rgnop::Xor); 170try('rgnop::Xor', 171 " ". 172 " ** ". 173 " * * ". 174 " ** ". 175 " " 176); 177 178$r = $r2->dup; 179$r->combine( $r3, rgnop::Diff); 180try('rgnop::Diff', 181 " ". 182 " ". 183 " * ". 184 " ** ". 185 " " 186); 187 188$r = $dbm->region; 189try('region re-reuse', 190 " ". 191 " ". 192 " * ". 193 " ** ". 194 " " 195); 196 197sub bits { join ':', map { sprintf "%08b", ord } split '', shift } 198sub bytes { unpack('H*', shift ) } 199 200sub is_bytes 201{ 202 my ( $bytes_actual, $bytes_expected, $name ) = @_; 203 my $ok = $bytes_actual eq $bytes_expected; 204 ok( $ok, $name ); 205 warn "# " . bytes($bytes_actual) . " (actual)\n# " . bytes($bytes_expected) . " (expected)\n" unless $ok; 206} 207 208sub sort_boxes($) 209{ 210 my @b = @{$_[0]}; 211 my (@x,@r); 212 push @r, [@x] while @x = splice(@b, 0, 4); 213 @r = sort { "@$a" cmp "@$b" } @r; 214 return [ map { @$_ } @r]; 215} 216 217sub is_rects 218{ 219 my ($r, $rects, $name) = @_; 220 my $boxes = sort_boxes $r->get_boxes; 221 $rects = sort_boxes $rects; 222 my $ok = is_deeply( $boxes, $rects, $name); 223 warn "# (@$boxes) vs (@$rects)\n" unless $ok; 224 return $ok; 225} 226 227$r = Prima::Region->new; 228$r = Prima::Region->new( rect => [0,1,2,3,4,5,6,7]); 229is_rects($r, [0,1,2,2,4,5,2,2], "two simple rects"); 230ok( $r->equals( Prima::Region->new(box => $r->get_boxes)), "is equal (1)"); 231$r = Prima::Region->new( box => [0,1,2,3,4,5,6,7]); 232is_rects($r, [0,1,2,3,4,5,6,7], "two simple boxes"); 233ok( $r->equals( Prima::Region->new(box => $r->get_boxes)), "is equal (2)"); 234$r = Prima::Region->new( polygon => [0,0,0,5,5,5,5,0], fillMode => fm::Overlay | fm::Winding); 235is_rects($r, [0,0,6,6], "simple polygon"); 236ok( $r->equals( Prima::Region->new(box => $r->get_boxes)), "is equal (3)"); 237 238my $b = Prima::Image->new( 239 size => [5,5], 240 type => im::Byte, 241); 242 243sub render 244{ 245 my $rx = shift; 246 $b->region(undef); 247 $b->color(cl::Black); 248 $b->bar(0,0,$b->size); 249 $b->color(cl::White); 250 $b->region($rx); 251 $b->bar(0,0,$b->size); 252} 253 254$r = Prima::Region->new( polygon => [0,0,0,5,5,5,5,0, 0,0,0,2,2,2,2,0], fillMode => fm::Winding|fm::Overlay); 255render($r); 256is( $b->sum, 25 * 255, "polygon with winding"); 257ok( $r->equals( Prima::Region->new(box => $r->get_boxes)), "is equal (4)"); 258 259$r = Prima::Region->new( polygon => [0,0,0,5,5,5,5,0, 0,0,0,2,2,2,2,0], fillMode => fm::Alternate|fm::Overlay); 260render($r); 261is( $b->sum, 24 * 255, "polygon without winding"); 262ok( $r->equals( Prima::Region->new(box => $r->get_boxes)), "is equal (5)"); 263 264ok( 265 $b->pixel(0,0) != 0 && 266 $b->pixel(1,0) != 0 && 267 $b->pixel(0,1) != 0 && 268 $b->pixel(1,1) == 0, 269 "pixels are in correct position" 270); 271my $d = $b->data; 272render($b->to_region); 273is_bytes($d, $b->data, "region to image and back is okay"); 274 275$b->size(4,4); 276$r = Prima::Region->new( box => [-1,-1,3,3, 2,2,3,3]); 277render($r); 278is_bytes($b->data, ("\xff\xff\x00\x00" x 2).("\x00\x00\xff\xff" x 2), "region outside the box"); 279$b->color(0x808080); 280$b->bar(1,1,2,2); 281is_bytes($b->data, 282 "\xff\xff\x00\x00". 283 "\xff\x80\x00\x00". 284 "\x00\x00\x80\xff". 285 "\x00\x00\xff\xff", 286 "bar inside region" 287); 288$b->translate(0,0); 289render(undef); 290$b->color(cl::Black); 291$b->region($r); 292$b->translate(1,1); 293$b->bar(0,0,$b->size); 294is_bytes($b->data, 295 "\xff\xff\xff\xff". 296 "\xff\x00\xff\xff". 297 "\xff\xff\x00\x00". 298 "\xff\xff\x00\x00", 299 "region plot with offset 1" 300); 301 302$b->translate(0,0); 303render(undef); 304$b->translate(2,2); 305$b->color(cl::Black); 306$b->region($r); 307$b->bar(0,0,$b->size); 308is_bytes($b->data, 309 "\xff\xff\xff\xff". 310 "\xff\xff\xff\xff". 311 "\xff\xff\x00\x00". 312 "\xff\xff\x00\x00", 313 "region plot with offset 2" 314); 315 316$b->translate(0,0); 317render(undef); 318$b->translate(5,5); 319$b->color(cl::Black); 320$b->region($r); 321$b->bar(0,0,$b->size); 322is( $b->sum, 16 * 255, "region outside left"); 323$b->translate(-5,-5); 324is( $b->sum, 16 * 255, "region outside right"); 325 326my $i = Prima::Image->new( size => [32, 32], type => im::Byte); 327$i->color(0); 328$i->bar(0,0,$i->size); 329my $j = $i->dup; 330$j->color(cl::White); 331$j->bar(0,0,$j->size); 332$r = Prima::Region->new( polygon => [0, 0, 10, 25, 25, 0, 0, 15, 25, 15]); 333$i->region($r); 334$i->put_image(0,0,$j); 335 336my $xr = $r->image(type => im::Byte, size => [32, 32], backColor => 0, color => cl::White); 337is( $i->data, $xr->data, 'put_image(region) == region.image'); 338 339$i = Prima::Icon->new( size => [32, 32], type => im::Byte, maskType => im::bpp8, autoMasking => am::None); 340$i->color(0); 341$i->bar(0,0,$i->size); 342$j = Prima::Icon->new( size => [32, 32], type => im::Byte, maskType => im::bpp8, autoMasking => am::None); 343$j->color(cl::White); 344$j->bar(0,0,$j->size); 345$j->mask( "\xff" x length($i->mask)); 346$i->region($r); 347$i->put_image(0,0,$j,rop::SrcOver); 348is( $i->data, $xr->data, 'put_image(region).rgb == region.image'); 349is( $i->mask, $xr->data, 'put_image(region).a8 == region.image'); 350 351done_testing; 352