mirror of
https://github.com/crskycode/GARbro.git
synced 2024-12-24 20:04:13 +08:00
implemented D.O.'s VRS, GGA and GGS images.
This commit is contained in:
parent
c270574f52
commit
aa93dabd2d
@ -123,6 +123,11 @@
|
|||||||
<Compile Include="elf\ArcAi5DAT.cs" />
|
<Compile Include="elf\ArcAi5DAT.cs" />
|
||||||
<Compile Include="elf\ImageRMT.cs" />
|
<Compile Include="elf\ImageRMT.cs" />
|
||||||
<Compile Include="HuffmanCompression.cs" />
|
<Compile Include="HuffmanCompression.cs" />
|
||||||
|
<Compile Include="Ikura\ArcTAN.cs" />
|
||||||
|
<Compile Include="Ikura\ImageGGA.cs" />
|
||||||
|
<Compile Include="Ikura\ImageGGS.cs" />
|
||||||
|
<Compile Include="Ikura\ImageTAN.cs" />
|
||||||
|
<Compile Include="Ikura\ImageVRS.cs" />
|
||||||
<Compile Include="Lambda\ArcLAX.cs" />
|
<Compile Include="Lambda\ArcLAX.cs" />
|
||||||
<Compile Include="Lambda\ImageCLS.cs" />
|
<Compile Include="Lambda\ImageCLS.cs" />
|
||||||
<Compile Include="Maika\ArcBK.cs" />
|
<Compile Include="Maika\ArcBK.cs" />
|
||||||
|
@ -45,7 +45,7 @@ namespace GameRes.Formats.Ikura
|
|||||||
|
|
||||||
public DrsOpener ()
|
public DrsOpener ()
|
||||||
{
|
{
|
||||||
Extensions = Enumerable.Empty<string>(); // DRS archives have no extensions
|
Extensions = new string[] { "", "dat", "snr" };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ArcFile TryOpen (ArcView file)
|
public override ArcFile TryOpen (ArcView file)
|
||||||
@ -56,7 +56,7 @@ namespace GameRes.Formats.Ikura
|
|||||||
if (dir_size < 0x20 || 0 != (dir_size & 0xf) || dir_size + 2 >= file.MaxOffset)
|
if (dir_size < 0x20 || 0 != (dir_size & 0xf) || dir_size + 2 >= file.MaxOffset)
|
||||||
return null;
|
return null;
|
||||||
byte first = file.View.ReadByte (2);
|
byte first = file.View.ReadByte (2);
|
||||||
if (0 == first)
|
if (first <= 0x20)
|
||||||
return null;
|
return null;
|
||||||
file.View.Reserve (0, (uint)dir_size + 2);
|
file.View.Reserve (0, (uint)dir_size + 2);
|
||||||
int dir_offset = 2;
|
int dir_offset = 2;
|
||||||
@ -64,25 +64,19 @@ namespace GameRes.Formats.Ikura
|
|||||||
uint next_offset = file.View.ReadUInt32 (dir_offset+12);
|
uint next_offset = file.View.ReadUInt32 (dir_offset+12);
|
||||||
if (next_offset > file.MaxOffset || next_offset < dir_size+2)
|
if (next_offset > file.MaxOffset || next_offset < dir_size+2)
|
||||||
return null;
|
return null;
|
||||||
var encoding = Encodings.cp932.WithFatalFallback();
|
|
||||||
byte[] name_raw = new byte[12];
|
|
||||||
|
|
||||||
int count = dir_size / 0x10 - 1;
|
int count = dir_size / 0x10 - 1;
|
||||||
var dir = new List<Entry> (count);
|
var dir = new List<Entry> (count);
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
file.View.Read (dir_offset, name_raw, 0, 12);
|
var name = file.View.ReadString (dir_offset, 12);
|
||||||
int name_length = name_raw.Length;
|
if (string.IsNullOrEmpty (name))
|
||||||
while (name_length > 0 && 0 == name_raw[name_length-1])
|
|
||||||
--name_length;
|
|
||||||
if (0 == name_length)
|
|
||||||
return null;
|
return null;
|
||||||
uint offset = next_offset;
|
uint offset = next_offset;
|
||||||
dir_offset += 0x10;
|
dir_offset += 0x10;
|
||||||
next_offset = file.View.ReadUInt32 (dir_offset+12);
|
next_offset = file.View.ReadUInt32 (dir_offset+12);
|
||||||
if (next_offset > file.MaxOffset || next_offset < offset)
|
if (next_offset > file.MaxOffset || next_offset < offset)
|
||||||
return null;
|
return null;
|
||||||
string name = encoding.GetString (name_raw, 0, name_length).ToLowerInvariant();
|
|
||||||
var entry = FormatCatalog.Instance.Create<Entry> (name);
|
var entry = FormatCatalog.Instance.Create<Entry> (name);
|
||||||
entry.Offset = offset;
|
entry.Offset = offset;
|
||||||
entry.Size = next_offset - offset;
|
entry.Size = next_offset - offset;
|
||||||
@ -138,21 +132,16 @@ namespace GameRes.Formats.Ikura
|
|||||||
uint index_size = file.View.ReadUInt32 (12);
|
uint index_size = file.View.ReadUInt32 (12);
|
||||||
if (index_size > file.MaxOffset)
|
if (index_size > file.MaxOffset)
|
||||||
return null;
|
return null;
|
||||||
var encoding = Encodings.cp932.WithFatalFallback();
|
|
||||||
byte[] name_raw = new byte[12];
|
|
||||||
|
|
||||||
long dir_offset = 0x20;
|
long dir_offset = 0x20;
|
||||||
var dir = new List<Entry> (count);
|
var dir = new List<Entry> (count);
|
||||||
bool has_scripts = false;
|
bool has_scripts = false;
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
file.View.Read (dir_offset, name_raw, 0, 12);
|
var name = file.View.ReadString (dir_offset, 12);
|
||||||
int name_length = name_raw.Length;
|
if (string.IsNullOrEmpty (name))
|
||||||
while (name_length > 0 && 0 == name_raw[name_length-1])
|
|
||||||
--name_length;
|
|
||||||
if (0 == name_length)
|
|
||||||
return null;
|
return null;
|
||||||
string name = encoding.GetString (name_raw, 0, name_length).ToLowerInvariant();
|
name = name.ToLowerInvariant();
|
||||||
Entry entry;
|
Entry entry;
|
||||||
if (name.EndsWith (".isf") || name.EndsWith (".snr"))
|
if (name.EndsWith (".isf") || name.EndsWith (".snr"))
|
||||||
{
|
{
|
||||||
|
128
ArcFormats/Ikura/ArcTAN.cs
Normal file
128
ArcFormats/Ikura/ArcTAN.cs
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
//! \file ArcTAN.cs
|
||||||
|
//! \date 2018 Jan 16
|
||||||
|
//! \brief D.O. animation resource format.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2018 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.Collections.Generic;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
|
||||||
|
namespace GameRes.Formats.Ikura
|
||||||
|
{
|
||||||
|
internal class TanEntry : Entry
|
||||||
|
{
|
||||||
|
public int Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class TanArchive : ArcFile
|
||||||
|
{
|
||||||
|
public readonly TanMetaData Info;
|
||||||
|
|
||||||
|
public TanArchive (ArcView arc, ArchiveFormat impl, ICollection<Entry> dir, TanMetaData info)
|
||||||
|
: base (arc, impl, dir)
|
||||||
|
{
|
||||||
|
Info = info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Export(typeof(ArchiveFormat))]
|
||||||
|
public class TanOpener : ArchiveFormat
|
||||||
|
{
|
||||||
|
public override string Tag { get { return "TAN/DO"; } }
|
||||||
|
public override string Description { get { return "D.O. animation resource"; } }
|
||||||
|
public override uint Signature { get { return 0; } }
|
||||||
|
public override bool IsHierarchic { get { return false; } }
|
||||||
|
public override bool CanWrite { get { return false; } }
|
||||||
|
|
||||||
|
public override ArcFile TryOpen (ArcView file)
|
||||||
|
{
|
||||||
|
if (!file.Name.HasExtension (".tan"))
|
||||||
|
return null;
|
||||||
|
int count = file.View.ReadInt16 (0);
|
||||||
|
if (!IsSaneCount (count))
|
||||||
|
return null;
|
||||||
|
uint index_pos = 2 + (uint)count * 4;
|
||||||
|
var info = new TanMetaData {
|
||||||
|
Width = file.View.ReadUInt16 (index_pos),
|
||||||
|
Height = file.View.ReadUInt16 (index_pos+2),
|
||||||
|
DataOffset = index_pos + 4,
|
||||||
|
};
|
||||||
|
index_pos += 0x404;
|
||||||
|
count = file.View.ReadInt16 (index_pos);
|
||||||
|
if (!IsSaneCount (count))
|
||||||
|
return null;
|
||||||
|
index_pos += 2;
|
||||||
|
|
||||||
|
var base_name = Path.GetFileNameWithoutExtension (file.Name);
|
||||||
|
var base_offset = index_pos + 4 * count;
|
||||||
|
var dir = new List<Entry> (count);
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
var entry = new TanEntry {
|
||||||
|
Name = string.Format ("{0}#{1:D2}", base_name, i),
|
||||||
|
Type = "image",
|
||||||
|
Offset = base_offset + file.View.ReadUInt32 (index_pos),
|
||||||
|
Index = i,
|
||||||
|
};
|
||||||
|
dir.Add (entry);
|
||||||
|
index_pos += 4;
|
||||||
|
}
|
||||||
|
for (int i = 1; i < count; ++i)
|
||||||
|
{
|
||||||
|
dir[i-1].Size = (uint)(dir[i].Offset - dir[i-1].Offset);
|
||||||
|
if (!dir[i-1].CheckPlacement (file.MaxOffset))
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
dir[dir.Count-1].Size = (uint)(file.MaxOffset - dir[dir.Count-1].Offset);
|
||||||
|
return new TanArchive (file, this, dir, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IImageDecoder OpenImage (ArcFile arc, Entry entry)
|
||||||
|
{
|
||||||
|
var tarc = (TanArchive)arc;
|
||||||
|
var tent = (TanEntry)entry;
|
||||||
|
var input = arc.File.CreateStream();
|
||||||
|
return new TanFrameDecoder (input, tarc.Info, tent.Index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class TanFrameDecoder : BinaryImageDecoder
|
||||||
|
{
|
||||||
|
int m_frame;
|
||||||
|
TanReader m_reader;
|
||||||
|
|
||||||
|
public TanFrameDecoder (IBinaryStream input, TanMetaData info, int frame)
|
||||||
|
: base (input, info)
|
||||||
|
{
|
||||||
|
m_frame = frame;
|
||||||
|
m_reader = new TanReader (m_input, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override ImageData GetImageData ()
|
||||||
|
{
|
||||||
|
var pixels = m_reader.UnpackFrame (m_frame);
|
||||||
|
return ImageData.Create (Info, m_reader.Format, m_reader.Palette, pixels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -460,13 +460,13 @@ namespace GameRes.Formats.Ikura
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Export(typeof(ImageFormat))]
|
[Export(typeof(ImageFormat))]
|
||||||
public class GgaFormat : ImageFormat
|
public class Gga0Format : ImageFormat
|
||||||
{
|
{
|
||||||
public override string Tag { get { return "GG2"; } }
|
public override string Tag { get { return "GG2"; } }
|
||||||
public override string Description { get { return "IKURA GDL image format"; } }
|
public override string Description { get { return "IKURA GDL image format"; } }
|
||||||
public override uint Signature { get { return 0x30414747u; } } // 'GGA0'
|
public override uint Signature { get { return 0x30414747u; } } // 'GGA0'
|
||||||
|
|
||||||
public GgaFormat ()
|
public Gga0Format ()
|
||||||
{
|
{
|
||||||
Extensions = new string[] { "gg1", "gg2", "gg3", "gg0" };
|
Extensions = new string[] { "gg1", "gg2", "gg3", "gg0" };
|
||||||
}
|
}
|
||||||
|
81
ArcFormats/Ikura/ImageGGA.cs
Normal file
81
ArcFormats/Ikura/ImageGGA.cs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
//! \file ImageGGA.cs
|
||||||
|
//! \date 2018 Jan 16
|
||||||
|
//! \brief D.O. compressed image format.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2018 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.ComponentModel.Composition;
|
||||||
|
using System.IO;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using GameRes.Compression;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.Ikura
|
||||||
|
{
|
||||||
|
[Export(typeof(ImageFormat))]
|
||||||
|
public class GgaFormat : ImageFormat
|
||||||
|
{
|
||||||
|
public override string Tag { get { return "GGA"; } }
|
||||||
|
public override string Description { get { return "D.O. image format"; } }
|
||||||
|
public override uint Signature { get { return 0; } }
|
||||||
|
|
||||||
|
class GgaMetaData : ImageMetaData
|
||||||
|
{
|
||||||
|
public int UnpackedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||||
|
{
|
||||||
|
if (!file.Name.HasExtension (".gga"))
|
||||||
|
return null;
|
||||||
|
int x = file.ReadInt16();
|
||||||
|
int y = file.ReadInt16();
|
||||||
|
uint w = file.ReadUInt16();
|
||||||
|
uint h = file.ReadUInt16();
|
||||||
|
int unpacked_size = file.ReadInt32();
|
||||||
|
if (0 == w || 0 == h || w > 0x7FFF || h > 0x7FFF || x < 0 || y < 0
|
||||||
|
|| 3 * w * h != unpacked_size)
|
||||||
|
return null;
|
||||||
|
return new GgaMetaData {
|
||||||
|
Width = w, Height = h, OffsetX = x, OffsetY = y, BPP = 24,
|
||||||
|
UnpackedSize = unpacked_size,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||||
|
{
|
||||||
|
var meta = (GgaMetaData)info;
|
||||||
|
file.Position = 12;
|
||||||
|
var pixels = new byte[meta.UnpackedSize];
|
||||||
|
using (var input = new LzssStream (file.AsStream, LzssMode.Decompress, true))
|
||||||
|
{
|
||||||
|
if (pixels.Length != input.Read (pixels, 0, pixels.Length))
|
||||||
|
throw new InvalidFormatException();
|
||||||
|
}
|
||||||
|
return ImageData.Create (info, PixelFormats.Bgr24, null, pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write (Stream file, ImageData image)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException ("GgaFormat.Write not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
140
ArcFormats/Ikura/ImageGGS.cs
Normal file
140
ArcFormats/Ikura/ImageGGS.cs
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
//! \file ImageGGS.cs
|
||||||
|
//! \date 2018 Jan 16
|
||||||
|
//! \brief D.O. compressed image format.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2018 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.ComponentModel.Composition;
|
||||||
|
using System.IO;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.Ikura
|
||||||
|
{
|
||||||
|
[Export(typeof(ImageFormat))]
|
||||||
|
public class GgsFormat : ImageFormat
|
||||||
|
{
|
||||||
|
public override string Tag { get { return "GGS"; } }
|
||||||
|
public override string Description { get { return "D.O. image format"; } }
|
||||||
|
public override uint Signature { get { return 0; } }
|
||||||
|
|
||||||
|
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||||
|
{
|
||||||
|
if (!file.Name.HasExtension (".ggs"))
|
||||||
|
return null;
|
||||||
|
int x = file.ReadInt16();
|
||||||
|
int y = file.ReadInt16();
|
||||||
|
uint w = file.ReadUInt16();
|
||||||
|
uint h = file.ReadUInt16();
|
||||||
|
if (0 == w || 0 == h || w > 0x4000 || h > 0x4000 || x < 0 || y < 0)
|
||||||
|
return null;
|
||||||
|
return new ImageMetaData { Width = w, Height = h, OffsetX = x, OffsetY = y, BPP = 24 };
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||||
|
{
|
||||||
|
var reader = new GgsReader (file, info);
|
||||||
|
var pixels = reader.Unpack();
|
||||||
|
return ImageData.Create (info, reader.Format, null, pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write (Stream file, ImageData image)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException ("GgsFormat.Write not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class GgsReader
|
||||||
|
{
|
||||||
|
IBinaryStream m_input;
|
||||||
|
byte[] m_output;
|
||||||
|
|
||||||
|
public PixelFormat Format { get { return PixelFormats.Bgr24; } }
|
||||||
|
|
||||||
|
public GgsReader (IBinaryStream input, ImageMetaData info)
|
||||||
|
{
|
||||||
|
m_input = input;
|
||||||
|
m_output = new byte[3 * info.Width * info.Height];
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Unpack ()
|
||||||
|
{
|
||||||
|
m_input.Position = 8;
|
||||||
|
for (int channel = 0; channel < 3; ++channel)
|
||||||
|
{
|
||||||
|
int dst = channel;
|
||||||
|
while (dst < m_output.Length)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
byte ctl = m_input.ReadUInt8();
|
||||||
|
if (0 == ctl--)
|
||||||
|
{
|
||||||
|
count = m_input.ReadUInt8();
|
||||||
|
byte v = m_input.ReadUInt8();
|
||||||
|
while (count --> 0)
|
||||||
|
{
|
||||||
|
m_output[dst] = v;
|
||||||
|
dst += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (0 == ctl--)
|
||||||
|
{
|
||||||
|
count = m_input.ReadUInt8();
|
||||||
|
int offset = m_input.ReadUInt8();
|
||||||
|
while (count --> 0)
|
||||||
|
{
|
||||||
|
m_output[dst] = m_output[dst-offset];
|
||||||
|
dst += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (0 == ctl--)
|
||||||
|
{
|
||||||
|
count = m_input.ReadUInt8();
|
||||||
|
int offset = m_input.ReadUInt16();
|
||||||
|
while (count --> 0)
|
||||||
|
{
|
||||||
|
m_output[dst] = m_output[dst-offset];
|
||||||
|
dst += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (0 == ctl--)
|
||||||
|
{
|
||||||
|
dst += m_input.ReadUInt8();
|
||||||
|
}
|
||||||
|
else if (0 == ctl)
|
||||||
|
{
|
||||||
|
dst += m_input.ReadUInt16();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
count = ctl;
|
||||||
|
while (count --> 0)
|
||||||
|
{
|
||||||
|
m_output[dst] = m_input.ReadUInt8();
|
||||||
|
dst += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m_output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
170
ArcFormats/Ikura/ImageTAN.cs
Normal file
170
ArcFormats/Ikura/ImageTAN.cs
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
//! \file ImageTAN.cs
|
||||||
|
//! \date 2018 Jan 16
|
||||||
|
//! \brief D.O. animation resource format.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2018 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 System.Windows.Media.Imaging;
|
||||||
|
using GameRes.Utility;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.Ikura
|
||||||
|
{
|
||||||
|
internal class TanMetaData : ImageMetaData
|
||||||
|
{
|
||||||
|
public uint DataOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Export(typeof(ImageFormat))]
|
||||||
|
public class TanFormat : ImageFormat
|
||||||
|
{
|
||||||
|
public override string Tag { get { return "TAN"; } }
|
||||||
|
public override string Description { get { return "D.O. animation resource"; } }
|
||||||
|
public override uint Signature { get { return 0; } }
|
||||||
|
|
||||||
|
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||||
|
{
|
||||||
|
if (!file.Name.HasExtension (".tan"))
|
||||||
|
return null;
|
||||||
|
int count = file.ReadUInt16();
|
||||||
|
if (0 == count)
|
||||||
|
return null;
|
||||||
|
file.Position = 2 + count * 4;
|
||||||
|
uint w = file.ReadUInt16();
|
||||||
|
uint h = file.ReadUInt16();
|
||||||
|
if (0 == w || 0 == h)
|
||||||
|
return null;
|
||||||
|
return new TanMetaData {
|
||||||
|
Width = w, Height = h, BPP = 8,
|
||||||
|
DataOffset = (uint)file.Position,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||||
|
{
|
||||||
|
var reader = new TanReader (file, (TanMetaData)info);
|
||||||
|
var pixels = reader.UnpackFrame (0);
|
||||||
|
return ImageData.Create (info, reader.Format, reader.Palette, pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write (Stream file, ImageData image)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException ("TanFormat.Write not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class TanReader
|
||||||
|
{
|
||||||
|
IBinaryStream m_input;
|
||||||
|
byte[] m_output;
|
||||||
|
TanMetaData m_info;
|
||||||
|
|
||||||
|
public PixelFormat Format { get; private set; }
|
||||||
|
public BitmapPalette Palette { get; private set; }
|
||||||
|
|
||||||
|
public TanReader (IBinaryStream input, TanMetaData info)
|
||||||
|
{
|
||||||
|
m_input = input;
|
||||||
|
m_output = new byte[info.Width * info.Height];
|
||||||
|
m_info = info;
|
||||||
|
Format = 8 == m_info.BPP ? PixelFormats.Indexed8 : PixelFormats.Bgr24;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] UnpackFrame (int frame)
|
||||||
|
{
|
||||||
|
m_input.Position = m_info.DataOffset;
|
||||||
|
if (8 == m_info.BPP)
|
||||||
|
Palette = ImageFormat.ReadPalette (m_input.AsStream);
|
||||||
|
int count = m_input.ReadUInt16();
|
||||||
|
if (frame >= count)
|
||||||
|
throw new InvalidFormatException ("Not enough frames in TAN file.");
|
||||||
|
long base_pos = m_input.Position + 4 * count;
|
||||||
|
var frame_table = new uint[count];
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
frame_table[i] = m_input.ReadUInt32();
|
||||||
|
Action Unpack;
|
||||||
|
if (8 == m_info.BPP)
|
||||||
|
Unpack = Unpack8bpp;
|
||||||
|
else
|
||||||
|
Unpack = Unpack24bpp;
|
||||||
|
for (int i = 0; i <= frame; ++i)
|
||||||
|
{
|
||||||
|
m_input.Position = base_pos + frame_table[i];
|
||||||
|
Unpack();
|
||||||
|
}
|
||||||
|
return m_output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Unpack8bpp ()
|
||||||
|
{
|
||||||
|
int dst = 0;
|
||||||
|
while (dst < m_output.Length)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
byte ctl = m_input.ReadUInt8();
|
||||||
|
if (0 == ctl--)
|
||||||
|
{
|
||||||
|
count = m_input.ReadUInt8();
|
||||||
|
byte v = m_input.ReadUInt8();
|
||||||
|
while (count --> 0)
|
||||||
|
m_output[dst++] = v;
|
||||||
|
}
|
||||||
|
else if (0 == ctl--)
|
||||||
|
{
|
||||||
|
count = m_input.ReadUInt8();
|
||||||
|
int offset = m_input.ReadUInt8();
|
||||||
|
Binary.CopyOverlapped (m_output, dst-offset, dst, count);
|
||||||
|
dst += count;
|
||||||
|
}
|
||||||
|
else if (0 == ctl--)
|
||||||
|
{
|
||||||
|
count = m_input.ReadUInt8();
|
||||||
|
int offset = m_input.ReadUInt16();
|
||||||
|
Binary.CopyOverlapped (m_output, dst-offset, dst, count);
|
||||||
|
dst += count;
|
||||||
|
}
|
||||||
|
else if (0 == ctl--)
|
||||||
|
{
|
||||||
|
dst += m_input.ReadUInt8();
|
||||||
|
}
|
||||||
|
else if (0 == ctl)
|
||||||
|
{
|
||||||
|
dst += m_input.ReadUInt16();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
count = ctl;
|
||||||
|
m_input.Read (m_output, dst, count);
|
||||||
|
dst += count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Unpack24bpp ()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
132
ArcFormats/Ikura/ImageVRS.cs
Normal file
132
ArcFormats/Ikura/ImageVRS.cs
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
//! \file ImageVRS.cs
|
||||||
|
//! \date 2018 Jan 16
|
||||||
|
//! \brief D.O. image format.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2018 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.ComponentModel.Composition;
|
||||||
|
using System.IO;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using GameRes.Utility;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.Ikura
|
||||||
|
{
|
||||||
|
[Export(typeof(ImageFormat))]
|
||||||
|
public class DoFormat : ImageFormat
|
||||||
|
{
|
||||||
|
public override string Tag { get { return "VRS/DO"; } }
|
||||||
|
public override string Description { get { return "D.O. image format"; } }
|
||||||
|
public override uint Signature { get { return 0x4F44; } } // 'DO'
|
||||||
|
|
||||||
|
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||||
|
{
|
||||||
|
var header = file.ReadHeader (8);
|
||||||
|
return new ImageMetaData {
|
||||||
|
Width = header.ToUInt16 (4),
|
||||||
|
Height = header.ToUInt16 (6),
|
||||||
|
BPP = 8,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||||
|
{
|
||||||
|
var reader = new DoReader (file, info);
|
||||||
|
reader.Unpack();
|
||||||
|
return ImageData.Create (info, reader.Format, reader.Palette, reader.Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write (Stream file, ImageData image)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException ("DoFormat.Write not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DoReader
|
||||||
|
{
|
||||||
|
IBinaryStream m_input;
|
||||||
|
byte[] m_output;
|
||||||
|
|
||||||
|
public PixelFormat Format { get; private set; }
|
||||||
|
public BitmapPalette Palette { get; private set; }
|
||||||
|
public byte[] Data { get { return m_output; } }
|
||||||
|
|
||||||
|
public DoReader (IBinaryStream input, ImageMetaData info)
|
||||||
|
{
|
||||||
|
m_input = input;
|
||||||
|
m_output = new byte[info.Width * info.Height];
|
||||||
|
Format = PixelFormats.Indexed8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unpack ()
|
||||||
|
{
|
||||||
|
m_input.Position = 12;
|
||||||
|
Palette = ReadPalette();
|
||||||
|
int dst = 0;
|
||||||
|
while (dst < m_output.Length)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
byte ctl = m_input.ReadUInt8();
|
||||||
|
if (0 == (ctl & 0xC0))
|
||||||
|
{
|
||||||
|
count = ctl & 0x3F;
|
||||||
|
if (0 == count)
|
||||||
|
count = m_input.ReadUInt8() + 0x40;
|
||||||
|
m_input.Read (m_output, dst, count);
|
||||||
|
}
|
||||||
|
else if (0 == (ctl & 0x80))
|
||||||
|
{
|
||||||
|
count = ctl & 0x3F;
|
||||||
|
if (0 == count)
|
||||||
|
count = m_input.ReadUInt8() + 0x40;
|
||||||
|
++count;
|
||||||
|
Binary.CopyOverlapped (m_output, dst-1, dst, count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int offset = (m_input.ReadUInt8() | (ctl & 0xF) << 8) + 1;
|
||||||
|
count = (ctl >> 4) & 7;
|
||||||
|
if (0 == count)
|
||||||
|
count = m_input.ReadUInt8() + 8;
|
||||||
|
count += 2;
|
||||||
|
Binary.CopyOverlapped (m_output, dst-offset, dst, count);
|
||||||
|
}
|
||||||
|
dst += count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BitmapPalette ReadPalette ()
|
||||||
|
{
|
||||||
|
var palette_data = m_input.ReadBytes (0x300);
|
||||||
|
if (palette_data.Length != 0x300)
|
||||||
|
throw new EndOfStreamException();
|
||||||
|
int src = 0;
|
||||||
|
var color_map = new Color[0x100];
|
||||||
|
for (int i = 0; i < 0x100; ++i)
|
||||||
|
{
|
||||||
|
color_map[i] = Color.FromRgb (palette_data[src+1], palette_data[src+2], palette_data[src]);
|
||||||
|
src += 3;
|
||||||
|
}
|
||||||
|
return new BitmapPalette (color_map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user