mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-23 13:45:34 +08:00
implemented image format used in Softpal archives (VAFSH).
This commit is contained in:
parent
00f4fd6e23
commit
9b6c4ddff0
@ -111,6 +111,7 @@
|
||||
<Compile Include="Silky\ImageAKB.cs" />
|
||||
<Compile Include="Softpal\ArcVAFS.cs" />
|
||||
<Compile Include="Softpal\ImageBPIC.cs" />
|
||||
<Compile Include="Softpal\ImagePIC.cs" />
|
||||
<Compile Include="StudioEgo\ArcPAK0.cs" />
|
||||
<Compile Include="StudioEgo\ImageANT.cs" />
|
||||
<Compile Include="TechnoBrain\ImageIPH.cs" />
|
||||
|
@ -41,7 +41,7 @@ namespace GameRes.Formats.Softpal
|
||||
|
||||
public VafsOpener ()
|
||||
{
|
||||
Extensions = new string[] { "052" };
|
||||
Extensions = new string[] { "052", "055" };
|
||||
}
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
@ -59,14 +59,26 @@ namespace GameRes.Formats.Softpal
|
||||
uint next_offset = data_offset;
|
||||
var base_name = Path.GetFileNameWithoutExtension (file.Name).ToUpperInvariant();
|
||||
bool is_audio = "BGM" == base_name;
|
||||
bool is_pic = "PIC" == base_name;
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; next_offset != 0 && next_offset != file.MaxOffset && i < count; ++i)
|
||||
{
|
||||
index_offset += 4;
|
||||
var name = string.Format("{0}#{1:D5}", base_name, i);
|
||||
var entry = AutoEntry.Create (file, next_offset, name);
|
||||
var offset = next_offset;
|
||||
next_offset = index_offset == data_offset ? 0 : file.View.ReadUInt32 (index_offset);
|
||||
entry.Size = (uint)((0 != next_offset ? (long)next_offset : file.MaxOffset) - entry.Offset);
|
||||
uint size = (uint)((0 != next_offset ? (long)next_offset : file.MaxOffset) - offset);
|
||||
Entry entry;
|
||||
if (size <= 4)
|
||||
entry = new Entry { Name = name, Offset = offset };
|
||||
else if (is_pic)
|
||||
entry = new Entry { Name = name, Type = "image", Offset = offset };
|
||||
else if (is_audio)
|
||||
entry = new Entry { Name = name + ".wav", Type = "audio", Offset = offset };
|
||||
else
|
||||
entry = AutoEntry.Create (file, offset, name);
|
||||
|
||||
entry.Size = size;
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
|
@ -43,7 +43,7 @@ namespace GameRes.Formats.Softpal
|
||||
if (header.Length != stream.Read (header, 0, header.Length))
|
||||
return null;
|
||||
int pixel_size = LittleEndian.ToInt32 (header, 12);
|
||||
if (pixel_size != 3 && pixel_size != 4)
|
||||
if (pixel_size != 4 && pixel_size != 3 && pixel_size != 1)
|
||||
return null;
|
||||
return new ImageMetaData
|
||||
{
|
||||
@ -60,13 +60,17 @@ namespace GameRes.Formats.Softpal
|
||||
var pixels = new byte[(int)info.Width * (int)info.Height * pixel_size];
|
||||
if (pixels.Length != stream.Read (pixels, 0, pixels.Length))
|
||||
throw new EndOfStreamException();
|
||||
for (int i = 2; i < pixels.Length; i += pixel_size)
|
||||
if (pixel_size > 1)
|
||||
{
|
||||
byte t = pixels[i];
|
||||
pixels[i] = pixels[i-2];
|
||||
pixels[i-2] = t;
|
||||
for (int i = 2; i < pixels.Length; i += pixel_size)
|
||||
{
|
||||
byte t = pixels[i];
|
||||
pixels[i] = pixels[i-2];
|
||||
pixels[i-2] = t;
|
||||
}
|
||||
}
|
||||
PixelFormat format = 24 == info.BPP ? PixelFormats.Bgr24 : PixelFormats.Bgr32;
|
||||
PixelFormat format = 24 == info.BPP ? PixelFormats.Bgr24 :
|
||||
8 == info.BPP ? PixelFormats.Gray8 : PixelFormats.Bgra32;
|
||||
return ImageData.Create (info, format, null, pixels);
|
||||
}
|
||||
|
||||
|
425
ArcFormats/Softpal/ImagePIC.cs
Normal file
425
ArcFormats/Softpal/ImagePIC.cs
Normal file
@ -0,0 +1,425 @@
|
||||
//! \file ImagePIC.cs
|
||||
//! \date Sun Jan 24 18:48:25 2016
|
||||
//! \brief Softpal engine image format.
|
||||
//
|
||||
// Copyright (C) 2016 by morkt
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Windows.Media;
|
||||
using GameRes.Utility;
|
||||
|
||||
namespace GameRes.Formats.Softpal
|
||||
{
|
||||
internal class PicMetaData : ImageMetaData
|
||||
{
|
||||
public int BlocksWidth;
|
||||
public int BlocksHeight;
|
||||
}
|
||||
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class PicFormat : ImageFormat
|
||||
{
|
||||
public override string Tag { get { return "PIC/SOFTPAL"; } }
|
||||
public override string Description { get { return "Softpal engine image format"; } }
|
||||
public override uint Signature { get { return 0; } }
|
||||
|
||||
public PicFormat ()
|
||||
{
|
||||
Extensions = new string[] { "pic", "" };
|
||||
}
|
||||
|
||||
public override ImageMetaData ReadMetaData (Stream stream)
|
||||
{
|
||||
var header = new byte[8];
|
||||
if (header.Length != stream.Read (header, 0, header.Length))
|
||||
return null;
|
||||
int bpp = LittleEndian.ToInt16 (header, 0);
|
||||
if (1 != bpp && 3 != bpp && 4 != bpp)
|
||||
return null;
|
||||
uint width = LittleEndian.ToUInt16 (header, 2);
|
||||
uint height = LittleEndian.ToUInt16 (header, 4);
|
||||
if (0 == width || 0 == height || header[6]*8 < width || header[7]*8 < height)
|
||||
return null;
|
||||
return new PicMetaData
|
||||
{
|
||||
Width = width,
|
||||
Height = height,
|
||||
BPP = bpp * 8,
|
||||
BlocksWidth = header[6],
|
||||
BlocksHeight = header[7],
|
||||
};
|
||||
}
|
||||
|
||||
public override ImageData Read (Stream stream, ImageMetaData info)
|
||||
{
|
||||
var meta = (PicMetaData)info;
|
||||
using (var reader = new PicReader (stream, meta))
|
||||
{
|
||||
reader.Unpack();
|
||||
return ImageData.Create (info, reader.Format, null, reader.Data);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("PicFormat.Write not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class PicReader : IDisposable
|
||||
{
|
||||
BinaryReader m_input;
|
||||
byte[] m_output;
|
||||
PicMetaData m_info;
|
||||
byte[] m_control;
|
||||
int m_src_stride;
|
||||
|
||||
public PixelFormat Format { get; private set; }
|
||||
public byte[] Data { get { return m_output; } }
|
||||
|
||||
readonly byte[] Values2bit = InitBlockValues (2);
|
||||
readonly byte[] Values4bit = InitBlockValues (8);
|
||||
readonly byte[] Values6bit = InitBlockValues (0x20);
|
||||
|
||||
public PicReader (Stream input, PicMetaData info)
|
||||
{
|
||||
m_input = new ArcView.Reader (input);
|
||||
m_info = info;
|
||||
m_src_stride = m_info.BlocksWidth * m_info.BPP;
|
||||
}
|
||||
|
||||
static byte[] InitBlockValues (int length)
|
||||
{
|
||||
var values = new byte[length*2];
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
values[i] = (byte)i;
|
||||
values[values.Length-1-i] = (byte)(-1-i);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
public void Unpack ()
|
||||
{
|
||||
m_input.BaseStream.Position = 8;
|
||||
m_control = m_input.ReadBytes (m_info.BlocksHeight * m_info.BlocksWidth);
|
||||
m_output = new byte[m_src_stride * m_info.BlocksHeight * 8];
|
||||
if (8 == m_info.BPP)
|
||||
{
|
||||
Format = PixelFormats.Gray8;
|
||||
Unpack8bpp();
|
||||
}
|
||||
else if (24 == m_info.BPP)
|
||||
{
|
||||
Format = PixelFormats.Bgr24;
|
||||
Unpack24bpp();
|
||||
}
|
||||
else if (32 == m_info.BPP)
|
||||
{
|
||||
Format = PixelFormats.Bgra32;
|
||||
Unpack32bpp();
|
||||
}
|
||||
else
|
||||
throw new InvalidFormatException();
|
||||
|
||||
int dst_stride = (int)m_info.Width * m_info.BPP / 8;
|
||||
byte[] flipped = new byte[dst_stride*(int)m_info.Height];
|
||||
int dst = 0;
|
||||
int src = m_output.Length - m_src_stride;
|
||||
while (dst < flipped.Length)
|
||||
{
|
||||
Buffer.BlockCopy (m_output, src, flipped, dst, dst_stride);
|
||||
dst += dst_stride;
|
||||
src -= m_src_stride;
|
||||
}
|
||||
m_output = flipped;
|
||||
}
|
||||
|
||||
void Unpack24bpp()
|
||||
{
|
||||
int pixel_size = 3;
|
||||
var pixel = new byte[4];
|
||||
var block = new byte[64];
|
||||
for (int y = 0; y < m_info.BlocksHeight; ++y)
|
||||
{
|
||||
for (int x = 0; x < m_info.BlocksWidth; ++x)
|
||||
{
|
||||
byte ctl = m_control[x + m_info.BlocksWidth * (m_info.BlocksHeight - y - 1)];
|
||||
if (0x80 == ctl)
|
||||
{
|
||||
int dst = pixel_size * 8 * (x + 8 * y * m_info.BlocksWidth);
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
for (int j = 0; j < 24; ++j)
|
||||
m_output[dst+j] = 0;
|
||||
dst += m_src_stride;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_input.Read (pixel, 0, pixel_size);
|
||||
for (int channel = 0; channel < pixel_size; ++channel)
|
||||
{
|
||||
DecodeBlock (ctl & 3, pixel[channel], block);
|
||||
int dst = pixel_size * 8 * (x + 8 * y * m_info.BlocksWidth) + channel;
|
||||
int src = 0;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
m_output[dst] = block[src++];
|
||||
m_output[dst+3] = block[src++];
|
||||
m_output[dst+6] = block[src++];
|
||||
m_output[dst+9] = block[src++];
|
||||
m_output[dst+12] = block[src++];
|
||||
m_output[dst+15] = block[src++];
|
||||
m_output[dst+18] = block[src++];
|
||||
m_output[dst+21] = block[src++];
|
||||
dst += m_src_stride;
|
||||
}
|
||||
ctl >>= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Unpack32bpp()
|
||||
{
|
||||
int pixel_size = 4;
|
||||
var pixel = new byte[4];
|
||||
var block = new byte[64];
|
||||
for (int y = 0; y < m_info.BlocksHeight; ++y)
|
||||
{
|
||||
for (int x = 0; x < m_info.BlocksWidth; ++x)
|
||||
{
|
||||
byte ctl = m_control[x + m_info.BlocksWidth * (m_info.BlocksHeight - y - 1)];
|
||||
m_input.Read (pixel, 0, pixel_size);
|
||||
for (int channel = 0; channel < pixel_size; ++channel)
|
||||
{
|
||||
DecodeBlock (ctl & 3, pixel[channel], block);
|
||||
int dst = 8 * pixel_size * (x + 8 * y * m_info.BlocksWidth) + ChannelOrder[channel];
|
||||
int src = 0;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
m_output[dst] = block[src++];
|
||||
m_output[dst+4] = block[src++];
|
||||
m_output[dst+8] = block[src++];
|
||||
m_output[dst+12] = block[src++];
|
||||
m_output[dst+16] = block[src++];
|
||||
m_output[dst+20] = block[src++];
|
||||
m_output[dst+24] = block[src++];
|
||||
m_output[dst+28] = block[src++];
|
||||
dst += m_src_stride;
|
||||
}
|
||||
ctl >>= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static readonly byte[] ChannelOrder = { 3, 0, 1, 2 };
|
||||
|
||||
void Unpack8bpp()
|
||||
{
|
||||
var block = new byte[64];
|
||||
for (int y = 0; y < m_info.BlocksHeight; ++y)
|
||||
{
|
||||
for (int x = 0; x < m_info.BlocksWidth; ++x)
|
||||
{
|
||||
byte ctl = m_control[x + m_info.BlocksWidth * (m_info.BlocksHeight - y - 1)];
|
||||
if (0x80 == ctl)
|
||||
{
|
||||
for (int i = 0; i < block.Length; ++i)
|
||||
block[i] = 0;
|
||||
}
|
||||
else if (0x81 == ctl)
|
||||
{
|
||||
for (int i = 0; i < block.Length; ++i)
|
||||
block[i] = 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte pixel = m_input.ReadByte();
|
||||
DecodeBlock (ctl, pixel, block);
|
||||
}
|
||||
int dst = 8 * (x + 8 * y * m_info.BlocksWidth);
|
||||
int src = 0;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
m_output[dst] = block[src++];
|
||||
m_output[dst+1] = block[src++];
|
||||
m_output[dst+2] = block[src++];
|
||||
m_output[dst+3] = block[src++];
|
||||
m_output[dst+4] = block[src++];
|
||||
m_output[dst+5] = block[src++];
|
||||
m_output[dst+6] = block[src++];
|
||||
m_output[dst+7] = block[src++];
|
||||
dst += m_src_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DecodeBlock (int control, byte pixel, byte[] block)
|
||||
{
|
||||
int dst = 0;
|
||||
switch (control)
|
||||
{
|
||||
case 0:
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
int b = m_input.ReadByte();
|
||||
block[dst++] = Values2bit[b >> 6];
|
||||
block[dst++] = Values2bit[(b >> 4) & 3];
|
||||
block[dst++] = Values2bit[(b >> 2) & 3];
|
||||
block[dst++] = Values2bit[b & 3];
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
for (int i = 0; i < 32; ++i)
|
||||
{
|
||||
int b = m_input.ReadByte();
|
||||
block[dst++] = Values4bit[b >> 4];
|
||||
block[dst++] = Values4bit[b & 0xF];
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
int b1 = m_input.ReadByte();
|
||||
int b2 = m_input.ReadByte();
|
||||
int b3 = m_input.ReadByte();
|
||||
int b4 = (b3 >> 6) | ((b2 >> 4) & 0xC) | ((b1 >> 2) & 0x30);
|
||||
block[dst++] = Values6bit[b1 & 0x3F];
|
||||
block[dst++] = Values6bit[b2 & 0x3F];
|
||||
block[dst++] = Values6bit[b3 & 0x3F];
|
||||
block[dst++] = Values6bit[b4];
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (64 != m_input.Read (block, 0, 64))
|
||||
throw new EndOfStreamException();
|
||||
break;
|
||||
}
|
||||
int v32 = pixel + block[27];
|
||||
int v33 = v32 + block[26];
|
||||
block[27] = (byte)v32;
|
||||
block[26] = (byte)v33;
|
||||
block[25] += (byte)v33;
|
||||
block[24] += block[25];
|
||||
block[19] += (byte)v32;
|
||||
int v34 = v32 + block[18];
|
||||
int v35 = v34 + block[17];
|
||||
block[18] = (byte)v34;
|
||||
block[17] = (byte)v35;
|
||||
block[16] += (byte)v35;
|
||||
block[11] += block[19];
|
||||
block[10] += (byte)v34;
|
||||
int v36 = v34 + block[9];
|
||||
int v37 = v36 + block[8];
|
||||
block[9] = (byte)v36;
|
||||
block[8] = (byte)v37;
|
||||
block[3] += block[11];
|
||||
block[2] += block[10];
|
||||
block[1] += (byte)v36;
|
||||
block[0] += (byte)v36;
|
||||
int v39 = pixel + block[28];
|
||||
int v40 = v39 + block[29];
|
||||
block[28] = (byte)v39;
|
||||
block[29] = (byte)v40;
|
||||
block[30] += (byte)v40;
|
||||
block[31] += block[30];
|
||||
block[20] += (byte)v39;
|
||||
int v41 = v39 + block[21];
|
||||
int v42 = v41 + block[22];
|
||||
block[21] = (byte)v41;
|
||||
block[22] = (byte)v42;
|
||||
block[23] += (byte)v42;
|
||||
block[12] += block[20];
|
||||
block[13] += (byte)v41;
|
||||
int v43 = v41 + block[14];
|
||||
int v44 = v43 + block[15];
|
||||
block[14] = (byte)v43;
|
||||
block[15] = (byte)v44;
|
||||
block[4] += block[12];
|
||||
block[5] += block[13];
|
||||
block[6] += (byte)v43;
|
||||
block[7] += (byte)v43;
|
||||
int v46 = pixel + block[35];
|
||||
int v47 = v46 + block[34];
|
||||
block[35] = (byte)v46;
|
||||
block[34] = (byte)v47;
|
||||
block[33] += (byte)v47;
|
||||
block[32] += block[33];
|
||||
block[43] += (byte)v46;
|
||||
int v48 = v46 + block[42];
|
||||
int v49 = v48 + block[41];
|
||||
block[42] = (byte)v48;
|
||||
block[41] = (byte)v49;
|
||||
block[40] += (byte)v49;
|
||||
block[51] += block[43];
|
||||
block[50] += (byte)v48;
|
||||
int v50 = v48 + block[49];
|
||||
int v51 = v50 + block[48];
|
||||
block[49] = (byte)v50;
|
||||
block[48] = (byte)v51;
|
||||
block[59] += block[51];
|
||||
block[58] += block[50];
|
||||
block[57] += (byte)v50;
|
||||
block[56] += (byte)v50;
|
||||
int v53 = pixel + block[36];
|
||||
int v54 = v53 + block[37];
|
||||
block[36] = (byte)v53;
|
||||
block[37] = (byte)v54;
|
||||
block[38] += (byte)v54;
|
||||
block[39] += block[38];
|
||||
int v56 = v53 + block[45];
|
||||
int v57 = v56 + block[46];
|
||||
block[47] += (byte)v57;
|
||||
block[46] = (byte)v57;
|
||||
block[45] = (byte)v56;
|
||||
block[44] += (byte)v53;
|
||||
block[53] += (byte)v56;
|
||||
block[52] += block[44];
|
||||
int v58 = v56 + block[54];
|
||||
block[54] = (byte)v58;
|
||||
block[55] += (byte)v58;
|
||||
block[60] += block[52];
|
||||
block[61] += block[53];
|
||||
block[62] += (byte)v58;
|
||||
block[63] += (byte)v58;
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
bool _disposed = false;
|
||||
public void Dispose ()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
m_input.Dispose();
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -214,6 +214,7 @@ Ikusa Otome Valkyrie<br/>
|
||||
Onsoku Hishou Sonic Mercedes<br/>
|
||||
Sakura Machizaka Stories vol.1<br/>
|
||||
Sakura Machizaka Stories vol.2<br/>
|
||||
Shoujo Senki Soul Eater<br/>
|
||||
</td></tr>
|
||||
<tr class="odd"><td>*.prs</td><td><tt>YB</tt></td><td>No</td></tr>
|
||||
<tr class="odd"><td>*.way</td><td><tt>WADY</tt></td><td>No</td></tr>
|
||||
@ -642,6 +643,11 @@ Dokidoki Onee-san<br/>
|
||||
<tr><td>*.pcs</td><td><tt>PCCS</tt></td><td>No</td><td>C's ware</td><td>
|
||||
Mikan<br/>
|
||||
</td></tr>
|
||||
<tr class="odd"><td>*.052<br/>*.055</td><td><tt>VAFSH</tt></td><td>No</td><td rowspan="2">Softpal</td><td rowspan="2">
|
||||
Komorebi ni Yureru Tamashii no Koe<br/>
|
||||
Komokyun!! ~Heart ni Yureru Tamashi no Fandisc~<br/>
|
||||
</td></tr>
|
||||
<tr class="odd"><td>*</td><td><tt>BPIC</tt></td><td>No</td></tr>
|
||||
</table>
|
||||
<p><a name="note-1" class="footnote">1</a> Non-encrypted only</p>
|
||||
</body>
|
||||
|
Loading…
Reference in New Issue
Block a user