#!/usr/bin/perl

#- Build a message file for syslinux-graphic from a BMP file.
#- Copyright (C) 1999,200,2001 MandrakeSoft (pixel@mandrakesoft.com)
#-
#- This program is free software; you can redistribute it and/or modify
#- it under the terms of the GNU General Public License as published by
#- the Free Software Foundation; either version 2, or (at your option)
#- any later version.
#-
#- This program is distributed in the hope that it will be useful,
#- but WITHOUT ANY WARRANTY; without even the implied warranty of
#- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#- GNU General Public License for more details.
#-
#- You should have received a copy of the GNU General Public License
#- along with this program; if not, write to the Free Software
#- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

#- usage:
#-   bmp2mdk <picture.bmp >picture.msg
#- NB: the input image (colormap indexed) should not have more than 128 colors
#- and should not be compressed.

#- additional modification, to include some escape sequence for the picture
#- commented as follow:
#-   mode:value                   - VESA mode to use, assume graphic if > 0x100,
#-				    default is 0x101 (ie 640x480 in 256 colors).
#-   timer:y,x,bg,fg              - timer position and colors (for LILO only).
#-   entry:y,x,bg,fg,h_chr,w_chr  - entry position, colors and size in chars
#-				    (for LILO only).
#-   progress:y,x,h,w,c           - progress bar position, size (h and w in byte
#-				    only) and color (for SYSLINUX only).
#-   clear:h,w,c                  - clear before with color c, default is clear
#-				    640x480 in color 0 (black).
#- no options assume no addition initcode given.
#- colors given in the range 0x40 and 0xBF are from picture palette used (shifted).

use strict;

my $initcode_str;
my %initcode = ( #- this default are running quite nicely with first english LILO image.
		mode        => 0x101,
		timer_y     => 0,
		timer_x     => 0,
		timer_bg    => 0x00,
		timer_fg    => 0x0f,
		entry_y     => 0,
		entry_x     => 0,
		entry_bg    => 0x00,
		entry_fg    => 0x0f,
		entry_h_chr => 24,
		entry_w_chr => 22,
	        progress_y  => 0,
                progress_x  => 0,
	        progress_h  => 8,
		progress_w  => 32,
		progress_c  => 0x01,
		clear_w     => 640,
		clear_h     => 480,
		clear_color => 0,
		pos_y       => 0,
		pos_x       => 0,
	       );
foreach (@ARGV) {
    /^mode:(.*)/  and do { @initcode{qw(mode)} = map { eval "$_" } split /,/, $1; next };
    /^timer:(.*)/ and do { @initcode{qw(timer_y timer_x timer_bg timer_fg)} = map { eval "$_" } split /,/, $1; next };
    /^entry:(.*)/ and do { @initcode{qw(entry_y entry_x entry_bg entry_fg entry_h_chr entry_w_chr)} = map { eval "$_" } split /,/, $1; next };
    /^progress:(.*)/ and do { @initcode{qw(progress_y progress_x progress_h progress_w progress_c)} = map { eval "$_" } split /,/, $1; next };
    /^clear:(.*)/ and do { @initcode{qw(clear_h clear_w clear_color)} = map { eval "$_" } split /,/, $1; next };
    /^pos:(.*)/   and do { @initcode{qw(pos_y pos_x)} = map { eval "$_" } split /,/, $1; next };
    /^initcode$/  and next;
    die "usage: bmp2mdk [options]
where [options] are taken from the following list:
   mode:value                   - VESA mode to use, assume graphic if > 0x100,
                                  default is 0x101 (ie 640x480 in 256 colors).
   timer:y,x,bg,fg              - timer position and colors (for LILO only).
   entry:y,x,bg,fg,h_chr,w_chr  - entry position, colors and size in chars
                                  (for LILO only).
   progress:y,x,h,w,c           - progress bar position, size (h and w in byte
                                  only) and color (for SYSLINUX only).
   clear:h,w,c                  - clear before with color c, default is clear
                                  640x480 in color 0 (black).
   pos:y,x                      - set x,y for next pixmap, default is to (0,0).
no options assume no addition initcode given.
colors given in the range 0x40 and 0xBF are from picture palette used (shifted).
input image should be a 128 colors uncompressed BMP file.

unknown option [$_]\n";
}
if (@ARGV) {
    my ($ext_code, $ext_data) = (0x00, '');

    if ($initcode{mode}) {
	$ext_code |= 0x80;
	$ext_data .= pack "v", $initcode{mode};
    }
    if ($initcode{progress_y} || $initcode{progress_x}) {
	$ext_code |= 0x20;
	$ext_data .= pack "v2C3", @initcode{qw(progress_y progress_x progress_h progress_w progress_c)};
    }
    if ($initcode{timer_y} || $initcode{timer_x} || $initcode{entry_y} || $initcode{entry_x}) {
	$ext_code |= 0x08;
	$ext_data .= pack "v2C2 v2C4", @initcode{qw(timer_y timer_x timer_bg timer_fg
						    entry_y entry_x entry_bg entry_fg entry_h_chr entry_w_chr)};
    }
    #- always set up clear.
    $ext_code |= 0x02;
    $ext_data .= pack "v2C", @initcode{qw(clear_w clear_h clear_color)};

    print "\x0e";
    print pack "C", $ext_code;
    print $ext_data;

    #- always set up pos too but in separate coded.
    print "\x0e\x10";
    print pack "v2", @initcode{qw(pos_y pos_x)};
}

undef $/;
my $f = <STDIN>;

my ($width, $height, $nbcolors) = unpack "x18 V V x20 V", $f;

my $s = $nbcolors * 4;
my ($palette, $image) = unpack "x54 a$s a*", $f;
my @palette = unpack("C3x" x $nbcolors, $palette);

for (my $i = 0; $i < 3 * $nbcolors; $i += 3) {
    ($palette[$i], $palette[$i + 2]) = ($palette[$i + 2], $palette[$i]);
}

print "\x0e\x04";
print pack "v v C C" . "C3" x $nbcolors, $width, $height, $nbcolors, 0, @palette;

my $width_ = 4 * int (($width + 3) / 4);
my ($oldv, $nb) = (-1024, 0);

for (my $i = 0; $i < $height; $i++) {
    for (my $j = 0; $j < $width; $j++) {
	my $v = vec $image, ($height - $i - 1) * $width_+ $j, 8;
	$v >= 128 and die "cannot use more than 128 colors in input file\n";

	if ($v == $oldv) {
	    $nb++;
	} else {
	    while ($nb > 129) {
		print pack "C", 0xFF;
		$nb -= 129;
	    }
	    if ($nb > 1) { #- necessary <= 129 here
		print pack "C", (0x80 | ($nb - 2));
	    } elsif ($nb == 1) {
		print pack "C", $oldv;
	    }
	    print pack "C", $v;
	    $oldv = $v;
	    $nb = 0;
	}
    }
}
while ($nb > 129) {
    print pack "C", 0xFF;
    $nb -= 129;
}
if ($nb > 1) { #- necessary <= 129 here
    print pack "C", (0x80 | ($nb - 2));
} elsif ($nb == 1) {
    print pack "C", $oldv;
}

1;
