package Data::StarCraft::Tileset;

use strict;
use warnings;
use Data::Dumper;

use List::Util qw(sum);

our $VERSION = '0.10';

sub open {
	my ($class, $filename) = @_;
	my $self = bless {}, $class;
	open my $groupfile, '<', "$filename.cv5" or return;
	$self->readgroups($groupfile);
	if (open my $groupfile, '<', "$filename.vx4") {
		$self->readvx4($groupfile);
	}
	if (open my $groupfile, '<', "$filename.vf4") {
		$self->readvf4($groupfile);
	}
	if (open my $groupfile, '<', "$filename.vr4") {
		$self->readvr4($groupfile);
	}
	if (open my $groupfile, '<', "$filename.wpe") {
		$self->readwpe($groupfile);
	}
	return $self;
}

sub _read {
	my $self = shift;
	my ($fh, $size, $seek) = @_;

	seek $fh, $seek, 0 if $seek;
	read($fh, my $in, $size) eq $size or return undef;
	return $in;
}

sub readwpe {
	my $self = shift;
	my ($fh) = @_;

	# wpe = palette
	while (defined (my $line = $self->_read($fh, 4))) {
		push @{ $self->{palette} }, [ unpack 'CCCX', $line ];
	}
	return;
}

sub readvx4 {
	my $self = shift;
	my ($fh) = @_;

	# vx4 = minitile map (4x4 references per megatile)
	while (defined (my $line = $self->_read($fh, 16*2))) {
		push @{ $self->{tileref} }, [ unpack 'v*', $line ];
	}
	return;
}

sub readvr4 {
	my $self = shift;
	my ($fh) = @_;

	# vr4 = minitile sprites
	while (defined (my $line = $self->_read($fh, 8**2))) {
		push @{ $self->{minibmp} }, [ unpack 'C*', $line ];
	}
	return;
}

sub readvf4 {
	my $self = shift;
	my ($fh) = @_;

	# vf4 = minitile type
	while (defined (my $line = $self->_read($fh, 2))) {
		push @{ $self->{minitype} }, unpack 'v', $line;
	}
	return;
}

sub col {
	my $self = shift;
	my ($minitile) = @_;

	return $self->{bmp}->[$minitile] if defined $self->{bmp}->[$minitile];

	my $pixels = $self->{minibmp}->[$minitile];
	my $pal = $self->{palette};

	my @rgb;
	for my $color (@$pixels) {
#		$rgb[$_] += $self->{palette}->[$color]->[$_] for 0 .. 2;
#			# ^ wow, this is really slow
		$rgb[0] += $pal->[$color]->[0];
		$rgb[1] += $pal->[$color]->[1];
		$rgb[2] += $pal->[$color]->[2];
	}
	return $self->{bmp}->[$minitile] = [map {$_ >> 6} @rgb];
}

=head2 col

Average color [r,g,b] for minitile.

For example, using the Jungle tileset:

	$t->col(719)

is a water minitile, giving a blue color C<[38, 38, 57]>.

=cut

sub sprite {
	my $self = shift;
	my ($id) = @_;

	my $minitiles = $self->{tileref}->[$id];
	my @pix;
	for my $tiley (0 .. 3) {
		for my $y (0 .. 7) {
			for my $tilex (0 .. 3) {
				# minitile number is half of tileref
				# if odd, the minitile is mirrored
				my $minitile = $minitiles->[$tilex + $tiley*4];

				for my $x ($minitile & 1 ? (reverse 0 .. 7) : (0 .. 7)) {
					push @pix, $self->{minibmp}->[$minitile >> 1]->[$x + $y*8];
				}
			}
		}
	}
	return \@pix;
}

=head2 sprite

Returns bitmap of an entire tile, as 32x32 color indexes.

For example, the green value of the bottom center pixel of tile #1 would be:

	$t->{palette}->[ $t->sprite(1)->[31*32 + 15] ]->[2]

=cut

sub tile {
	my $self = shift;
	my ($id) = @_;

	my $tile = $self->{map}->[$id];
	my $minitiles = $self->{tileref}->[$tile] || [];
	return {
		id => $tile,
		group   => $self->{group}->[$id >> 4],
#		subtype => [ map { $self->{minitype}->[$_] } @$minitiles ],
		subtype => [ map { $self->{minitype}->[$_] } $tile*16 .. $tile*16+15 ],
		subcol  => [ map { $self->col($_ >> 1) } @$minitiles ],
#		sprite  => $self->sprite($tile),
	};
}

sub tileavg {
	my $self = shift;
	my $tile = $self->tile(shift);

	my $info = $tile->{group};
	$info->{walk} = sum(@{ $tile->{subtype} }) >> 4;
	my @rgb;
	for my $subcol (@{ $tile->{subcol} }) {
		$rgb[0] += $subcol->[0];
		$rgb[1] += $subcol->[1]; # seperate for speed
		$rgb[2] += $subcol->[2];
	}
	$info->{col} = [ map {$_ >> 4} @rgb ];
	return $info;
}

=head2 tile

Tile details. For example a water tile:

	$t->tile(96)

would give:

	group => {
		walk   => 0,
		height => 0,
		build  => 128,
	},
	subtype => [ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1 ],
	subcol => [
		[39,40,59], [38,39,57], [40,41,60], [36,37,55],
		[37,38,56], [39,40,60], [38,39,57], [40,41,61],
		[37,38,56], [41,41,61], [40,40,60], [36,36,54],
		[36,36,54], [37,37,55], [35,35,53], [38,38,57]
	],

=cut

sub readgroups {
	my $self = shift;
	my ($fh) = @_;

	# cv5 = tile groups
	my @tilemap;
	while (defined (my $line = $self->_read($fh, 52))) {
		my @data = unpack "vCC v24", $line;
		my %row = (
			build => $data[1] & 0xF0,
			height => $data[2] & 0xF,
#			rawdata => [@data[0..10]],
		);
		push @{ $self->{group} }, \%row;
		push @{ $self->{map} }, $_ for @data[11..26];
	}
	return;
	# index (ground_height unknown4 buildable unknown3) u6 u7 u8 u9 u10 u11 u12 u13
	# 1 (ground_height unknown4 buildable unknown3) 35 0 doodad_group 0 58 6 6 0
}

1;

