0

ファイルを読み込んで画像に変換しようとしています。このファイル形式は Infernal Machine MAT と呼ばれ、ゲーム Star Wars Jedi Knight Dark Forces 2 のテクスチャに使用されます。ファイルには、8 ビットと 16 ビットの 2 つの色深度があります。これらは、さまざまなヘッダーとパレット情報がないことを除いて、ほとんどビットマップ イメージです。

Infernal Machine MAT に関する仕様は、Google で「Jedi Knight Unofficial Specs Millennium」および「JK Hub mat2」と入力すると見つかります。

さて、私は最高のプログラマーではありませんが、ゆっくりとこのファイル形式を理解することができました。私はこのゲームを編集していくつかのテクスチャを作成し、自分のウェブサイトに表示するのがいいと思ったので、これを学びたかった. 私がそれらを表示したかった方法は、それらを側で PNG に変換するのではなく、直接ロードすることでした (たとえば、変更があった場合、MAT ファイルの両方をアップロードする必要はなく、別のファイルをアップロードすることを忘れないでください)。 PNG)。

しかし、私は少し引っ掛かりに遭遇したようです。私ができる最善の方法は、画像をピクセルごとにロード/変換することです。これには時間がかかり、大きな 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