diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj index f8e37d86..ad15eb57 100644 --- a/ArcFormats/ArcFormats.csproj +++ b/ArcFormats/ArcFormats.csproj @@ -131,7 +131,9 @@ + + WidgetDXA.xaml @@ -142,8 +144,10 @@ + + diff --git a/ArcFormats/DigitalWorks/ArcPACsingle.cs b/ArcFormats/DigitalWorks/ArcPACsingle.cs new file mode 100644 index 00000000..310823c1 --- /dev/null +++ b/ArcFormats/DigitalWorks/ArcPACsingle.cs @@ -0,0 +1,88 @@ +//! \file ArcPACPS2.cs +//! \date 2018 Sep 18 +//! \brief Digital Works PS2 resource archive. +// +// 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; +using GameRes.Compression; + +namespace GameRes.Formats.DigitalWorks +{ + [Export(typeof(ArchiveFormat))] + public class PacSingleOpener : ArchiveFormat + { + public override string Tag { get { return "PAC/LZS-TIM2"; } } + public override string Description { get { return "LZS-TIM2 Image archive"; } } + public override uint Signature { get { return 0x535A4C; } } // 'LZS' + public override bool IsHierarchic { get { return false; } } + public override bool CanWrite { get { return false; } } + + /** + Target games: + Cafe Little Wish SLPM-65294 + F Fanatic SLPM-65296 + */ + + public override ArcFile TryOpen (ArcView file) + { + if (!file.View.AsciiEqual(9, "TIM2")) + return null; + var dir = new List (1); + var entry = FormatCatalog.Instance.Create (file.Name); + entry.Offset = 0L; + entry.Size = (uint)file.MaxOffset; + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + dir.Add (entry); + + return new ArcFile (file, this, dir); + } + + public override Stream OpenEntry (ArcFile arc, Entry entry) + { + var pent = entry as PackedEntry; + if (null == pent) + return base.OpenEntry (arc, entry); + if (!pent.IsPacked) + { + if (!arc.File.View.AsciiEqual (entry.Offset, "LZS\0")) + return base.OpenEntry (arc, entry); + pent.IsPacked = true; + pent.UnpackedSize = arc.File.View.ReadUInt32 (entry.Offset+4); + } + var input = arc.File.CreateStream (entry.Offset+8, entry.Size-8); + bool embedded_lzs = (input.Signature & ~0xF0u) == 0x535A4C0F; // 'LZS' + var lzs = new LzssStream (input); + if (embedded_lzs) + { + var header = new byte[8]; + lzs.Read (header, 0, 8); + pent.UnpackedSize = header.ToUInt32 (4); + lzs = new LzssStream (lzs); + } + return lzs; + } + } +} diff --git a/ArcFormats/DigitalWorks/ImageTM2.cs b/ArcFormats/DigitalWorks/ImageTM2.cs index 2c3a6afc..b5ce73f4 100644 --- a/ArcFormats/DigitalWorks/ImageTM2.cs +++ b/ArcFormats/DigitalWorks/ImageTM2.cs @@ -23,6 +23,7 @@ // IN THE SOFTWARE. // +using GameRes.Formats.Strings; using System; using System.ComponentModel.Composition; using System.IO; @@ -36,6 +37,7 @@ namespace GameRes.Formats.DigitalWorks public int PaletteSize; public int HeaderSize; public int Colors; + public byte Alpha; } [Export(typeof(ImageFormat))] @@ -48,8 +50,16 @@ namespace GameRes.Formats.DigitalWorks public Tim2Format () { Extensions = new string[] { "tm2", "ext" }; + Settings = new[] { AlphaFormat }; } + FixedSetSetting AlphaFormat = new FixedSetSetting(Properties.Settings.Default) + { + Name = "TIM2AlphaFormat", + Text = arcStrings.Tim2AlphaFormat, + ValuesSet = new[] { "No Alpha", "RGBX", "RGBA" }, + }; + public override ImageMetaData ReadMetaData (IBinaryStream file) { var header = file.ReadHeader (0x40); @@ -59,9 +69,18 @@ namespace GameRes.Formats.DigitalWorks case 1: bpp = 16; break; case 2: bpp = 24; break; case 3: bpp = 32; break; + case 4: bpp = 4; break; //16color case 5: bpp = 8; break; default: return null; } + byte alpha; + switch (AlphaFormat.Get()) + { + case "No Alpha": alpha = 0; break; + case "RGBX": alpha = 7; break; + case "RGBA": + default: alpha = 8; break; + } return new Tim2MetaData { Width = header.ToUInt16 (0x24), Height = header.ToUInt16 (0x26), @@ -69,6 +88,7 @@ namespace GameRes.Formats.DigitalWorks PaletteSize = header.ToInt32 (0x14), HeaderSize = header.ToUInt16 (0x1C), Colors = header.ToUInt16 (0x1E), + Alpha = alpha, //header.ToUInt16(0x30) == 0?// not so sure, there will be omissions }; } @@ -99,39 +119,69 @@ namespace GameRes.Formats.DigitalWorks m_info = info; switch (info.BPP) { - case 8: Format = PixelFormats.Indexed8; break; - case 16: Format = PixelFormats.Bgr555; break; - case 24: Format = PixelFormats.Bgr24; break; - case 32: Format = PixelFormats.Bgra32; break; + case 4: Format = PixelFormats.Indexed4; break; + case 8: Format = PixelFormats.Indexed8; break; + case 16: Format = PixelFormats.Bgr555; break; + case 24: Format = PixelFormats.Bgr24; break; + case 32: Format = PixelFormats.Bgra32; break; } } public byte[] Unpack () { m_input.Position = 0x10 + m_info.HeaderSize; - int pixel_size = m_info.BPP / 8; - int image_size = (int)m_info.Width * (int)m_info.Height * pixel_size; + double pixel_size = (double)m_info.BPP / 8; + int image_size = (int)((int)m_info.Width * (int)m_info.Height * pixel_size); var output = m_input.ReadBytes (image_size); if (pixel_size <= 8 && m_info.Colors > 0) - Palette = ReadPalette (m_info.Colors); + Palette = ReadPalette (m_info.Colors, m_info.Alpha); - if (pixel_size >= 3) + if (pixel_size == 3 || pixel_size == 4 && m_info.Alpha == 8) { - for (int i = 0; i < image_size; i += pixel_size) + for (int i = 0; i < image_size; i += (int)pixel_size) { byte r = output[i]; output[i] = output[i+2]; output[i+2] = r; } } + if (pixel_size == 4 && m_info.Alpha == 7) + { + for (int i = 0; i < image_size; i += 4) + { + byte r = output[i]; + output[i] = output[i + 2]; + output[i + 2] = r; + if (output[i + 3] >= byte.MaxValue / 2) + output[i + 3] = byte.MaxValue; + else + output[i + 3] = (byte)(output[i + 3] << 1); + } + } + if (pixel_size == 4 && m_info.Alpha == 0) + { + for (int i = 0; i < image_size; i += 4) + { + byte r = output[i]; + output[i] = output[i + 2]; + output[i + 2] = r; + output[i + 3] = byte.MaxValue; + } + } return output; } - BitmapPalette ReadPalette (int color_num) + BitmapPalette ReadPalette (int color_num, byte X_A = 8) { - var source = ImageFormat.ReadColorMap (m_input.AsStream, color_num, PaletteFormat.RgbA); + var source = ImageFormat.ReadColorMap (m_input.AsStream, + color_num, X_A == 7 ? PaletteFormat.RgbA7 : X_A == 0 ? PaletteFormat.RgbX : PaletteFormat.RgbA); var color_map = new Color[color_num]; + if (color_num == 16){ + Array.Copy(source, 0, color_map, 0, 16); + return new BitmapPalette(color_map); + } + int parts = color_num / 32; const int blocks = 2; const int rows = 2; diff --git a/ArcFormats/DigitalWorks/ImageTM2arc.cs b/ArcFormats/DigitalWorks/ImageTM2arc.cs new file mode 100644 index 00000000..f7be9250 --- /dev/null +++ b/ArcFormats/DigitalWorks/ImageTM2arc.cs @@ -0,0 +1,53 @@ +using GameRes.Compression; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; + +namespace GameRes.Formats.DigitalWorks +{ + [Export(typeof(ImageFormat))] + public class TM2ArkFormat : Tim2Format + { + public override string Tag { get { return "TIM2/PS2 compressed"; } } + public override string Description { get { return "PlayStation/2 image format with LZSS compress"; } } + public override uint Signature { get { return 0x535A4C; } } // 'LZS' + public TM2ArkFormat() + { + Extensions = new string[] { "tm2" }; + Settings = null; + } + + public override ImageMetaData ReadMetaData(IBinaryStream stream) + { + stream.Position = 9; + uint real_sign = stream.ReadUInt32(); + //Tim2Format tm2raw = new Tim2Format(); + if (real_sign != base.Signature) + { + return null; + } + stream.Position = 4; + uint unpacked_size = stream.ReadUInt32(); + if (unpacked_size <= 0x20 || unpacked_size > 0x5000000) // ~83MB + return null; + stream.Position = 8; + using (var lzss = new LzssStream(stream.AsStream, LzssMode.Decompress, true)) + using (var input = new SeekableStream(lzss)) + using (var tm2 = new BinaryStream(input, stream.Name)) + return base.ReadMetaData(tm2); + } + public override ImageData Read(IBinaryStream stream, ImageMetaData info) + { + stream.Position = 8; + using (var lzss = new LzssStream(stream.AsStream, LzssMode.Decompress, true)) + using (var input = new SeekableStream(lzss)) + using (var tm2 = new BinaryStream(input, stream.Name)) + return base.Read(tm2, info); + } + public override void Write(Stream file, ImageData image) + { + throw new System.NotImplementedException("TM2ArkFormat.Write not implemented"); + } + } +} diff --git a/ArcFormats/Kid/ArcKLZ.cs b/ArcFormats/Kid/ArcKLZ.cs new file mode 100644 index 00000000..e073bb70 --- /dev/null +++ b/ArcFormats/Kid/ArcKLZ.cs @@ -0,0 +1,122 @@ +using GameRes.Utility; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; + +namespace GameRes.Formats.Kid +{ + [Export(typeof(ArchiveFormat))] + public class KlzOpener: ArchiveFormat + { + public override string Tag { get { return "KLZ/KID PS2"; } } + public override string Description { get { return "KID PS2 compressed image format with multi TIM2"; } } + public override uint Signature { get { return 0; } } + public override bool IsHierarchic { get { return false; } } + public override bool CanWrite { get { return false; } } + + public KlzOpener() + { + Extensions = new string[] { "klz" }; + } + + public override ArcFile TryOpen(ArcView file) + { + if (!file.Name.HasExtension(".klz")) + return null; + uint unpacked_size = Binary.BigEndian(file.View.ReadUInt32(0)); + if (unpacked_size <= 0x20 || unpacked_size > 0x5000000) + return null; + + var backend = file.CreateStream(); + var input = KlzFormat.LzhStreamDecode(backend); + var base_name = Path.GetFileNameWithoutExtension(file.Name); + var dir = GetEntries(input, base_name); + if (dir == null || dir.Count == 0) + { + return null; + } + else + { + return new KlzArchive(file, this, dir, input); + } + //throw new NotImplementedException(); + } + + public override Stream OpenEntry(ArcFile arc, Entry entry) + { + return new StreamRegion(((KlzArchive)arc).Source, entry.Offset, entry.Size, true); + } + + internal static List GetEntries (Stream input, string base_name) + { + var entries = new List(); + BinaryReader m_input = new ArcView.Reader(input); + int count = 0; + m_input.BaseStream.Position = 0; + while (m_input.BaseStream.Position < m_input.BaseStream.Length) + { + while (true) + { + try + { + uint sign = m_input.ReadUInt32(); + m_input.ReadBytes(12); + if (sign == 0x324D4954) //TIM2 + { + //m_input.BaseStream.Seek(-4, SeekOrigin.Current); + break; + } + } + catch (EndOfStreamException) + { + return entries; + } + } + long tell = m_input.BaseStream.Position - 16; + uint size = m_input.ReadUInt32() + 16; + string name = base_name + "_" + count.ToString("D2"); + if (tell + size > m_input.BaseStream.Length) + { + size = (uint)(m_input.BaseStream.Length - tell); + name += "_incomplete"; + } + var entry = new Entry { + Name = name + ".tm2", + Size = size, + Offset = tell, + Type = "image" + }; + count++; + entries.Add(entry); + m_input.BaseStream.Position = tell + size; + } + return entries; + } + } + + internal class KlzArchive : ArcFile + { + public readonly Stream Source; + public KlzArchive(ArcView arc, ArchiveFormat impl, ICollection dir, Stream input) + : base (arc, impl, dir) + { + Source = input; + } + + #region IDisposable Members + bool _spc_disposed = false; + protected override void Dispose(bool disposing) + { + if (_spc_disposed) + return; + if (disposing) + { + Source.Dispose(); + } + _spc_disposed = true; + base.Dispose(disposing); + } + #endregion + } +} diff --git a/ArcFormats/Kid/ImageKLZ.cs b/ArcFormats/Kid/ImageKLZ.cs new file mode 100644 index 00000000..b8be2adb --- /dev/null +++ b/ArcFormats/Kid/ImageKLZ.cs @@ -0,0 +1,313 @@ +using GameRes.Utility; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; +using System.Linq; + +namespace GameRes.Formats.Kid +{ + [Export(typeof(ImageFormat))] + public class KlzFormat: DigitalWorks.Tim2Format + { + public override string Tag { get { return "KLZ/KID PS2 compressed TIM2"; } } + public override string Description { get { return "KID PS2 compressed TIM2 image format"; } } + public override uint Signature { get { return 0; } } //KLZ have no header + public KlzFormat() + { + Extensions = new string[] { "klz" }; + Settings = null; + } + + public override ImageMetaData ReadMetaData(IBinaryStream stream) + { + uint unpacked_size = Binary.BigEndian(stream.Signature); + if (unpacked_size <= 0x20 || unpacked_size > 0x5000000) // ~83MB + return null; + stream.Position = 0; + //Stream streamdec = LzsStreamDecode(stream); + //using (var lzss = new LzssStream(stream.AsStream, LzssMode.Decompress, true)) + using (var input = new SeekableStream(LzhStreamDecode(stream))) + using (var tm2 = new BinaryStream(input, stream.Name)) + return base.ReadMetaData(tm2); + } + public override ImageData Read(IBinaryStream stream, ImageMetaData info) + { + //stream.Position = 4; + //using (var lzss = new LzssStream(stream.AsStream, LzssMode.Decompress, true)) + using (var input = new SeekableStream(LzhStreamDecode(stream))) + using (var tm2 = new BinaryStream(input, stream.Name)) + return base.Read(tm2, info); + } + public override void Write(Stream file, ImageData image) + { + throw new System.NotImplementedException("KlzFormat.Write not implemented"); + } + + /// + /// Original lzh_decode_mips + /// + /// The following code is from punk7890/PS2-Visual-Novel-Tool under MIT license. + /// Source code: https://github.com/punk7890/PS2-Visual-Novel-Tool/blob/ac5602fbf13d15ce1bfaa27dc2263373cfebc0e5/src/scenes/kid.gd#L104 + /// input stream, include header + /// + public static Stream LzhStreamDecode(IBinaryStream input) { + byte[] out_bytes = new byte[0x4000]; + List f_out_bytes = new List(); + uint output_size = Binary.BigEndian(input.ReadUInt32()); + ushort fill_count = Binary.BigEndian(input.ReadUInt16()); + bool at; + int v0, s0 = 0, s1, s3; + byte v1; //byte a0 + ushort s2; + int OO40_sp = 0, OO42_sp = 0, OO44_sp, OO48_sp, OO50_sp = 0, OO60_sp = 0, OO70_sp = fill_count; + int next_read_pos = 0; + int count = 0; + int num_passes = 0; + byte[] decode_table = new byte[] { + 0x01, 0x02, 0x04, 0x08, + 0x10, 0x20, 0x40, 0x80, + // Only first 8 are used + 0x81, 0x75, 0x81, 0x69, + 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x00, 0x00 + }; + // out.resize(0x4000) + /*int temp = 0x4000; + while (temp > 0) + { + out_bytes.Add(0); + temp--; + }*/ + //out_bytes = Enumerable.Repeat((byte)0, 0x4000); + // out.resize(0x4000) end + if (fill_count > 0x4000) + { + next_read_pos = 4; + while (OO70_sp > 0x4000) + { + int cnt = 0; + int copy_off = next_read_pos + 2; + while (cnt < 0x4000) + { + input.Position = copy_off; + f_out_bytes.Add(input.ReadUInt8()); + cnt++; + copy_off++; + } + count += 0x4000; + next_read_pos += cnt + 2; + num_passes++; + input.Position = next_read_pos; + OO70_sp = Binary.BigEndian(input.ReadUInt16()); + if (count >= output_size || next_read_pos >= input.Length) + { + Stream stream = new MemoryStream(f_out_bytes.ToArray()); + return stream; + } + OO60_sp = next_read_pos + 2; + } + } + else + { + OO60_sp = 6; + } + + OO44_sp = OO60_sp; + /*v0 = OO60_sp + 1; + OO48_sp = v0;*/ + OO48_sp = OO60_sp + 1; + while (true){ + input.Position = OO44_sp; + //input.Seek(OO44_sp, SeekOrigin.Begin); + /*v0 = input.ReadUInt8(); + a0 = v0 & 0xFF;*/ + //a0 = input.ReadUInt8(); + /*v0 = OO40_sp; + v1 = v0 & 0xFF;*/ + v0 = decode_table[OO40_sp & 0xFF] & input.ReadUInt8(); + //v0 &= a0; + // #001BA8AC + if (v0 == 0) + { + input.Position = OO48_sp; + //input.Seek(OO48_sp, SeekOrigin.Begin); + v1 = input.ReadUInt8(); + v0 = OO50_sp + s0; + /*out_bytes.RemoveAt(v0); + out_bytes.Insert(v0, v1);*/ + out_bytes[v0] = v1; + OO48_sp++; + OO42_sp++; + s0++; + } + else if (v0 != 0) { + // # 001BA8F0 + OO42_sp += 2; + input.Position = OO48_sp; + // input.Seek(OO48_sp, SeekOrigin.Begin); + /*v0 = input.ReadUInt8() & 0xFF; + v1 = v0 << 8; + v0 = input.ReadUInt8() & 0xFF; + v0 = v1 | v0; + v0 &= 0xFFFF;*/ + s2 = Binary.BigEndian(input.ReadUInt16()); + /*s2 = v0 & 0xFFFF; + v0 = s2 & 0xFFFF;*/ + //v0 = s2; + //v0 = (s2 & 0x1F); + //v0 += 2; + //v0 &= 0xFFFF; + /*s3 = v0 & 0xFFFF; + v0 = s2 & 0xFFFF;*/ + s3 = (s2 & 0x1F) + 2; + //v0 = s2; + //v0 >>= 5; + /*v0 &= 0xFFFF; + s1 = v0 & 0xFFFF; + v0 = s1 & 0xFFFF;*/ + v0 = s0 - (s2 >> 5) - 1; + //v0 -= 1; + //v0 &= 0xFFFF; + s1 = v0 & 0xFFFF; + OO48_sp += 1; + v0 = 1; + while (v0 != 0) + { + at = s0 < 0x0800; + // # 001BA96C + if (at) + { + v0 = s1 & 0xFFFF; + at = s0 < v0; + if (at) + { + v1 = out_bytes[OO50_sp]; + v0 = OO50_sp + s0; + /*out_bytes.RemoveAt(v0); + out_bytes.Insert(v0, v1);*/ + out_bytes[v0] = v1; + s0 += 1; + /*v0 = s1 + 1; + s1 = v0 & 0xFFFF;*/ + s1 = (s1 + 1) & 0xFFFF; + // # 001BA9D8 + /*v1 = s3; + v0 = v1 - 1; + s3 = v0 & 0xFFFF; + v0 = v1 & 0xFFFF;*/ + v0 = s3 & 0xFFFF; + s3 = (s3 - 1) & 0xFFFF; + continue; + } + } + // # 001BA9B0 + /*v1 = s1 & 0xFFFF; + v0 = OO50_sp; + v0 += v1;*/ + //v0 = OO50_sp + s1 & 0xFFFF; + //v1 = out_bytes[v0]; + v1 = out_bytes[OO50_sp + s1 & 0xFFFF]; + v0 = OO50_sp; + v0 += s0; + /*out_bytes.RemoveAt(v0); + out_bytes.Insert(v0, v1);*/ + out_bytes[v0] = v1; + s0 += 1; + //v0 = s1 + 1; + s1 = (s1 + 1) & 0xFFFF; + // # 001BA9D8 + /*v1 = s3; + v0 = v1 - 1; + s3 = v0 & 0xFFFF; + v0 = v1 & 0xFFFF;*/ + v0 = s3 & 0xFFFF; + s3 = s3 - 1 & 0xFFFF; + } + OO48_sp += 1; + } + // # 001BAA00 + OO40_sp += 1; + //v1 = Convert.ToByte(OO40_sp & 0xFF); + //v0 = 8; + if ((OO40_sp & 0xFF) == 8) + { + OO40_sp = 0; + OO44_sp = OO48_sp; + OO48_sp += 1; + OO42_sp += 1; + } + /*v0 = OO42_sp; + v1 = v0 & 0xFFFF; + v0 = OO70_sp; + v0 -= 1;*/ + //v0 = v1 < v0 ? 1 : 0; + v0 = OO42_sp < OO70_sp - 1 ? 1 : 0; + if (v0 == 0) + { + count += s0; + if (count >= output_size || next_read_pos >= input.Length) + { + f_out_bytes.AddRange(out_bytes); + Stream stream = new MemoryStream(f_out_bytes.ToArray()); + return stream; + } + num_passes += 1; + if (num_passes == 1) + { + next_read_pos += OO70_sp + 6; + } + else + { + next_read_pos += OO70_sp + 2; + } + + f_out_bytes.AddRange(out_bytes); + // # out.fill(0); + input.Position = next_read_pos; + OO70_sp = Binary.BigEndian(input.ReadUInt16()); + if (OO70_sp > 0x4000) + { + while (OO70_sp > 0x4000) + { + int cnt = 0; + int copy_off = next_read_pos + 2; + while (cnt < 0x4000) + { + input.Position = copy_off; + f_out_bytes.Add(input.ReadUInt8()); + cnt += 1; + copy_off += 1; + } + count += 0x4000; + next_read_pos += cnt + 2; + input.Position = next_read_pos; + OO70_sp = Binary.BigEndian(input.ReadUInt16()); + if (count >= output_size || next_read_pos >= input.Length) + { + Stream stream = new MemoryStream(f_out_bytes.ToArray()); + return stream; + } + } + } + s0 = 0; + //s1 = 0; + OO50_sp = 0; + OO42_sp = 0; + OO48_sp = next_read_pos + 2; + if (OO48_sp > input.Length) { + Stream stream = new MemoryStream(f_out_bytes.ToArray()); + return stream; + } + OO40_sp = 0; + OO60_sp = OO48_sp; + OO44_sp = OO60_sp; + v0 = OO60_sp + 1; + OO48_sp = v0; + } + } + //Stream stream_out = new MemoryStream(f_out_bytes.ToArray()); + //return stream_out; + } + } +} diff --git a/ArcFormats/MAGES/ArcARC20.cs b/ArcFormats/MAGES/ArcARC20.cs index a8c3f1cd..9c7a16c5 100644 --- a/ArcFormats/MAGES/ArcARC20.cs +++ b/ArcFormats/MAGES/ArcARC20.cs @@ -11,7 +11,7 @@ namespace GameRes.Formats.MAGES public override string Tag { get { return "ARC/Princess Soft ARC20"; } } public override string Description { get { return "Princess Soft PS2 resource archive"; } } public override uint Signature { get { return 0x20435241; } } // 'ARC\x20' - public override bool IsHierarchic { get { return false; } } + public override bool IsHierarchic { get { return true; } } public override bool CanWrite { get { return false; } } public override ArcFile TryOpen(ArcView file) diff --git a/ArcFormats/Properties/Settings.Designer.cs b/ArcFormats/Properties/Settings.Designer.cs index f22c61a8..4bad779b 100644 --- a/ArcFormats/Properties/Settings.Designer.cs +++ b/ArcFormats/Properties/Settings.Designer.cs @@ -837,5 +837,17 @@ namespace GameRes.Formats.Properties { this["NexasEncodingCP"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("RGBA")] + public string TIM2AlphaFormat { + get { + return ((string)(this["TIM2AlphaFormat"])); + } + set { + this["TIM2AlphaFormat"] = value; + } + } } } diff --git a/ArcFormats/Properties/Settings.settings b/ArcFormats/Properties/Settings.settings index a6aa5543..50457412 100644 --- a/ArcFormats/Properties/Settings.settings +++ b/ArcFormats/Properties/Settings.settings @@ -206,5 +206,8 @@ 932 + + RGBA + \ No newline at end of file diff --git a/ArcFormats/Strings/arcStrings.Designer.cs b/ArcFormats/Strings/arcStrings.Designer.cs index c42b4340..accb3959 100644 --- a/ArcFormats/Strings/arcStrings.Designer.cs +++ b/ArcFormats/Strings/arcStrings.Designer.cs @@ -752,6 +752,16 @@ namespace GameRes.Formats.Strings { } } + /// + /// Looks up a localized string similar to Choose Tim2 image alpha format. + /// It can't be read correctly from the file. + /// + public static string Tim2AlphaFormat { + get { + return ResourceManager.GetString("Tim2AlphaFormat", resourceCulture); + } + } + /// /// Looks up a localized string similar to Hex number. /// diff --git a/ArcFormats/Strings/arcStrings.ja-JP.resx b/ArcFormats/Strings/arcStrings.ja-JP.resx index 09cb1f5f..ea90ba37 100644 --- a/ArcFormats/Strings/arcStrings.ja-JP.resx +++ b/ArcFormats/Strings/arcStrings.ja-JP.resx @@ -501,4 +501,8 @@ Choose encryption scheme or enter a passphrase. Default audio sampling rate + + Tim2画像のAlpha形式を選択してください。 +ファイルから正しく読み取ることができません。 + \ No newline at end of file diff --git a/ArcFormats/Strings/arcStrings.resx b/ArcFormats/Strings/arcStrings.resx index 435a145e..8543086c 100644 --- a/ArcFormats/Strings/arcStrings.resx +++ b/ArcFormats/Strings/arcStrings.resx @@ -401,4 +401,8 @@ Choose encryption scheme or enter a passphrase. Default audio sampling rate + + Choose Tim2 image alpha format. +It can't be read correctly from the file. + \ No newline at end of file diff --git a/ArcFormats/Strings/arcStrings.zh-Hans.resx b/ArcFormats/Strings/arcStrings.zh-Hans.resx index 97a8a221..056eb3ec 100644 --- a/ArcFormats/Strings/arcStrings.zh-Hans.resx +++ b/ArcFormats/Strings/arcStrings.zh-Hans.resx @@ -399,4 +399,8 @@ 默认音频采样率 + + 选择Tim2图片透明度格式。 +这无法从文件中正确获取。 + \ No newline at end of file diff --git a/ArcFormats/app.config b/ArcFormats/app.config index eb7f9ea8..ef1cc161 100644 --- a/ArcFormats/app.config +++ b/ArcFormats/app.config @@ -208,6 +208,9 @@ 932 + + RGBA + diff --git a/GameRes/Image.cs b/GameRes/Image.cs index f52ce64c..da5e4105 100644 --- a/GameRes/Image.cs +++ b/GameRes/Image.cs @@ -71,6 +71,8 @@ namespace GameRes BgrX = 6, RgbA = 9, BgrA = 10, + RgbA7 = 55, + BgrA7 = 66, } public class ImageData @@ -124,7 +126,8 @@ namespace GameRes public static ImageData Create (ImageMetaData info, PixelFormat format, BitmapPalette palette, Array pixel_data) { - return Create (info, format, palette, pixel_data, (int)info.Width*((format.BitsPerPixel+7)/8)); + return Create (info, format, palette, pixel_data, + format.BitsPerPixel == 4 ? (int)info.Width*format.BitsPerPixel/8 : (int)info.Width*((format.BitsPerPixel+7)/8)); } public static ImageData CreateFlipped (ImageMetaData info, PixelFormat format, BitmapPalette palette, @@ -215,12 +218,16 @@ namespace GameRes Func get_color; if (PaletteFormat.Bgr == format || PaletteFormat.BgrX == format) get_color = x => Color.FromRgb (palette_data[x+2], palette_data[x+1], palette_data[x]); + else if (PaletteFormat.BgrA7 == format) + get_color = x => Color.FromArgb(palette_data[x+3] >= byte.MaxValue / 2 ? byte.MaxValue : (byte)(palette_data[x+3] << 1), palette_data[x+2], palette_data[x+1], palette_data[x]); else if (PaletteFormat.BgrA == format) get_color = x => Color.FromArgb (palette_data[x+3], palette_data[x+2], palette_data[x+1], palette_data[x]); else if (PaletteFormat.RgbA == format) get_color = x => Color.FromArgb (palette_data[x+3], palette_data[x], palette_data[x+1], palette_data[x+2]); + else if (PaletteFormat.RgbA7 == format) + get_color = x => Color.FromArgb (palette_data[x+3] >= byte.MaxValue / 2 ? byte.MaxValue : (byte)(palette_data[x+3] << 1), palette_data[x], palette_data[x+1], palette_data[x+2]); else - get_color = x => Color.FromRgb (palette_data[x], palette_data[x+1], palette_data[x+2]); + get_color = x => Color.FromRgb (palette_data[x], palette_data[x+1], palette_data[x+2]); for (int i = 0; i < colors; ++i) {