return;
}
+
+sub _test_union {
+ my ($self, $rect) = (@_);
+ my ($x, $y, $w, $h);
+
+ $x = $self->x < $rect->x ? $self->x : $rect->x; # MIN
+ $y = $self->y < $rect->y ? $self->y : $rect->y; # MIN
+
+ $w = ($self->x + $self->w) > ($rect->x + $rect->w)
+ ? ($self->x + $self->w) - $x
+ : ($rect->x + $rect->w) - $x
+ ; # MAX
+
+ $h = ($self->y + $self->h) > ($rect->y + $rect->h)
+ ? ($self->y + $self->h) - $y
+ : ($rect->y + $rect->h) - $y
+ ; # MAX
+
+ return ($x, $y, $w, $h);
+}
+
+sub union {
+ my ($self, $rect) = (@_);
+
+ unless ($rect->isa('SDL::Rect')) {
+ croak "must receive an SDL::Rect-based object";
+ }
+
+ my ($x, $y, $w, $h) = _test_union($self, $rect);
+ return $self->new($x, $y, $w, $h);
+}
+
+sub union_ip {
+ my ($self, $rect) = (@_);
+
+ unless ($rect->isa('SDL::Rect')) {
+ croak "must receive an SDL::Rect-based object";
+ }
+
+ my ($x, $y, $w, $h) = _test_union($self, $rect);
+
+ $self->x($x);
+ $self->y($y);
+ $self->w($w);
+ $self->y($h);
+
+ return;
+}
+
+sub _test_unionall {
+ my ($self, $rects) = (@_);
+
+ # initial values for union rect
+ my $left = $self->x;
+ my $top = $self->y;
+ my $right = $self->x + $self->w;
+ my $bottom = $self->y + $self->h;
+
+ foreach my $rect (@{$rects}) {
+ unless ($rect->isa('SDL::Rect')) {
+ # TODO: better error message, maybe saying which item
+ # is the bad one (by list position)
+ croak "must receive an array reference of SDL::Rect-based objects";
+ }
+
+ $left = $rect->x if $rect->x < $left; # MIN
+ $top = $rect->y if $rect->y < $top; # MIN
+ $right = ($rect->x + $rect->w) if ($rect->x + $rect->w) > $right; # MAX
+ $bottom = ($rect->y + $rect->h) if ($rect->y + $rect->h) > $bottom; # MAX
+ }
+
+ return ($left, $top, $right - $left, $bottom - $top);
+}
+
+sub unionall {
+ my ($self, $rects) = (@_);
+
+ croak "must receive an array reference of SDL::Rect-based objects"
+ unless defined $rects and ref $rects eq 'ARRAY';
+
+ my ($x, $y, $w, $h) = _test_unionall($self, $rects);
+
+ return $self->new($x, $y, $w, $h);
+}
+
+sub unionall_ip {
+ my ($self, $rects) = (@_);
+
+ croak "must receive an array reference of SDL::Rect-based objects"
+ unless defined $rects and ref $rects eq 'ARRAY';
+
+ my ($x, $y, $w, $h) = _test_unionall($self, $rects);
+
+ $self->x($x);
+ $self->y($y);
+ $self->w($w);
+ $self->h($h);
+
+ return;
+}
+
+sub _check_fit {
+ my ($self, $rect) = (@_);
+
+ my $x_ratio = $self->w / $rect->w;
+ my $y_ratio = $self->h / $rect->h;
+ my $max_ratio = ($x_ratio > $y_ratio) ? $x_ratio : $y_ratio;
+
+ my $w = int ($self->w / $max_ratio);
+ my $h = int ($self->h / $max_ratio);
+
+ my $x = $rect->x + int (($rect->w - $w) / 2);
+ my $y = $rect->y + int (($rect->h - $h) / 2);
+
+ return ($x, $y, $w, $h);
+}
+
+sub fit {
+ my ($self, $rect) = (@_);
+
+ unless ($rect->isa('SDL::Rect')) {
+ croak "must receive an SDL::Rect-based object";
+ }
+
+ my ($x, $y, $w, $h) = _check_fit($self, $rect);
+
+ return $self->new ($x, $y, $w, $h);
+}
+
+sub fit_ip {
+ my ($self, $rect) = (@_);
+
+ unless ($rect->isa('SDL::Rect')) {
+ croak "must receive an SDL::Rect-based object";
+ }
+
+ my ($x, $y, $w, $h) = _check_fit($self, $rect);
+
+ $self->x($x);
+ $self->y($y);
+ $self->w($w);
+ $self->h($h);
+
+ return;
+}
+
+sub normalize {
+ my $self = shift;
+
+ if ($self->w < 0) {
+ $self->x($self->x + $self->w);
+ $self->w(-$self->w);
+ }
+
+ if ($self->h < 0) {
+ $self->y( $self->y + $self->h);
+ $self->h(-$self->h);
+ }
+ return;
+}
+
+
42;
__END__