0

我正在尝试加载文件并将其转换为图像。该文件格式称为 Infernal Machine MAT,用于《星球大战绝地武士黑暗力量 2》游戏中的纹理。该文件有 2 种颜色深度,8 位和 16 位。它们几乎是位图图像,只是它们缺少各种标题和调色板信息。

有关 Infernal Machine MAT 的规格可以在 Google 中输入:“Jedi Knight Unofficial Specs Millennium”和“JK Hub mat2”。

现在,我不是最好的程序员,但慢慢地我设法理解了这种文件格式。我想学习这个,因为我编辑了这个游戏并为它创建了一些纹理,并认为将它们显示在我的网站上会很好。我想要显示它们的方式不是将它们转换为侧面的 PNG,而是直接加载它们(例如,如果有更改,我不必同时上传 MAT 文件并记住上传另一个巴布亚新几内亚)。

但是,我似乎遇到了一些障碍。我能做的最好的事情是逐个像素地加载/转换图像,这在大型 MAT 文件上既耗时又超时。我尝试将数据直接作为 imagecreatefromstring() 输入,但失败了(我猜是因为缺少调色板信息)。有没有一种方法可以加快进程而不是逐点进行?

我的代码如下所示:http ://www.edwardleuf.org/Games/JK/IM_MAT_Loader.zip

// Create our palette
$colormap=imagecreate(256,1);
for($i=0; $i<256; $i++)
{
    $color=imagecolorallocate($colormap,$cmpR[$i],$cmpG[$i],$cmpB[$i]);
    imagesetpixel($colormap,$i,0,$color);
}

// Read whole mat into one string.
$wholemat = "";
if($zipfile!="")
{
    $zip = zip_open($zipfile);
    if(is_resource($zip))
    {
        While ($zip_entry = zip_read($zip))
        {
            $zip_ename = zip_entry_name($zip_entry);
            if($matfile!="" && $zip_ename==$matfile)
            {
                $wholemat = zip_entry_read($zip_entry,zip_entry_filesize($zip_entry));
            }
            else if($matfile=="" && strtoupper(substr(strrchr($zip_ename,"."),1)) == "MAT")
            {
                $wholemat = zip_entry_read($zip_entry,zip_entry_filesize($zip_entry));
            }
        }
    }
    zip_close($zip);
}
else
{
    if($matfile!="")
    {
        $mat = fopen($matfile,'r');
        $wholemat = fread($mat,filesize($matfile));
        fclose($mat);
    }
}
if($wholemat=="" || substr($wholemat,0,5)!="MAT 2")
{    // If we weren't successful in procuring a proper MAT file
    // produce a 2x2 blank
    header('Content-type: image/png');
    $img = imagecreatetruecolor(2,2);
    imagepng($img,'',9);
    imagedestroy($img);
    return;
}

// Type: 0 = single color, 1 = ?, 2 = full texture
$u = unpack("L",substr($wholemat,8,4));
$matType = $u[1];

// Number of textures or colors
$u = unpack("L",substr($wholemat,12,4));
$matRecordCount = $u[1];

// If single color, it is 0. If full, same as RecordCount
$u = unpack("L",substr($wholemat,16,4));
$matTextureCount = $u[1];

// 8 or 16 bits
$u = unpack("L",substr($wholemat,24,4));
$matBitDepth = $u[1];

$u = unpack("L",substr($wholemat,28,4));
$matBlueBits = $u[1];    // 0, 5, 8
$u = unpack("L",substr($wholemat,32,4));
$matGreenBits = $u[1];    // 0, 6 (16-bit 565), 5 (16-bit 1555), 8
$u = unpack("L",substr($wholemat,36,4));
$matRedBits = $u[1];    // 0, 5, 8

// The shift offset for the location of the R, G and B color values
// in the bitmap data. The color data is extracted by shifting
// the opposite direction of these values.
$u = unpack("L",substr($wholemat,40,4));
$matRedShiftL = $u[1];        // 11 for RGB565, 10 for ARGB1555
$u = unpack("L",substr($wholemat,44,4));
$matGreenShiftL = $u[1];    // 5
$u = unpack("L",substr($wholemat,48,4));
$matBlueShiftL = $u[1];        // 0

// The amount to shift the extracted color values to expand them from
// 5 or 6 bit values to 8 bit values. Unsure if JK actually uses these.
$u = unpack("L",substr($wholemat,52,4));
$matRedShiftR = $u[1];        // 3
$u = unpack("L",substr($wholemat,56,4));
$matGreenShiftR = $u[1];    // 2
$u = unpack("L",substr($wholemat,60,4));
$matBlueShiftR = $u[1];        // 3
$u = unpack("L",substr($wholemat,80,4));
$matTransColor = $u[1];

if($matType==0)
{    // Single Color Mat
    if($matBitDepth==8)
    {
        $img = imagecreate(64*$matRecordCount,64) or die("Cannot Initialize new GD image stream");
        imagepalettecopy($img,$colormap);
    }
    else if($matBitDepth==16)
    {
        $img = imagecreatetruecolor(64*$matRecordCount,64) or die("Cannot Initialize new GD image stream");
    }
    for($i=0; $i<$matRecordCount; $i++)
    {
        $u = unpack("L",substr($wholemat,80+($i*24),4));
        if($matBitDepth==8)
        {
            $carray = imagecolorsforindex($img,$u[1]);
            $color = imagecolorclosest($img,$carray[red],$carray[green],$carray[blue]);
        }
        else if($matBitDepth==16)
        {
            $color = $u[1];
        }
        imagefilledrectangle($img,$i*64,0,$i*64+64,64,$color);
    }

}
else if($matType==2)
{    // Full Texture
    $starttex = intval(76+$matRecordCount*40);
    $u = unpack("L",substr($wholemat,$starttex,4));
    $matSizeX = $u[1];
    $u = unpack("L",substr($wholemat,$starttex+4,4));
    $matSizeY = $u[1];
    if($matBitDepth==8)
    {
        $img = imagecreate($matSizeX*$matRecordCount,$matSizeY) or die("Cannot Initialize new GD image stream");
        imagepalettecopy($img,$colormap);
    }
    else if($matBitDepth==16)
    {
        $img = imagecreatetruecolor($matSizeX*$matRecordCount,$matSizeY) or die("Cannot Initialize new GD image stream");
    }
    $matTransparency=0;
    for($i=0; $i<$matRecordCount; $i++)
    {    // Each animation cel can in theory have different sizes.
        $u = unpack("L",substr($wholemat,$starttex,4));
        $matSizeX = $u[1];
        $u = unpack("L",substr($wholemat,$starttex+4,4));
        $matSizeY = $u[1];
        if($matTransparency==0)
        {
            $u = unpack("L",substr($wholemat,$starttex+8,4));
            $matTransparency = $u[1];
        }
        $u = unpack("L",substr($wholemat,$starttex+20,4));
        $matMipMaps = $u[1];
        if($matBitDepth==8)
        {
            $strimg = substr($wholemat,($starttex+24),($matSizeX*$matSizeY));
        }
        else if($matBitDepth==16)
        {
            $strimg = substr($wholemat,($starttex+24),($matSizeX*$matSizeY*2));
        }
        $j=0;
        for($y=0; $y<$matSizeY; $y++)
        {
            for($x=$matSizeX*$i; $x<$matSizeX+$matSizeX*$i; $x++)
            {
                if($matBitDepth==8)
                {
                    $carray = imagecolorsforindex($img,ord(substr($strimg,$j,1)));
                    $color = imagecolorclosest($img,$carray[red],$carray[green],$carray[blue]);
                    $j=$j+1;
                }
                else if($matBitDepth==16)
                {
                    if(strlen(substr($strimg,$j,2))==2)
                    {
                        $u = unpack("S",substr($strimg,$j,2));
                        $xr = ($u[1] & 0xf800) >> 11;
                        $xg = ($u[1] & 0x07e0) >> 5;
                        $xb = $u[1] & 0x001f;
                        $br = pow(2,$matRedBits)-1;
                        $bg = pow(2,$matGreenBits)-1;
                        $bb = pow(2,$matBlueBits)-1;
                        if($br>0) $nr = 255/$br * $xr; else $nr = $xr*8;
                        if($bg>0) $ng = 255/$bg * $xg; else $ng = $xg*4;
                        if($bb>0) $nb = 255/$bb * $xb; else $nb = $xb*8;
                        $color = imagecolorallocate($img,$nr,$ng,$nb);
                    //    echo $nr."\t".$ng."\t".$nb."\n";
                        $j=$j+2;
                    }
                }
                imagesetpixel($img,$x,$y,$color);
            }
        }
        // Jump over MipMaps...
        if($matMipMaps>1)
        {
            $j=$j+(($matSizeX/2)*($matSizeY/2));
            if($matMipMaps>2)
            {
                $j=$j+(($matSizeX/4)*($matSizeY/4));
                if($matMipMaps>3)
                {
                    $j=$j+(($matSizeX/8)*($matSizeY/8));
                }
            }
        }
        $starttex=$starttex+$j+24;
    }

}

if($matBitDepth==8)
{
    if($matTransparency!=0)
    {
        /* Not sure about Transparency Information.
           According to sources, this should be the index to mask out,
           but when looking at 08tgrate.mat it says index 85
           which is not the black that should be transparent.

        $carray = imagecolorsforindex($img,$matTransColor);
        $color = imagecolorclosest($img,$carray[red],$carray[green],$carray[blue]);

           Does JK ignore this completely? */

        $color = imagecolorclosest($img,0,0,0);
        imagecolortransparent($img,$color);
    }
}
else if($matBitDepth==16)
{
    if($matTransparency!=0)
    {
        imagecolortransparent($img,$matTransColor);
    }
}

if($thumbW!=0 && $thumbH!=0)
{
    $newwidth=$thumbW;
    $newheight=(imagesy($img)/imagesx($img))*$newwidth;
    if($newheight>$thumbH)
    {
        $newheight=$thumbH;
        $newwidth=(imagesx($img)/imagesy($img))*$newheight;
    }
    $tmp=imagecreatetruecolor($newwidth,$newheight);
    imagecopyresampled($tmp,$img,0,0,0,0,$newwidth,$newheight,imagesx($img),imagesy($img));
    header('Content-type: image/png');
    imagejpeg($tmp,'',50);
    imagedestroy($tmp);
}
else
{
    header('Content-type: image/png');
    imagepng($img,'',9);
}
imagedestroy($img);
imagedestroy($colormap);
unset($wholemat);

这是使用它的网站:http ://www.edwardleuf.org/Games/JK/MATs/

/爱德华

4

0 回答 0