mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-23 13:45:34 +08:00
updated legacy formats.
(BIZ): moved to Adviz folder. (GIZ, GIZ2, BIZ2, PR1): new PC-98 image formats. (DATA, BGM, SED): MyHarvest resource formats. (HTF): compressed image format. (PAK): Mina resource archives. (GCmp): read palette from external resource. (NCG): Nekotaro image format. (BND, TCZ, TSZ): Ponytail Soft PC-98 formats. (NOR): Sophia resource archive. (SDA, PLA): Squadra D resource archives. (UCA): added checks to avoid false positives.
This commit is contained in:
parent
4d26cdcff6
commit
f90e2e851c
366
Legacy/Adviz/ImageBIZ.cs
Normal file
366
Legacy/Adviz/ImageBIZ.cs
Normal file
@ -0,0 +1,366 @@
|
||||
//! \file ImageBIZ.cs
|
||||
//! \date 2023 Sep 30
|
||||
//! \brief ADVIZ engine image format.
|
||||
//
|
||||
// Copyright (C) 2023 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 System.Text.RegularExpressions;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
// [970829][Ange] Coin
|
||||
|
||||
namespace GameRes.Formats.Adviz
|
||||
{
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class BizFormat : ImageFormat
|
||||
{
|
||||
public override string Tag => "BIZ";
|
||||
public override string Description => "ADVIZ engine image format";
|
||||
public override uint Signature => 0;
|
||||
|
||||
const byte DefaultKey = 0x39;
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
if (!file.Name.HasExtension (".BIZ"))
|
||||
return null;
|
||||
var header = file.ReadHeader (4);
|
||||
uint width = header.ToUInt16 (0);
|
||||
uint height = header.ToUInt16 (2);
|
||||
if (width * height + 4 != file.Length)
|
||||
return null;
|
||||
return new ImageMetaData {
|
||||
Width = width,
|
||||
Height = height,
|
||||
BPP = 8,
|
||||
};
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
var palette = ReadPalette (file.Name, 0x300, (pal, off) => ReadPalette (pal, off, 0x100, PaletteFormat.Rgb));
|
||||
if (null == palette)
|
||||
throw new FileNotFoundException ("Unable to retrieve palette.");
|
||||
file.Position = 4;
|
||||
var pixels = file.ReadBytes (info.iWidth * info.iHeight);
|
||||
byte key = DefaultKey;
|
||||
for (int i = 0; i < pixels.Length; ++i)
|
||||
{
|
||||
pixels[i] ^= key;
|
||||
key += pixels[i];
|
||||
}
|
||||
return ImageData.CreateFlipped (info, PixelFormats.Indexed8, palette, pixels, info.iWidth);
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("BizFormat.Write not implemented");
|
||||
}
|
||||
|
||||
internal delegate BitmapPalette PaletteReader (ArcView file, int offset);
|
||||
|
||||
static readonly Regex TachieRe = new Regex (@"^(T[^._]+_)[2-9][^.]*\.GIZ$", RegexOptions.Compiled);
|
||||
|
||||
internal static BitmapPalette ReadPalette (string base_name, int pal_size, PaletteReader read_pal)
|
||||
{
|
||||
var dir_name = Path.GetDirectoryName (base_name);
|
||||
var grp_tbl_name = Path.Combine (dir_name, @"..\GRP_TBL.SYS");
|
||||
var plt_tbl_name = Path.Combine (dir_name, @"..\PLT_TBL.SYS");
|
||||
if (!File.Exists (grp_tbl_name) || !File.Exists (plt_tbl_name))
|
||||
return null;
|
||||
int index = 0;
|
||||
uint grp_size = 0;
|
||||
base_name = Path.GetFileName (base_name).ToUpperInvariant();
|
||||
var name = base_name;
|
||||
var ext = Path.GetExtension (name).TrimStart('.');
|
||||
var match = TachieRe.Match (name);
|
||||
if (match.Success)
|
||||
name = match.Groups[1].Value + "1";
|
||||
else
|
||||
name = Path.GetFileNameWithoutExtension (name);
|
||||
if (name.Length < 8)
|
||||
name += ' ';
|
||||
using (var grp = new ArcView (grp_tbl_name))
|
||||
{
|
||||
grp_size = (uint)grp.MaxOffset;
|
||||
int pos = 0;
|
||||
while (pos + 12 <= grp.MaxOffset)
|
||||
{
|
||||
if (grp.View.AsciiEqual (pos, name) &&
|
||||
grp.View.AsciiEqual (pos+8, ext))
|
||||
{
|
||||
break;
|
||||
}
|
||||
++index;
|
||||
pos += 12;
|
||||
}
|
||||
if (pos >= grp.MaxOffset)
|
||||
return null;
|
||||
}
|
||||
using (var pal = new ArcView (plt_tbl_name))
|
||||
{
|
||||
uint plt_size = (uint)pal.MaxOffset;
|
||||
var id = new GrpIdentifier (grp_size, plt_size);
|
||||
IGrpMapper mapper;
|
||||
if (!GrpMap.TryGetValue (id, out mapper))
|
||||
mapper = new DirectMapper();
|
||||
index = mapper.GetPaletteIndex (index, base_name);
|
||||
int pal_offset = index * pal_size;
|
||||
if (pal_offset + pal_size > pal.MaxOffset)
|
||||
{
|
||||
int count = (int)(pal.MaxOffset / pal_size) - 1;
|
||||
pal_offset = count * pal_size;
|
||||
}
|
||||
return read_pal (pal, pal_offset);
|
||||
}
|
||||
}
|
||||
|
||||
static readonly Dictionary<GrpIdentifier, IGrpMapper> GrpMap = new Dictionary<GrpIdentifier, IGrpMapper> {
|
||||
{ new GrpIdentifier (1584, 139008), new GrpShiftMapper (52) },
|
||||
{ new GrpIdentifier (2160, 12288),
|
||||
new GrpNameMapper { NameMap = new Dictionary<string, int> {
|
||||
{ "BG01.BIZ", 14 },
|
||||
{ "BG02.BIZ", 8 },
|
||||
{ "BG03.BIZ", 8 },
|
||||
{ "BG04.BIZ", 8 },
|
||||
{ "BG05.BIZ", 8 },
|
||||
{ "BG06.BIZ", 8 },
|
||||
{ "BG07.BIZ", 8 },
|
||||
{ "BG08.BIZ", 8 },
|
||||
{ "BG09.BIZ", 8 },
|
||||
{ "BG10.BIZ", 8 },
|
||||
{ "BG11.BIZ", 8 },
|
||||
{ "BG12.BIZ", 8 },
|
||||
{ "BG13.BIZ", 8 },
|
||||
{ "BG14.BIZ", 8 },
|
||||
{ "BG15.BIZ", 8 },
|
||||
{ "BG16.BIZ", 8 },
|
||||
{ "BG17.BIZ", 8 },
|
||||
{ "BG18.BIZ", 8 },
|
||||
{ "BG19.BIZ", 8 },
|
||||
{ "CA01.BIZ", 12 },
|
||||
{ "CA02.BIZ", 12 },
|
||||
{ "CA03.BIZ", 4 },
|
||||
{ "CA04.BIZ", 8 },
|
||||
{ "CA05.BIZ", 8 },
|
||||
{ "CA06.BIZ", 8 },
|
||||
{ "CA07.BIZ", 8 },
|
||||
{ "CA08.BIZ", 8 },
|
||||
{ "CA09.BIZ", 8 },
|
||||
{ "CA10.BIZ", 8 },
|
||||
{ "CA11.BIZ", 8 },
|
||||
{ "CA12.BIZ", 8 },
|
||||
{ "CA13.BIZ", 8 },
|
||||
{ "CA14.BIZ", 8 },
|
||||
{ "CA15.BIZ", 8 },
|
||||
{ "CA16.BIZ", 8 },
|
||||
{ "CA17.BIZ", 8 },
|
||||
{ "CA18.BIZ", 8 },
|
||||
{ "CA19.BIZ", 8 },
|
||||
{ "CA20.BIZ", 8 },
|
||||
{ "CA21.BIZ", 8 },
|
||||
{ "CA22.BIZ", 8 },
|
||||
{ "CA23.BIZ", 8 },
|
||||
{ "CA24.BIZ", 8 },
|
||||
{ "CA25.BIZ", 8 },
|
||||
{ "CA26.BIZ", 8 },
|
||||
{ "CA27.BIZ", 8 },
|
||||
{ "CA28.BIZ", 8 },
|
||||
{ "CA29.BIZ", 8 },
|
||||
{ "CA30.BIZ", 8 },
|
||||
{ "CA31.BIZ", 8 },
|
||||
{ "CA32.BIZ", 8 },
|
||||
{ "CA33.BIZ", 8 },
|
||||
{ "CA34.BIZ", 8 },
|
||||
{ "CA35.BIZ", 8 },
|
||||
{ "CA36.BIZ", 8 },
|
||||
{ "CA37.BIZ", 8 },
|
||||
{ "CA38.BIZ", 8 },
|
||||
{ "CA39.BIZ", 8 },
|
||||
{ "CA40.BIZ", 8 },
|
||||
{ "CA41.BIZ", 8 },
|
||||
{ "CA42.BIZ", 8 },
|
||||
{ "CA43.BIZ", 8 },
|
||||
{ "CA44.BIZ", 8 },
|
||||
{ "CA45.BIZ", 8 },
|
||||
{ "CA46.BIZ", 8 },
|
||||
{ "CA47.BIZ", 8 },
|
||||
{ "CA48.BIZ", 8 },
|
||||
{ "CA49.BIZ", 8 },
|
||||
{ "CA50.BIZ", 8 },
|
||||
{ "CA51.BIZ", 8 },
|
||||
{ "CA52.BIZ", 8 },
|
||||
{ "CA53.BIZ", 8 },
|
||||
{ "CA54.BIZ", 8 },
|
||||
{ "CA55.BIZ", 8 },
|
||||
{ "CA56.BIZ", 8 },
|
||||
{ "CA57.BIZ", 8 },
|
||||
{ "CA58.BIZ", 8 },
|
||||
{ "CA59.BIZ", 8 },
|
||||
{ "CA60.BIZ", 8 },
|
||||
{ "E02.BIZ", 8 },
|
||||
{ "E03.BIZ", 8 },
|
||||
{ "E04.BIZ", 8 },
|
||||
{ "E05.BIZ", 8 },
|
||||
{ "E06.BIZ", 8 },
|
||||
{ "E07.BIZ", 8 },
|
||||
{ "E08.BIZ", 8 },
|
||||
{ "E09.BIZ", 8 },
|
||||
{ "E10.BIZ", 8 },
|
||||
{ "E11.BIZ", 8 },
|
||||
{ "E12.BIZ", 8 },
|
||||
{ "E13.BIZ", 8 },
|
||||
{ "E14.BIZ", 8 },
|
||||
{ "E15.BIZ", 8 },
|
||||
{ "E16.BIZ", 8 },
|
||||
{ "E17.BIZ", 8 },
|
||||
{ "E18.BIZ", 8 },
|
||||
{ "END.BIZ", 6 },
|
||||
{ "IPL.BIZ", 12 },
|
||||
{ "S01.BIZ", 8 },
|
||||
{ "S02.BIZ", 8 },
|
||||
{ "S03.BIZ", 8 },
|
||||
{ "S04.BIZ", 8 },
|
||||
{ "S05.BIZ", 8 },
|
||||
{ "S06.BIZ", 8 },
|
||||
{ "S07.BIZ", 8 },
|
||||
{ "S08.BIZ", 8 },
|
||||
{ "S09.BIZ", 8 },
|
||||
{ "S10.BIZ", 8 },
|
||||
{ "S11.BIZ", 8 },
|
||||
{ "S12.BIZ", 8 },
|
||||
{ "S13.BIZ", 8 },
|
||||
{ "S14.BIZ", 8 },
|
||||
{ "S15.BIZ", 8 },
|
||||
{ "S16.BIZ", 8 },
|
||||
{ "S17.BIZ", 8 },
|
||||
{ "S18.BIZ", 8 },
|
||||
{ "S19.BIZ", 8 },
|
||||
{ "S20.BIZ", 8 },
|
||||
{ "S21.BIZ", 8 },
|
||||
{ "S22.BIZ", 8 },
|
||||
{ "S23.BIZ", 8 },
|
||||
{ "S24.BIZ", 8 },
|
||||
{ "S25.BIZ", 8 },
|
||||
{ "S26.BIZ", 8 },
|
||||
{ "S27.BIZ", 8 },
|
||||
{ "S28.BIZ", 8 },
|
||||
{ "S29.BIZ", 8 },
|
||||
{ "S30.BIZ", 8 },
|
||||
{ "S31.BIZ", 8 },
|
||||
{ "S32.BIZ", 8 },
|
||||
{ "S33.BIZ", 8 },
|
||||
{ "S34.BIZ", 8 },
|
||||
{ "S35.BIZ", 8 },
|
||||
{ "S36.BIZ", 8 },
|
||||
{ "S37.BIZ", 8 },
|
||||
{ "S38.BIZ", 8 },
|
||||
{ "S39.BIZ", 8 },
|
||||
{ "S40.BIZ", 8 },
|
||||
{ "S41.BIZ", 8 },
|
||||
{ "S42.BIZ", 8 },
|
||||
{ "S43.BIZ", 8 },
|
||||
{ "S44.BIZ", 8 },
|
||||
{ "S45.BIZ", 8 },
|
||||
{ "S46.BIZ", 8 },
|
||||
{ "S47.BIZ", 8 },
|
||||
{ "S48.BIZ", 8 },
|
||||
{ "S49.BIZ", 8 },
|
||||
{ "T01.BIZ", 8 },
|
||||
{ "T02.BIZ", 8 },
|
||||
{ "T03.BIZ", 8 },
|
||||
{ "WAKU1.BIZ", 8 },
|
||||
{ "WAKU2.BIZ", 8 },
|
||||
} } },
|
||||
};
|
||||
}
|
||||
|
||||
public struct GrpIdentifier
|
||||
{
|
||||
public uint GrpSize;
|
||||
public uint PltSize;
|
||||
|
||||
public GrpIdentifier (uint grp_size, uint plt_size)
|
||||
{
|
||||
GrpSize = grp_size;
|
||||
PltSize = plt_size;
|
||||
}
|
||||
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
return (int)((GrpSize + 1) * (PltSize + 1));
|
||||
}
|
||||
|
||||
public override bool Equals (object obj)
|
||||
{
|
||||
if (null == obj)
|
||||
return false;
|
||||
var other = (GrpIdentifier)obj;
|
||||
return this.GrpSize == other.GrpSize && this.PltSize == other.PltSize;
|
||||
}
|
||||
}
|
||||
|
||||
internal interface IGrpMapper
|
||||
{
|
||||
int GetPaletteIndex (int id, string name);
|
||||
}
|
||||
|
||||
internal class DirectMapper : IGrpMapper
|
||||
{
|
||||
public int GetPaletteIndex (int id, string name)
|
||||
{
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
internal class GrpShiftMapper : IGrpMapper
|
||||
{
|
||||
int m_shift;
|
||||
|
||||
public GrpShiftMapper (int shift)
|
||||
{
|
||||
m_shift = shift;
|
||||
}
|
||||
|
||||
public int GetPaletteIndex (int id, string name)
|
||||
{
|
||||
return id + m_shift;
|
||||
}
|
||||
}
|
||||
|
||||
internal class GrpNameMapper : IGrpMapper
|
||||
{
|
||||
public Dictionary<string, int> NameMap;
|
||||
|
||||
public int GetPaletteIndex (int id, string name)
|
||||
{
|
||||
int index;
|
||||
if (NameMap.TryGetValue (name, out index))
|
||||
return index;
|
||||
return id;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
//! \file ImageBIZ.cs
|
||||
//! \file ImageBIZ2.cs
|
||||
//! \date 2018 Feb 11
|
||||
//! \brief Sorciere compressed image.
|
||||
//! \brief ADVIZ engine compressed image.
|
||||
//
|
||||
// Copyright (C) 2018 by morkt
|
||||
//
|
||||
@ -29,14 +29,15 @@ using System.Windows.Media;
|
||||
using GameRes.Compression;
|
||||
|
||||
// [000225][Sorciere] Karei
|
||||
// [011012][Ange] Nyuunyuu
|
||||
|
||||
namespace GameRes.Formats.Sorciere
|
||||
namespace GameRes.Formats.Adviz
|
||||
{
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class BizFormat : ImageFormat
|
||||
public class Biz2Format : ImageFormat
|
||||
{
|
||||
public override string Tag { get { return "BIZ"; } }
|
||||
public override string Description { get { return "Sorciere compressed image"; } }
|
||||
public override string Tag { get { return "BIZ/2"; } }
|
||||
public override string Description { get { return "ADVIZ engine compressed image"; } }
|
||||
public override uint Signature { get { return 0x325A4942; } } // 'BIZ2'
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
@ -52,13 +53,34 @@ namespace GameRes.Formats.Sorciere
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
file.Position = 8;
|
||||
using (var input = new LzssStream (file.AsStream, LzssMode.Decompress, true))
|
||||
using (var lzss = new LzssStream (file.AsStream, LzssMode.Decompress, true))
|
||||
using (var input = new BinaryStream (lzss, file.Name))
|
||||
{
|
||||
int stride = (int)info.Width * 3;
|
||||
var pixels = new byte[stride * (int)info.Height];
|
||||
if (pixels.Length != input.Read (pixels, 0, pixels.Length))
|
||||
int stride = info.iWidth * 3;
|
||||
var rgb = new byte[stride * info.Height];
|
||||
if (rgb.Length != input.Read (rgb, 0, rgb.Length))
|
||||
throw new InvalidFormatException();
|
||||
return ImageData.CreateFlipped (info, PixelFormats.Bgr24, null, pixels, stride);
|
||||
if (input.PeekByte() != -1) // possible alpha channel
|
||||
{
|
||||
var alpha = input.ReadBytes (rgb.Length);
|
||||
if (alpha.Length == rgb.Length)
|
||||
{
|
||||
int stride32bpp = info.iWidth * 4;
|
||||
var rgba = new byte[stride32bpp * info.iHeight];
|
||||
int src = 0;
|
||||
int dst = 0;
|
||||
while (src < rgb.Length)
|
||||
{
|
||||
rgba[dst++] = rgb[src ];
|
||||
rgba[dst++] = rgb[src+1];
|
||||
rgba[dst++] = rgb[src+2];
|
||||
rgba[dst++] = alpha[src]; // presumably it's grayscale and R/G/B values are equal
|
||||
src += 3;
|
||||
}
|
||||
return ImageData.CreateFlipped (info, PixelFormats.Bgra32, null, rgba, stride32bpp);
|
||||
}
|
||||
}
|
||||
return ImageData.CreateFlipped (info, PixelFormats.Bgr24, null, rgb, stride);
|
||||
}
|
||||
}
|
||||
|
309
Legacy/Adviz/ImageGIZ.cs
Normal file
309
Legacy/Adviz/ImageGIZ.cs
Normal file
@ -0,0 +1,309 @@
|
||||
//! \file ImageGIZ.cs
|
||||
//! \date 2023 Oct 02
|
||||
//! \brief ADVIZ engine image format (PC-98).
|
||||
//
|
||||
// Copyright (C) 2023 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 GameRes.Utility;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
// [960830][Ange] Coin
|
||||
|
||||
namespace GameRes.Formats.Adviz
|
||||
{
|
||||
internal class GizMetaData : ImageMetaData
|
||||
{
|
||||
public byte RleCode;
|
||||
public byte PlaneMap;
|
||||
public bool HasPalette;
|
||||
}
|
||||
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class Giz3Format : ImageFormat
|
||||
{
|
||||
public override string Tag => "GIZ";
|
||||
public override string Description => "ADVIZ engine image format";
|
||||
public override uint Signature => 0x335A4947; // 'GIZ3'
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
var header = file.ReadHeader (0x10);
|
||||
int xy = header.ToUInt16 (4);
|
||||
return new GizMetaData {
|
||||
Width = (uint)header.ToUInt16 (6) << 3,
|
||||
Height = header.ToUInt16 (8),
|
||||
OffsetX = (xy % 0x50) << 3,
|
||||
OffsetY = xy / 0x50,
|
||||
HasPalette = header[0xC] != 0,
|
||||
PlaneMap = header[0xE],
|
||||
BPP = 4,
|
||||
};
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
var reader = new Giz3Reader (file, (GizMetaData)info);
|
||||
return reader.Unpack();
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("Giz3Format.Write not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
internal class Giz3Reader
|
||||
{
|
||||
IBinaryStream m_input;
|
||||
GizMetaData m_info;
|
||||
BitmapPalette m_palette;
|
||||
int m_stride;
|
||||
int m_output_stride;
|
||||
|
||||
public Giz3Reader (IBinaryStream input, GizMetaData info)
|
||||
{
|
||||
m_input = input;
|
||||
m_info = info;
|
||||
}
|
||||
|
||||
byte[] m_buffer;
|
||||
byte[] m_output;
|
||||
|
||||
public ImageData Unpack ()
|
||||
{
|
||||
m_input.Position = 0x10;
|
||||
if (m_info.HasPalette)
|
||||
m_palette = ReadPalette();
|
||||
else
|
||||
m_palette = BitmapPalettes.Gray16; // palette is stored somewhere else
|
||||
long data_pos = m_input.Position;
|
||||
ReadHuffmanTree();
|
||||
data_pos += m_dataOffset;
|
||||
|
||||
m_bitCount = 1;
|
||||
m_stride = m_info.iWidth >> 3;
|
||||
m_buffer = new byte[0x2000];
|
||||
m_output_stride = m_info.iWidth >> 1;
|
||||
m_output = new byte[m_output_stride * m_info.iHeight];
|
||||
m_input.Position = data_pos;
|
||||
UnpackBits();
|
||||
return ImageData.Create (m_info, PixelFormats.Indexed4, m_palette, m_output, m_output_stride);
|
||||
}
|
||||
|
||||
int m_dataOffset;
|
||||
int m_gizColumn;
|
||||
int m_outputPos1;
|
||||
int m_outputPos2;
|
||||
|
||||
void UnpackBits () // sub_15426
|
||||
{
|
||||
m_gizColumn = 0;
|
||||
m_outputPos1 = 0;
|
||||
m_outputPos2 = 0;
|
||||
int dst = 0;
|
||||
for (int x = 0; x < m_stride; ++x)
|
||||
{
|
||||
int src1 = m_outputPos1;
|
||||
int src2 = 0;
|
||||
for (int j = 0; j < 2; ++j)
|
||||
{
|
||||
src2 = m_outputPos1;
|
||||
int plane_mask = 1;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if ((m_info.PlaneMap & plane_mask) == 0)
|
||||
{
|
||||
UnpackPlane (m_outputPos1);
|
||||
}
|
||||
plane_mask <<= 1;
|
||||
m_outputPos1 += 0x800;
|
||||
m_outputPos2 += 0x800;
|
||||
}
|
||||
m_gizColumn = (m_gizColumn + 1) & 3;
|
||||
m_outputPos1 = m_gizColumn << 9;
|
||||
m_outputPos2 = 0;
|
||||
}
|
||||
CopyPlanes (src1, src2, dst);
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void CopyPlanes (int src1, int src2, int dst)
|
||||
{
|
||||
for (int y = 0; y < m_info.iHeight; ++y)
|
||||
{
|
||||
int b0 = m_buffer[src1+y ] << 4 | m_buffer[src2+y ];
|
||||
int b1 = m_buffer[src1+y+0x0800] << 4 | m_buffer[src2+y+0x0800];
|
||||
int b2 = m_buffer[src1+y+0x1000] << 4 | m_buffer[src2+y+0x1000];
|
||||
int b3 = m_buffer[src1+y+0x1800] << 4 | m_buffer[src2+y+0x1800];
|
||||
for (int j = 0; j < 8; j += 2)
|
||||
{
|
||||
byte px = (byte)((((b0 << j) & 0x80) >> 3)
|
||||
| (((b1 << j) & 0x80) >> 2)
|
||||
| (((b2 << j) & 0x80) >> 1)
|
||||
| (((b3 << j) & 0x80) ));
|
||||
px |= (byte)((((b0 << j) & 0x40) >> 6)
|
||||
| (((b1 << j) & 0x40) >> 5)
|
||||
| (((b2 << j) & 0x40) >> 4)
|
||||
| (((b3 << j) & 0x40) >> 3));
|
||||
m_output[dst+j/2] = px;
|
||||
}
|
||||
dst += m_output_stride;
|
||||
}
|
||||
}
|
||||
|
||||
int m_root;
|
||||
ushort[] m_treeTable;
|
||||
|
||||
void ReadHuffmanTree ()
|
||||
{
|
||||
m_dataOffset = m_input.ReadUInt16();
|
||||
m_treeTable = new ushort[(m_dataOffset-2) * 2 / 3 + 1];
|
||||
int di = 0;
|
||||
for (int si = 2; si + 2 < m_dataOffset; si += 3)
|
||||
{
|
||||
ushort bx = m_input.ReadUInt16();
|
||||
int ax = bx & 0xFFF;
|
||||
if ((ax & 0x800) == 0)
|
||||
ax = (ax - 2) >> 1;
|
||||
m_treeTable[di++] = (ushort)ax;
|
||||
ax = m_input.ReadUInt8() << 4;
|
||||
ax |= bx >> 12;
|
||||
if ((ax & 0x800) == 0)
|
||||
ax = (ax - 2) >> 1;
|
||||
m_treeTable[di++] = (ushort)ax;
|
||||
}
|
||||
m_root = di - 2;
|
||||
}
|
||||
|
||||
byte ReadToken ()
|
||||
{
|
||||
int token = m_root;
|
||||
do
|
||||
{
|
||||
if (GetNextBit())
|
||||
++token;
|
||||
token = m_treeTable[token];
|
||||
}
|
||||
while ((token & 0x800) == 0);
|
||||
return (byte)token;
|
||||
}
|
||||
|
||||
void UnpackPlane (int dst)
|
||||
{
|
||||
int y = 0;
|
||||
while (y < m_info.iHeight)
|
||||
{
|
||||
byte ctl = ReadToken();
|
||||
if (ctl < 0x10)
|
||||
{
|
||||
m_buffer[dst++] = ctl;
|
||||
++y;
|
||||
}
|
||||
else
|
||||
{
|
||||
int count = ReadToken() + 2;
|
||||
ctl -= 0x10;
|
||||
switch (ctl)
|
||||
{
|
||||
case 0:
|
||||
for (int i = 0; i < count; ++i)
|
||||
m_buffer[dst+i] = 0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
for (int i = 0; i < count; ++i)
|
||||
m_buffer[dst+i] = 0xF;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
Binary.CopyOverlapped (m_buffer, dst-1, dst, count);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
Binary.CopyOverlapped (m_buffer, dst-2, dst, count);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
{
|
||||
int off = (ctl - 3) << 11;
|
||||
Binary.CopyOverlapped (m_buffer, dst-off, dst, count);
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
int src = dst - m_outputPos1;
|
||||
int ax = (m_gizColumn - 1) & 3;
|
||||
src += (ax << 9) + m_outputPos2;
|
||||
Binary.CopyOverlapped (m_buffer, src, dst, count);
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
int src = dst - m_outputPos1;
|
||||
int ax = (m_gizColumn - 2) & 3;
|
||||
src += (ax << 9) + m_outputPos2;
|
||||
Binary.CopyOverlapped (m_buffer, src, dst, count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
dst += count;
|
||||
y += count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BitmapPalette ReadPalette ()
|
||||
{
|
||||
const int count = 16;
|
||||
var colors = new Color[count];
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
byte b = m_input.ReadUInt8();
|
||||
byte r = m_input.ReadUInt8();
|
||||
byte g = m_input.ReadUInt8();
|
||||
colors[i] = Color.FromRgb ((byte)(r * 0x11), (byte)(g * 0x11), (byte)(b * 0x11));
|
||||
}
|
||||
return new BitmapPalette (colors);
|
||||
}
|
||||
|
||||
int m_bitCount;
|
||||
int m_bits;
|
||||
|
||||
bool GetNextBit ()
|
||||
{
|
||||
if (--m_bitCount == 0)
|
||||
{
|
||||
m_bits = m_input.ReadUInt16();
|
||||
m_bitCount = 16;
|
||||
}
|
||||
bool bit = (m_bits & 0x8000) != 0;
|
||||
m_bits <<= 1;
|
||||
return bit;
|
||||
}
|
||||
}
|
||||
}
|
231
Legacy/Adviz/ImageGIZ2.cs
Normal file
231
Legacy/Adviz/ImageGIZ2.cs
Normal file
@ -0,0 +1,231 @@
|
||||
//! \file ImageGIZ2.cs
|
||||
//! \date 2023 Oct 02
|
||||
//! \brief ADVIZ engine image format (PC-98).
|
||||
//
|
||||
// Copyright (C) 2023 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 GameRes.Utility;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
// [951027][Ange] Leap Toki ni Sarawareta Shoujo
|
||||
|
||||
namespace GameRes.Formats.Adviz
|
||||
{
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class GizFormat : ImageFormat
|
||||
{
|
||||
public override string Tag => "GIZ/2";
|
||||
public override string Description => "ADVIZ engine image format";
|
||||
public override uint Signature => 0x325A4947; // 'GIZ2'
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
var header = file.ReadHeader (0x10);
|
||||
int xy = header.ToUInt16 (4);
|
||||
return new GizMetaData {
|
||||
Width = (uint)header.ToUInt16 (6) << 3,
|
||||
Height = header.ToUInt16 (8),
|
||||
OffsetX = (xy % 0x50) << 3,
|
||||
OffsetY = xy / 0x50,
|
||||
RleCode = header[0xC],
|
||||
PlaneMap = header[0xE],
|
||||
BPP = 4,
|
||||
};
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
var reader = new Giz2Reader (file, (GizMetaData)info);
|
||||
return reader.Unpack();
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("GizFormat.Write not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
internal class Giz2Reader
|
||||
{
|
||||
IBinaryStream m_input;
|
||||
GizMetaData m_info;
|
||||
BitmapPalette m_palette;
|
||||
|
||||
public BitmapPalette Palette => m_palette;
|
||||
|
||||
public Giz2Reader (IBinaryStream input, GizMetaData info)
|
||||
{
|
||||
m_input = input;
|
||||
m_info = info;
|
||||
}
|
||||
|
||||
int m_stride;
|
||||
byte[][] m_planes;
|
||||
int m_output_stride;
|
||||
byte[] m_output;
|
||||
|
||||
public ImageData Unpack ()
|
||||
{
|
||||
m_palette = BizFormat.ReadPalette (m_input.Name, 0x30, (pal, off) => ReadPalette (pal, off));
|
||||
if (null == m_palette)
|
||||
{
|
||||
// m_palette = BitmapPalettes.Gray16;
|
||||
throw new FileNotFoundException ("Unable to retrieve palette.");
|
||||
}
|
||||
m_input.Position = 0x10;
|
||||
m_stride = m_info.iWidth >> 3;
|
||||
int plane_size = m_info.iHeight;
|
||||
m_planes = new byte[][] {
|
||||
new byte[plane_size], new byte[plane_size], new byte[plane_size], new byte[plane_size],
|
||||
};
|
||||
m_output_stride = m_info.iWidth >> 1;
|
||||
m_output = new byte[m_output_stride * m_info.iHeight];
|
||||
int dst = 0;
|
||||
for (int x = 0; x < m_stride; ++x)
|
||||
{
|
||||
int plane_mask = 1;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if ((m_info.PlaneMap & plane_mask) == 0)
|
||||
UnpackPlane (m_planes[i], 0);
|
||||
plane_mask <<= 1;
|
||||
}
|
||||
CopyPlanes (dst);
|
||||
dst += 4;
|
||||
}
|
||||
return ImageData.Create (m_info, PixelFormats.Indexed4, Palette, m_output, m_output_stride);
|
||||
}
|
||||
|
||||
bool UnpackPlane (byte[] output, int dst)
|
||||
{
|
||||
for (int y = 0; y < m_info.iHeight; )
|
||||
{
|
||||
byte b = m_input.ReadUInt8();
|
||||
int ctl = (b - m_info.RleCode) & 0xFF;
|
||||
if (2 == ctl)
|
||||
{
|
||||
output[dst++] = m_input.ReadUInt8();
|
||||
}
|
||||
else if (ctl < 4)
|
||||
{
|
||||
if (0 == ctl)
|
||||
b = 0;
|
||||
else if (1 == ctl)
|
||||
b = 0xFF;
|
||||
else
|
||||
b = m_input.ReadUInt8();
|
||||
int count = ((m_input.ReadUInt8() - 1) & 0xFF) + 1;
|
||||
y += count;
|
||||
while (count --> 0)
|
||||
{
|
||||
output[dst++] = b;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (ctl < 7)
|
||||
{
|
||||
byte b0 = m_input.ReadUInt8();
|
||||
byte b1 = m_input.ReadUInt8();
|
||||
int count;
|
||||
if (4 == ctl)
|
||||
{
|
||||
count = ((b1 - 1) & 0x7F) + 1;
|
||||
if (b1 < 0x80)
|
||||
b1 = Binary.RotByteL (b0, 1);
|
||||
else
|
||||
b1 = Binary.RotByteR (b0, 1);
|
||||
}
|
||||
else if (5 == ctl)
|
||||
{
|
||||
count = ((b1 - 1) & 0x7F) + 1;
|
||||
if (b1 < 0x80)
|
||||
b1 = Binary.RotByteL (b0, 2);
|
||||
else
|
||||
b1 = Binary.RotByteR (b0, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
count = ((m_input.ReadUInt8() - 1) & 0xFF) + 1;
|
||||
count *= 2;
|
||||
}
|
||||
y += count;
|
||||
do
|
||||
{
|
||||
output[dst++] = b0;
|
||||
if (--count <= 0)
|
||||
break;
|
||||
output[dst++] = b1;
|
||||
}
|
||||
while (--count > 0);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
output[dst++] = b;
|
||||
}
|
||||
++y;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CopyPlanes (int dst)
|
||||
{
|
||||
for (int y = 0; y < m_info.iHeight; ++y)
|
||||
{
|
||||
int b0 = m_planes[0][y];
|
||||
int b1 = m_planes[1][y];
|
||||
int b2 = m_planes[2][y];
|
||||
int b3 = m_planes[3][y];
|
||||
for (int j = 0; j < 8; j += 2)
|
||||
{
|
||||
byte px = (byte)((((b0 << j) & 0x80) >> 3)
|
||||
| (((b1 << j) & 0x80) >> 2)
|
||||
| (((b2 << j) & 0x80) >> 1)
|
||||
| (((b3 << j) & 0x80) ));
|
||||
px |= (byte)((((b0 << j) & 0x40) >> 6)
|
||||
| (((b1 << j) & 0x40) >> 5)
|
||||
| (((b2 << j) & 0x40) >> 4)
|
||||
| (((b3 << j) & 0x40) >> 3));
|
||||
m_output[dst+j/2] = px;
|
||||
}
|
||||
dst += m_output_stride;
|
||||
}
|
||||
}
|
||||
|
||||
BitmapPalette ReadPalette (ArcView file, int offset)
|
||||
{
|
||||
const int count = 16;
|
||||
var colors = new Color[count];
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
byte b = file.View.ReadByte (offset++);
|
||||
byte r = file.View.ReadByte (offset++);
|
||||
byte g = file.View.ReadByte (offset++);
|
||||
colors[i] = Color.FromRgb ((byte)(r * 0x11), (byte)(g * 0x11), (byte)(b * 0x11));
|
||||
}
|
||||
return new BitmapPalette (colors);
|
||||
}
|
||||
}
|
||||
}
|
80
Legacy/Discovery/ImageAN1.cs
Normal file
80
Legacy/Discovery/ImageAN1.cs
Normal file
@ -0,0 +1,80 @@
|
||||
//! \file ImageAN1.cs
|
||||
//! \date 2023 Oct 05
|
||||
//! \brief Discovery animation resource (PC-98).
|
||||
//
|
||||
// Copyright (C) 2023 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.Discovery
|
||||
{
|
||||
//[Export(typeof(ImageFormat))]
|
||||
public class An1Format : Pr1Format
|
||||
{
|
||||
public override string Tag => "AN1";
|
||||
public override string Description => "Discovery animation resource";
|
||||
public override uint Signature => 0;
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
if (!file.Name.HasExtension (".AN1"))
|
||||
return null;
|
||||
return base.ReadMetaData (file);
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
var reader = new AnReader (file, (PrMetaData)info);
|
||||
return reader.Unpack();
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("An1Format.Write not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
internal class AnReader : PrReader
|
||||
{
|
||||
public AnReader (IBinaryStream file, PrMetaData info) : base (file, info)
|
||||
{
|
||||
}
|
||||
|
||||
public new ImageData Unpack ()
|
||||
{
|
||||
UnpackPlanes();
|
||||
int frame_count = m_planes[0].ToUInt16 (2);
|
||||
int frame_width = 0x20;
|
||||
int frame_height = frame_count * 0x20;
|
||||
int output_stride = frame_width >> 1;
|
||||
var output = new byte[output_stride * frame_height];
|
||||
int src = frame_count * 0x16 + 6;
|
||||
m_plane_size = (output_stride >> 2) * frame_height;
|
||||
FlattenPlanes (src, output);
|
||||
Info.Width = (uint)frame_width;
|
||||
Info.Height = (uint)frame_height;
|
||||
return ImageData.Create (Info, PixelFormats.Indexed4, m_palette, output, output_stride);
|
||||
}
|
||||
}
|
||||
}
|
343
Legacy/Discovery/ImagePR1.cs
Normal file
343
Legacy/Discovery/ImagePR1.cs
Normal file
@ -0,0 +1,343 @@
|
||||
//! \file ImagePR1.cs
|
||||
//! \date 2023 Oct 04
|
||||
//! \brief Discovery image format (PC-98).
|
||||
//
|
||||
// Copyright (C) 2023 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;
|
||||
|
||||
namespace GameRes.Formats.Discovery
|
||||
{
|
||||
internal class PrMetaData : ImageMetaData
|
||||
{
|
||||
public byte Flags;
|
||||
public byte Mask;
|
||||
|
||||
public bool IsLeftToRight => (Flags & 1) != 0;
|
||||
}
|
||||
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class Pr1Format : ImageFormat
|
||||
{
|
||||
public override string Tag => "PR1";
|
||||
public override string Description => "Discovery image format";
|
||||
public override uint Signature => 0;
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
if (!file.Name.HasAnyOfExtensions (".PR1", ".AN1"))
|
||||
return null;
|
||||
var header = file.ReadHeader (12);
|
||||
return new PrMetaData {
|
||||
Width = (uint)header.ToUInt16 (8) << 3,
|
||||
Height = header.ToUInt16 (0xA),
|
||||
OffsetX = header.ToUInt16 (2),
|
||||
OffsetY = header.ToUInt16 (4),
|
||||
Flags = header[0],
|
||||
Mask = header[1],
|
||||
BPP = 4,
|
||||
};
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
var reader = new PrReader (file, (PrMetaData)info);
|
||||
return reader.Unpack();
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("Pr1Format.Write not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
internal class PrReader
|
||||
{
|
||||
IBinaryStream m_input;
|
||||
PrMetaData m_info;
|
||||
|
||||
Action IncrementDest;
|
||||
Func<bool> IsDone;
|
||||
|
||||
public PrMetaData Info => m_info;
|
||||
|
||||
public PrReader (IBinaryStream file, PrMetaData info)
|
||||
{
|
||||
m_input = file;
|
||||
m_info = info;
|
||||
if (m_info.IsLeftToRight)
|
||||
{
|
||||
IncrementDest = IncLeftToRight;
|
||||
IsDone = () => m_dst >= m_plane_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
IncrementDest = IncTopToBottom;
|
||||
IsDone = () => m_x >= m_stride;
|
||||
}
|
||||
}
|
||||
|
||||
protected BitmapPalette m_palette;
|
||||
protected int m_stride;
|
||||
protected int m_plane_size;
|
||||
protected byte[][] m_planes;
|
||||
int m_dst;
|
||||
int m_x;
|
||||
|
||||
protected void UnpackPlanes ()
|
||||
{
|
||||
const int buffer_slice = 0x410;
|
||||
m_input.Position = 0xC;
|
||||
m_palette = ReadPalette();
|
||||
m_stride = m_info.iWidth >> 3;
|
||||
m_plane_size = m_stride * m_info.iHeight;
|
||||
m_planes = new byte[][] {
|
||||
new byte[m_plane_size], new byte[m_plane_size], new byte[m_plane_size], new byte[m_plane_size],
|
||||
};
|
||||
var buffer = new byte[buffer_slice * 4];
|
||||
var buf_count = new byte[4];
|
||||
var offsets = new int[] { 0, buffer_slice, buffer_slice*2, buffer_slice*3 };
|
||||
m_dst = 0;
|
||||
m_x = 0;
|
||||
while (!IsDone())
|
||||
{
|
||||
int ctl = m_input.ReadByte();
|
||||
if (-1 == ctl)
|
||||
break;
|
||||
int count = (ctl & 0x1F) + 1;
|
||||
bool bit = (ctl & 0x20) != 0;
|
||||
ctl >>= 6;
|
||||
if (!bit)
|
||||
{
|
||||
if (ctl != 0)
|
||||
{
|
||||
int src_pos = ctl;
|
||||
int src_count2 = 1 << (ctl - 1);
|
||||
int pos = offsets[ctl];
|
||||
int count2 = src_count2;
|
||||
do
|
||||
{
|
||||
byte p0 = m_input.ReadUInt8();
|
||||
byte p1 = m_input.ReadUInt8();
|
||||
byte p2 = m_input.ReadUInt8();
|
||||
byte p3 = m_input.ReadUInt8();
|
||||
PutPixels (p0, p1, p2, p3);
|
||||
buffer[pos++] = p0;
|
||||
buffer[pos++] = p1;
|
||||
buffer[pos++] = p2;
|
||||
buffer[pos++] = p3;
|
||||
}
|
||||
while (--count > 0 && --count2 > 0);
|
||||
while (count > 0)
|
||||
{
|
||||
int si = offsets[src_pos];
|
||||
for (int i = 0; i < src_count2; ++i)
|
||||
{
|
||||
byte p0 = buffer[si++];
|
||||
byte p1 = buffer[si++];
|
||||
byte p2 = buffer[si++];
|
||||
byte p3 = buffer[si++];
|
||||
PutPixels (p0, p1, p2, p3);
|
||||
if (--count <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
offsets[src_pos] += src_count2 * 4;
|
||||
buf_count[src_pos] += (byte)src_count2;
|
||||
if (buf_count[src_pos] == 0)
|
||||
offsets[src_pos] = src_pos * buffer_slice;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (count --> 0)
|
||||
{
|
||||
byte p0 = m_input.ReadUInt8();
|
||||
byte p1 = m_input.ReadUInt8();
|
||||
byte p2 = m_input.ReadUInt8();
|
||||
byte p3 = m_input.ReadUInt8();
|
||||
PutPixels (p0, p1, p2, p3);
|
||||
int pos = offsets[0];
|
||||
buffer[pos++] = p0;
|
||||
buffer[pos++] = p1;
|
||||
buffer[pos++] = p2;
|
||||
buffer[pos++] = p3;
|
||||
offsets[0] += 4;
|
||||
buf_count[0]++;
|
||||
if (0 == buf_count[0])
|
||||
offsets[0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ctl != 0)
|
||||
{
|
||||
int count2 = 1 << (ctl - 1);
|
||||
int off_diff = count2 << 2;
|
||||
int off_mask = off_diff - 1;
|
||||
int off = m_input.ReadUInt8() << 2;;
|
||||
int base_pos = ctl * buffer_slice;
|
||||
off += base_pos;
|
||||
int src = off;
|
||||
while (count > 0)
|
||||
{
|
||||
off = src;
|
||||
for (int i = 0; i < count2; ++i)
|
||||
{
|
||||
byte p0 = buffer[off];
|
||||
byte p1 = buffer[off+1];
|
||||
byte p2 = buffer[off+2];
|
||||
byte p3 = buffer[off+3];
|
||||
PutPixels (p0, p1, p2, p3);
|
||||
off += 4;
|
||||
int pos = off - base_pos;
|
||||
if ((pos & off_mask) == 0)
|
||||
off -= off_diff;
|
||||
if (--count <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (count --> 0)
|
||||
{
|
||||
int off = m_input.ReadUInt8() << 2;
|
||||
byte p0 = buffer[off];
|
||||
byte p1 = buffer[off+1];
|
||||
byte p2 = buffer[off+2];
|
||||
byte p3 = buffer[off+3];
|
||||
PutPixels (p0, p1, p2, p3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ImageData Unpack ()
|
||||
{
|
||||
UnpackPlanes();
|
||||
int output_stride = m_info.iWidth >> 1;
|
||||
var output = new byte[output_stride * m_info.iHeight];
|
||||
FlattenPlanes (0, output);
|
||||
return ImageData.Create (m_info, PixelFormats.Indexed4, m_palette, output, output_stride);
|
||||
}
|
||||
|
||||
void PutPixels (byte p0, byte p1, byte p2, byte p3)
|
||||
{
|
||||
if (0xFF == m_info.Mask || true) // we don't do overlaying here, just single image decoding
|
||||
{
|
||||
m_planes[0][m_dst] = p0;
|
||||
m_planes[1][m_dst] = p1;
|
||||
m_planes[2][m_dst] = p2;
|
||||
m_planes[3][m_dst] = p3;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte v = m_info.Mask;
|
||||
byte mask = p0;
|
||||
if ((v & 1) != 0)
|
||||
mask = (byte)~mask;
|
||||
if ((v & 2) != 0)
|
||||
mask |= (byte)~p1;
|
||||
else
|
||||
mask |= p1;
|
||||
if ((v & 4) != 0)
|
||||
mask |= (byte)~p2;
|
||||
else
|
||||
mask |= p2;
|
||||
if ((v & 8) != 0)
|
||||
mask |= (byte)~p3;
|
||||
else
|
||||
mask |= p3;
|
||||
p0 &= mask;
|
||||
p1 &= mask;
|
||||
p2 &= mask;
|
||||
p3 &= mask;
|
||||
mask = (byte)~mask;
|
||||
m_planes[0][m_dst] &= mask;
|
||||
m_planes[0][m_dst] |= p0;
|
||||
m_planes[1][m_dst] &= mask;
|
||||
m_planes[1][m_dst] |= p1;
|
||||
m_planes[2][m_dst] &= mask;
|
||||
m_planes[2][m_dst] |= p2;
|
||||
m_planes[3][m_dst] &= mask;
|
||||
m_planes[3][m_dst] |= p3;
|
||||
}
|
||||
IncrementDest();
|
||||
}
|
||||
|
||||
void IncLeftToRight ()
|
||||
{
|
||||
++m_dst;
|
||||
++m_x;
|
||||
if (m_x > m_info.iWidth)
|
||||
m_x = 0;
|
||||
}
|
||||
|
||||
void IncTopToBottom ()
|
||||
{
|
||||
m_dst += m_stride;
|
||||
if (m_dst >= m_plane_size)
|
||||
m_dst = ++m_x;
|
||||
}
|
||||
|
||||
internal void FlattenPlanes (int src, byte[] output)
|
||||
{
|
||||
int m_dst = 0;
|
||||
for (; src < m_plane_size; ++src)
|
||||
{
|
||||
int b0 = m_planes[0][src];
|
||||
int b1 = m_planes[1][src];
|
||||
int b2 = m_planes[2][src];
|
||||
int b3 = m_planes[3][src];
|
||||
for (int j = 0; j < 8; j += 2)
|
||||
{
|
||||
byte px = (byte)((((b0 << j) & 0x80) >> 3)
|
||||
| (((b1 << j) & 0x80) >> 2)
|
||||
| (((b2 << j) & 0x80) >> 1)
|
||||
| (((b3 << j) & 0x80) ));
|
||||
px |= (byte)((((b0 << j) & 0x40) >> 6)
|
||||
| (((b1 << j) & 0x40) >> 5)
|
||||
| (((b2 << j) & 0x40) >> 4)
|
||||
| (((b3 << j) & 0x40) >> 3));
|
||||
output[m_dst++] = px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BitmapPalette ReadPalette ()
|
||||
{
|
||||
const int count = 16;
|
||||
var colors = new Color[count];
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
byte g = m_input.ReadUInt8();
|
||||
byte r = m_input.ReadUInt8();
|
||||
byte b = m_input.ReadUInt8();
|
||||
colors[i] = Color.FromRgb ((byte)(r * 0x11), (byte)(g * 0x11), (byte)(b * 0x11));
|
||||
}
|
||||
return new BitmapPalette (colors);
|
||||
}
|
||||
}
|
||||
}
|
65
Legacy/Harvest/ArcDAT.cs
Normal file
65
Legacy/Harvest/ArcDAT.cs
Normal file
@ -0,0 +1,65 @@
|
||||
//! \file ArcDAT.cs
|
||||
//! \date 2023 Sep 26
|
||||
//! \brief MyHarvest resource archive.
|
||||
//
|
||||
// Copyright (C) 2023 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.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
|
||||
namespace GameRes.Formats.MyHarvest
|
||||
{
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class DatOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag => "DAT/UNA";
|
||||
public override string Description => "MyHarvest resource archive";
|
||||
public override uint Signature => 0x414E55; // 'UNA'
|
||||
public override bool IsHierarchic => false;
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
if (!file.View.AsciiEqual (4, "001\0"))
|
||||
return null;
|
||||
int count = file.View.ReadInt32 (8);
|
||||
if (!IsSaneCount (count))
|
||||
return null;
|
||||
uint index = 0x20;
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
var name = file.View.ReadString (index, 0x20);
|
||||
var entry = Create<Entry> (name);
|
||||
entry.Offset = file.View.ReadUInt32 (index+0x20);
|
||||
entry.Size = file.View.ReadUInt32 (index+0x24);
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
index += 0x30;
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
}
|
||||
}
|
56
Legacy/Harvest/AudioBGM.cs
Normal file
56
Legacy/Harvest/AudioBGM.cs
Normal file
@ -0,0 +1,56 @@
|
||||
//! \file AudioBGM.cs
|
||||
//! \date 2023 Sep 26
|
||||
//! \brief MyHarvest audio format.
|
||||
//
|
||||
// Copyright (C) 2023 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;
|
||||
|
||||
namespace GameRes.Formats.MyHarvest
|
||||
{
|
||||
[Export(typeof(AudioFormat))]
|
||||
public class BgmAudio : AudioFormat
|
||||
{
|
||||
public override string Tag => "BGM/HARVEST";
|
||||
public override string Description => "MyHarvest audio resource";
|
||||
public override uint Signature => 0x304D4742; // 'BMG0'
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override SoundInput TryOpen (IBinaryStream file)
|
||||
{
|
||||
var header = file.ReadHeader (0x1C);
|
||||
if (!header.AsciiEqual (0x14, "dar\0"))
|
||||
return null;
|
||||
var format = new WaveFormat {
|
||||
FormatTag = header.ToUInt16 (4),
|
||||
Channels = header.ToUInt16 (6),
|
||||
SamplesPerSecond = header.ToUInt32 (8),
|
||||
AverageBytesPerSecond = header.ToUInt32 (0xC),
|
||||
BlockAlign = header.ToUInt16 (0x10),
|
||||
BitsPerSample = header.ToUInt16 (0x12),
|
||||
};
|
||||
uint pcm_size = header.ToUInt32 (0x18);
|
||||
var region = new StreamRegion (file.AsStream, 0x1C, pcm_size);
|
||||
return new RawPcmInput (region, format);
|
||||
}
|
||||
}
|
||||
}
|
61
Legacy/Harvest/AudioSED.cs
Normal file
61
Legacy/Harvest/AudioSED.cs
Normal file
@ -0,0 +1,61 @@
|
||||
//! \file AudioSED.cs
|
||||
//! \date 2023 Sep 26
|
||||
//! \brief MyHarvest audio format.
|
||||
//
|
||||
// Copyright (C) 2023 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;
|
||||
|
||||
namespace GameRes.Formats.MyHarvest
|
||||
{
|
||||
[Export(typeof(AudioFormat))]
|
||||
public class SedAudio : AudioFormat
|
||||
{
|
||||
public override string Tag => "SED/HARVEST";
|
||||
public override string Description => "MyHarvest audio resource";
|
||||
public override uint Signature => 0x14553; // 'SE'
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public SedAudio ()
|
||||
{
|
||||
Signatures = new[] { 0x14553u, 0u };
|
||||
}
|
||||
|
||||
public override SoundInput TryOpen (IBinaryStream file)
|
||||
{
|
||||
var header = file.ReadHeader (0x18);
|
||||
if (!header.AsciiEqual (0, "SE") || !header.AsciiEqual (0x12, "da"))
|
||||
return null;
|
||||
var format = new WaveFormat {
|
||||
FormatTag = header.ToUInt16 (2),
|
||||
Channels = header.ToUInt16 (4),
|
||||
SamplesPerSecond = header.ToUInt32 (6),
|
||||
AverageBytesPerSecond = header.ToUInt32 (0xA),
|
||||
BlockAlign = header.ToUInt16 (0xE),
|
||||
BitsPerSample = header.ToUInt16 (0x10),
|
||||
};
|
||||
uint pcm_size = header.ToUInt32 (0x14);
|
||||
var region = new StreamRegion (file.AsStream, 0x18, pcm_size);
|
||||
return new RawPcmInput (region, format);
|
||||
}
|
||||
}
|
||||
}
|
96
Legacy/Harvest/ImageUNH.cs
Normal file
96
Legacy/Harvest/ImageUNH.cs
Normal file
@ -0,0 +1,96 @@
|
||||
//! \file ImageUNH.cs
|
||||
//! \date 2023 Sep 26
|
||||
//! \brief MyHarvest image format.
|
||||
//
|
||||
// Copyright (C) 2023 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;
|
||||
|
||||
// [021206][MyHarvest] Idol Mahjong Final Romance 4
|
||||
|
||||
namespace GameRes.Formats.MyHarvest
|
||||
{
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class UnhFormat : ImageFormat
|
||||
{
|
||||
public override string Tag => "UNH";
|
||||
public override string Description => "MyHarvest image format";
|
||||
public override uint Signature => 0x30484E55; // 'UNH0'
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
var header = file.ReadHeader (0x18);
|
||||
if (header.ToInt32 (4) != 1)
|
||||
return null;
|
||||
return new ImageMetaData {
|
||||
Width = header.ToUInt32 (0x10),
|
||||
Height = header.ToUInt32 (0x14),
|
||||
BPP = 16,
|
||||
};
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
file.Position = 0x44;
|
||||
var pixels = new ushort[info.iWidth * info.iHeight];
|
||||
var frame = new ushort[0x1000];
|
||||
int frame_pos = 0;
|
||||
int dst = 0;
|
||||
byte mask = 0;
|
||||
int ctl = 0;
|
||||
while (dst < pixels.Length)
|
||||
{
|
||||
mask <<= 1;
|
||||
if (0 == mask)
|
||||
{
|
||||
ctl = file.ReadByte();
|
||||
if (-1 == ctl)
|
||||
break;
|
||||
mask = 1;
|
||||
}
|
||||
ushort word = file.ReadUInt16();
|
||||
if ((ctl & mask) == 0)
|
||||
{
|
||||
pixels[dst++] = frame[frame_pos++ & 0xFFF] = word;
|
||||
}
|
||||
else
|
||||
{
|
||||
int offset = word >> 4;
|
||||
int count = (word & 0xF) + 2;
|
||||
while (count --> 0)
|
||||
{
|
||||
ushort u = frame[offset++ & 0xFFF];
|
||||
pixels[dst++] = frame[frame_pos++ & 0xFFF] = u;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ImageData.Create (info, PixelFormats.Bgr565, null, pixels);
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("UnhFormat.Write not implemented");
|
||||
}
|
||||
}
|
||||
}
|
69
Legacy/Jam/ImageHTF.cs
Normal file
69
Legacy/Jam/ImageHTF.cs
Normal file
@ -0,0 +1,69 @@
|
||||
//! \file ImageHTF.cs
|
||||
//! \date 2023 Oct 07
|
||||
//! \brief Huffman-compressed bitmap.
|
||||
//
|
||||
// Copyright (C) 2023 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 GameRes.Compression;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace GameRes.Formats.Jam
|
||||
{
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class HtfFormat : ImageFormat
|
||||
{
|
||||
public override string Tag => "HTF";
|
||||
public override string Description => "Huffman-compressed bitmap";
|
||||
public override uint Signature => 0;
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
if (!file.Name.HasExtension (".HTF"))
|
||||
return null;
|
||||
int unpacked_size = file.ReadInt32();
|
||||
if (unpacked_size <= 0 || unpacked_size > 0x1000000)
|
||||
return null;
|
||||
using (var huff = new HuffmanStream (file.AsStream, true))
|
||||
using (var input = new BinaryStream (huff, file.Name))
|
||||
{
|
||||
return Bmp.ReadMetaData (input);
|
||||
}
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
file.Position = 4;
|
||||
using (var input = new HuffmanStream (file.AsStream, true))
|
||||
{
|
||||
var decoder = new BmpBitmapDecoder (input, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
|
||||
return new ImageData (decoder.Frames[0], info);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("HtfFormat.Write not implemented");
|
||||
}
|
||||
}
|
||||
}
|
@ -78,6 +78,9 @@
|
||||
<Compile Include="AlphaSystem\ArcPAK.cs" />
|
||||
<Compile Include="AlphaSystem\ImageSFG.cs" />
|
||||
<Compile Include="Alterna\ArcBIN.cs" />
|
||||
<Compile Include="Adviz\ImageBIZ.cs" />
|
||||
<Compile Include="Adviz\ImageGIZ.cs" />
|
||||
<Compile Include="Adviz\ImageGIZ2.cs" />
|
||||
<Compile Include="Aos\ArcDAT.cs" />
|
||||
<Compile Include="Aquarium\ArcAAP.cs" />
|
||||
<Compile Include="Aquarium\ArcCPA.cs" />
|
||||
@ -92,9 +95,15 @@
|
||||
<Compile Include="Blucky\Aliases.cs" />
|
||||
<Compile Include="Bom\ImageGRP.cs" />
|
||||
<Compile Include="CottonClub\ImageLMG.cs" />
|
||||
<Compile Include="Discovery\ImageAN1.cs" />
|
||||
<Compile Include="Discovery\ImagePR1.cs" />
|
||||
<Compile Include="Grocer\ImagePIC.cs" />
|
||||
<Compile Include="Gsx\ArcK5.cs" />
|
||||
<Compile Include="Gsx\ImageK4.cs" />
|
||||
<Compile Include="Harvest\ArcDAT.cs" />
|
||||
<Compile Include="Harvest\AudioBGM.cs" />
|
||||
<Compile Include="Harvest\AudioSED.cs" />
|
||||
<Compile Include="Harvest\ImageUNH.cs" />
|
||||
<Compile Include="Herb\ArcPAK.cs" />
|
||||
<Compile Include="Herb\ImageGRP.cs" />
|
||||
<Compile Include="HyperWorks\ImageG.cs" />
|
||||
@ -118,6 +127,7 @@
|
||||
<Compile Include="hmp\ImageCBF.cs" />
|
||||
<Compile Include="HyperWorks\ArcPAK.cs" />
|
||||
<Compile Include="HyperWorks\ImageI24.cs" />
|
||||
<Compile Include="Jam\ImageHTF.cs" />
|
||||
<Compile Include="KApp\ArcASD.cs" />
|
||||
<Compile Include="KApp\ArcCGD.cs" />
|
||||
<Compile Include="KApp\ImageCGD.cs" />
|
||||
@ -138,9 +148,14 @@
|
||||
<Compile Include="Melonpan\ArcTTD.cs" />
|
||||
<Compile Include="Mermaid\AudioPWV.cs" />
|
||||
<Compile Include="Mermaid\ImageGP1.cs" />
|
||||
<Compile Include="Mina\ArcPAK.cs" />
|
||||
<Compile Include="Mink\ImageFC.cs" />
|
||||
<Compile Include="Mink\ImageFD.cs" />
|
||||
<Compile Include="Mmfass\ArcSDA.cs" />
|
||||
<Compile Include="Nekotaro\ImageNCG.cs" />
|
||||
<Compile Include="Ponytail\ArcBND.cs" />
|
||||
<Compile Include="Ponytail\ImageTCZ.cs" />
|
||||
<Compile Include="Ponytail\ImageTSZ.cs" />
|
||||
<Compile Include="Nug\ArcDAT.cs" />
|
||||
<Compile Include="Nyoken\ArcZLK.cs" />
|
||||
<Compile Include="Omi\ArcDAT.cs" />
|
||||
@ -209,8 +224,11 @@
|
||||
<Compile Include="Rune\ArcYK.cs" />
|
||||
<Compile Include="Sarang\ImageABC.cs" />
|
||||
<Compile Include="Sogna\ArcSGS.cs" />
|
||||
<Compile Include="Sophia\ArcNOR.cs" />
|
||||
<Compile Include="SplushWave\ArcDAT.cs" />
|
||||
<Compile Include="SplushWave\ImageSWG.cs" />
|
||||
<Compile Include="SquadraD\ArcPLA.cs" />
|
||||
<Compile Include="SquadraD\ArcSDA.cs" />
|
||||
<Compile Include="StudioEbisu\ArcEP1.cs" />
|
||||
<Compile Include="StudioFoma\ArcARC.cs" />
|
||||
<Compile Include="System21\ImageTEX.cs" />
|
||||
@ -251,7 +269,7 @@
|
||||
<Compile Include="Mink\ArcMINK.cs" />
|
||||
<Compile Include="Mutation\ArcDPF.cs" />
|
||||
<Compile Include="Pinpai\ArcARC.cs" />
|
||||
<Compile Include="Sorciere\ImageBIZ.cs" />
|
||||
<Compile Include="Adviz\ImageBIZ2.cs" />
|
||||
<Compile Include="UMeSoft\ArcBIN.cs" />
|
||||
<Compile Include="Uncanny\AudioCWV.cs" />
|
||||
<Compile Include="Uncanny\ImageCII.cs" />
|
||||
|
299
Legacy/Mina/ArcPAK.cs
Normal file
299
Legacy/Mina/ArcPAK.cs
Normal file
@ -0,0 +1,299 @@
|
||||
//! \file ArcPAK.cs
|
||||
//! \date 2023 Oct 09
|
||||
//! \brief Mina resource archive.
|
||||
//
|
||||
// Copyright (C) 2023 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 GameRes.Utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Windows.Media;
|
||||
|
||||
// [010223][Mina] Storia ~Ouma no Mori no Himegimi-tachi~
|
||||
|
||||
namespace GameRes.Formats.Mina
|
||||
{
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class BmpPakOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag => "PAK/MINA/BMP";
|
||||
public override string Description => "Mina bitmap archive";
|
||||
public override uint Signature => 0;
|
||||
public override bool IsHierarchic => false;
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
if (!file.Name.HasExtension (".PAK"))
|
||||
return null;
|
||||
int pos;
|
||||
for (pos = 0; pos < 0x10; ++pos)
|
||||
{
|
||||
if (0 == file.View.ReadByte (pos))
|
||||
break;
|
||||
}
|
||||
if (pos >= 0x10 || pos <= 4 || !file.View.AsciiEqual (pos-4, ".BMP"))
|
||||
return null;
|
||||
using (var input = file.CreateStream())
|
||||
{
|
||||
var dir = new List<Entry>();
|
||||
while (input.PeekByte() != -1)
|
||||
{
|
||||
var name = input.ReadCString();
|
||||
if (name.Length > 0x10)
|
||||
return null;
|
||||
var entry = Create<Entry> (name);
|
||||
entry.Offset = input.Position;
|
||||
input.Seek (5, SeekOrigin.Current);
|
||||
uint size = input.ReadUInt32();
|
||||
entry.Size = size + 9;
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
input.Seek (size, SeekOrigin.Current);
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
}
|
||||
|
||||
public override IImageDecoder OpenImage (ArcFile arc, Entry entry)
|
||||
{
|
||||
var input = arc.File.CreateStream (entry.Offset, entry.Size);
|
||||
return new BitmapDecoder (input);
|
||||
}
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class WavPakOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag => "PAK/MINA/WAV";
|
||||
public override string Description => "Mina audio archive";
|
||||
public override uint Signature => 0;
|
||||
public override bool IsHierarchic => false;
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
if (!file.Name.HasExtension (".PAK"))
|
||||
return null;
|
||||
int pos;
|
||||
for (pos = 4; pos < 0x14; ++pos)
|
||||
{
|
||||
if (0 == file.View.ReadByte (pos))
|
||||
break;
|
||||
}
|
||||
if (pos >= 0x14 || pos <= 8 || !file.View.AsciiEqual (pos-4, ".WAV"))
|
||||
return null;
|
||||
using (var input = file.CreateStream())
|
||||
{
|
||||
var dir = new List<Entry>();
|
||||
while (input.PeekByte() != -1)
|
||||
{
|
||||
uint data_size = input.ReadUInt32();
|
||||
var name = input.ReadCString();
|
||||
if (name.Length > 0x10)
|
||||
return null;
|
||||
var entry = Create<Entry> (name);
|
||||
entry.Offset = input.Position;
|
||||
uint fmt_size = input.ReadUInt32();
|
||||
if (fmt_size < 0x10)
|
||||
return null;
|
||||
entry.Size = data_size + fmt_size + 4;
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
input.Seek (data_size + fmt_size, SeekOrigin.Current);
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
uint fmt_size = arc.File.View.ReadUInt32 (entry.Offset);
|
||||
uint pcm_size = entry.Size - 4 - fmt_size;
|
||||
using (var mem = new MemoryStream ((int)fmt_size))
|
||||
{
|
||||
using (var buffer = new BinaryWriter (mem, Encoding.ASCII, true))
|
||||
{
|
||||
buffer.Write (AudioFormat.Wav.Signature);
|
||||
buffer.Write (entry.Size+0x10);
|
||||
buffer.Write (0x45564157); // 'WAVE'
|
||||
buffer.Write (0x20746d66); // 'fmt '
|
||||
buffer.Write (fmt_size);
|
||||
var fmt = arc.File.View.ReadBytes (entry.Offset+4, fmt_size);
|
||||
buffer.Write (fmt, 0, fmt.Length);
|
||||
buffer.Write (0x61746164); // 'data'
|
||||
buffer.Write (pcm_size);
|
||||
}
|
||||
var header = mem.ToArray();
|
||||
var data = arc.File.CreateStream (entry.Offset+4+fmt_size, pcm_size);
|
||||
return new PrefixStream (header, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class ScriptPakOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag => "PAK/MINA/SPT";
|
||||
public override string Description => "Mina scripts archive";
|
||||
public override uint Signature => 0;
|
||||
public override bool IsHierarchic => false;
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public ScriptPakOpener ()
|
||||
{
|
||||
ContainedFormats = new[] { "SCR" };
|
||||
}
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
if (!VFS.IsPathEqualsToFileName (file.Name, "SCRIPT.PAK"))
|
||||
return null;
|
||||
using (var input = file.CreateStream())
|
||||
{
|
||||
var dir = new List<Entry>();
|
||||
while (input.PeekByte() != -1)
|
||||
{
|
||||
var name = input.ReadCString();
|
||||
if (name.Length > 0x10)
|
||||
return null;
|
||||
var entry = Create<Entry> (name);
|
||||
entry.Size = input.ReadUInt32();
|
||||
entry.Offset = input.Position;
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
input.Seek (entry.Size, SeekOrigin.Current);
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
var data = arc.File.View.ReadBytes (entry.Offset, entry.Size);
|
||||
var mem = new MemoryStream (data.Length);
|
||||
int pos = 0;
|
||||
while (pos < data.Length)
|
||||
{
|
||||
int len = data[pos]+1;
|
||||
int num = data.ToUInt16 (1);
|
||||
pos += 3;
|
||||
for (int j = 0; j < len; ++j)
|
||||
data[pos+j] = Binary.RotByteR (data[pos+j], 4);
|
||||
mem.Write (data, pos, len);
|
||||
mem.WriteByte (0xD);
|
||||
mem.WriteByte (0xA);
|
||||
pos += len;
|
||||
}
|
||||
mem.Position = 0;
|
||||
return mem;
|
||||
}
|
||||
}
|
||||
|
||||
internal class BmpMetaData : ImageMetaData
|
||||
{
|
||||
public byte Flags;
|
||||
public bool IsCompressed => (Flags & 1) != 0;
|
||||
}
|
||||
|
||||
internal class BitmapDecoder : IImageDecoder
|
||||
{
|
||||
IBinaryStream m_input;
|
||||
BmpMetaData m_info;
|
||||
ImageData m_image;
|
||||
|
||||
public Stream Source => m_input.AsStream;
|
||||
public ImageFormat SourceFormat => null;
|
||||
public ImageMetaData Info => m_info;
|
||||
public ImageData Image => m_image ?? (m_image = Unpack());
|
||||
|
||||
public BitmapDecoder (IBinaryStream input)
|
||||
{
|
||||
m_input = input;
|
||||
m_info = new BmpMetaData {
|
||||
Width = input.ReadUInt16(),
|
||||
Height = input.ReadUInt16(),
|
||||
Flags = input.ReadUInt8(),
|
||||
};
|
||||
m_info.BPP = m_info.IsCompressed ? 32 : 24;
|
||||
}
|
||||
|
||||
ImageData Unpack ()
|
||||
{
|
||||
m_input.Position = 9;
|
||||
if (m_info.IsCompressed)
|
||||
{
|
||||
return RleUnpack();
|
||||
}
|
||||
else
|
||||
{
|
||||
int bitmap_size = m_info.iWidth * 3 * m_info.iHeight;
|
||||
var pixels = m_input.ReadBytes (bitmap_size);
|
||||
return ImageData.Create (m_info, PixelFormats.Rgb24, null, pixels);
|
||||
}
|
||||
}
|
||||
|
||||
ImageData RleUnpack ()
|
||||
{
|
||||
int stride = m_info.iWidth * 4;
|
||||
var output = new byte[stride * m_info.iHeight];
|
||||
byte alpha = 0;
|
||||
int count = 0;
|
||||
int dst = 0;
|
||||
while (dst < output.Length)
|
||||
{
|
||||
if (--count <= 0)
|
||||
{
|
||||
alpha = m_input.ReadUInt8();
|
||||
count = m_input.ReadUInt8();
|
||||
}
|
||||
if (alpha != 0)
|
||||
{
|
||||
output[dst+2] = m_input.ReadUInt8();
|
||||
output[dst+1] = m_input.ReadUInt8();
|
||||
output[dst ] = m_input.ReadUInt8();
|
||||
output[dst+3] = alpha;
|
||||
}
|
||||
dst += 4;
|
||||
}
|
||||
return ImageData.Create (m_info, PixelFormats.Bgra32, null, output, stride);
|
||||
}
|
||||
|
||||
#region IDisposable members
|
||||
bool m_disposed = false;
|
||||
public void Dispose ()
|
||||
{
|
||||
if (!m_disposed)
|
||||
{
|
||||
m_input.Dispose();
|
||||
m_disposed = true;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
|
||||
// [991231][Jam] Kakuyuugou Shoujo Ripple-chan
|
||||
// [000331][Jam] Zetsumetsu King
|
||||
// [000630][STONE HEADS] Sei Cosplay Gakuen ~Game Bunkou~
|
||||
|
||||
|
@ -24,8 +24,10 @@
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using GameRes.Utility;
|
||||
@ -44,6 +46,11 @@ namespace GameRes.Formats.Nekotaro
|
||||
public override string Description { get { return "Nekotaro Game System image format"; } }
|
||||
public override uint Signature { get { return 0x706D4347; } } // 'GCmp'
|
||||
|
||||
public GCmpFormat ()
|
||||
{
|
||||
Extensions = new[] { "GCMP", "AIG" };
|
||||
}
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
var header = file.ReadHeader (0x10);
|
||||
@ -98,6 +105,8 @@ namespace GameRes.Formats.Nekotaro
|
||||
Stride = (info.iWidth + 7) / 8;
|
||||
}
|
||||
|
||||
static BitmapPalette LastUsedPalette = null;
|
||||
|
||||
public ImageData Unpack ()
|
||||
{
|
||||
m_input.Position = 0x10;
|
||||
@ -106,6 +115,8 @@ namespace GameRes.Formats.Nekotaro
|
||||
pixels = Unpack24bpp();
|
||||
else
|
||||
pixels = Unpack8bpp();
|
||||
if (8 == Info.BPP)
|
||||
Palette = LastUsedPalette ?? (LastUsedPalette = RetrievePalette() ?? DefaultPalette);
|
||||
return ImageData.CreateFlipped (Info, Format, Palette, pixels, Stride);
|
||||
}
|
||||
|
||||
@ -190,14 +201,11 @@ namespace GameRes.Formats.Nekotaro
|
||||
byte[] Unpack8bpp ()
|
||||
{
|
||||
if (8 == Info.BPP)
|
||||
{
|
||||
Format = PixelFormats.Indexed8;
|
||||
Palette = DefaultPalette;
|
||||
}
|
||||
else
|
||||
Format = PixelFormats.BlackWhite;
|
||||
int pixel_count = Info.iHeight * Stride;
|
||||
if (m_info.IsCompressed)
|
||||
if (!m_info.IsCompressed)
|
||||
return m_input.ReadBytes (pixel_count);
|
||||
|
||||
var output = new byte[pixel_count];
|
||||
@ -272,268 +280,125 @@ namespace GameRes.Formats.Nekotaro
|
||||
return output;
|
||||
}
|
||||
|
||||
static readonly BitmapPalette DefaultPalette = new BitmapPalette (
|
||||
/*
|
||||
new Color[] {
|
||||
Color.FromRgb (0x00, 0x00, 0x00),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0x22, 0x22, 0x22),
|
||||
Color.FromRgb (0x44, 0x44, 0x44),
|
||||
Color.FromRgb (0x55, 0x55, 0x55),
|
||||
Color.FromRgb (0x66, 0x66, 0x66),
|
||||
Color.FromRgb (0x77, 0x77, 0x77),
|
||||
Color.FromRgb (0x88, 0x88, 0x88),
|
||||
Color.FromRgb (0x99, 0x99, 0x99),
|
||||
Color.FromRgb (0xAA, 0xAA, 0xAA),
|
||||
Color.FromRgb (0xBB, 0xBB, 0xBB),
|
||||
Color.FromRgb (0xCC, 0xCC, 0xCC),
|
||||
Color.FromRgb (0xDD, 0xDD, 0xDD),
|
||||
Color.FromRgb (0xEE, 0xEE, 0xEE),
|
||||
Color.FromRgb (0x00, 0xFF, 0x00),
|
||||
Color.FromRgb (0x1C, 0x09, 0x05),
|
||||
Color.FromRgb (0x2F, 0x0A, 0x05),
|
||||
Color.FromRgb (0x4E, 0x04, 0x02),
|
||||
Color.FromRgb (0x41, 0x0C, 0x05),
|
||||
Color.FromRgb (0x29, 0x15, 0x36),
|
||||
Color.FromRgb (0x24, 0x22, 0x21),
|
||||
Color.FromRgb (0x6C, 0x07, 0x0D),
|
||||
Color.FromRgb (0x1F, 0x2D, 0x36),
|
||||
Color.FromRgb (0x4B, 0x21, 0x18),
|
||||
Color.FromRgb (0x5D, 0x1B, 0x0D),
|
||||
Color.FromRgb (0x8B, 0x00, 0x36),
|
||||
Color.FromRgb (0x8E, 0x06, 0x16),
|
||||
Color.FromRgb (0x7E, 0x11, 0x0F),
|
||||
Color.FromRgb (0x09, 0x44, 0x64),
|
||||
Color.FromRgb (0x48, 0x2C, 0x4B),
|
||||
Color.FromRgb (0x38, 0x37, 0x3A),
|
||||
Color.FromRgb (0x3A, 0x24, 0x88),
|
||||
Color.FromRgb (0x74, 0x23, 0x12),
|
||||
Color.FromRgb (0x0D, 0x53, 0x29),
|
||||
Color.FromRgb (0x22, 0x34, 0x86),
|
||||
Color.FromRgb (0xB1, 0x03, 0x2A),
|
||||
Color.FromRgb (0x4B, 0x37, 0x28),
|
||||
Color.FromRgb (0x64, 0x30, 0x28),
|
||||
Color.FromRgb (0x32, 0x4A, 0x2D),
|
||||
Color.FromRgb (0x9B, 0x17, 0x20),
|
||||
Color.FromRgb (0xB0, 0x10, 0x10),
|
||||
Color.FromRgb (0x3D, 0x19, 0xCC),
|
||||
Color.FromRgb (0x1B, 0x38, 0xB2),
|
||||
Color.FromRgb (0x97, 0x25, 0x13),
|
||||
Color.FromRgb (0x30, 0x4C, 0x5E),
|
||||
Color.FromRgb (0x77, 0x38, 0x22),
|
||||
Color.FromRgb (0xD3, 0x0B, 0x1F),
|
||||
Color.FromRgb (0x01, 0x69, 0x65),
|
||||
Color.FromRgb (0x5F, 0x46, 0x33),
|
||||
Color.FromRgb (0x4B, 0x4D, 0x4F),
|
||||
Color.FromRgb (0xB6, 0x1B, 0x34),
|
||||
Color.FromRgb (0x0A, 0x74, 0x34),
|
||||
Color.FromRgb (0xBB, 0x26, 0x11),
|
||||
Color.FromRgb (0xED, 0x0B, 0x26),
|
||||
Color.FromRgb (0x2F, 0x52, 0x97),
|
||||
Color.FromRgb (0x49, 0x20, 0xFB),
|
||||
Color.FromRgb (0x89, 0x44, 0x15),
|
||||
Color.FromRgb (0x67, 0x46, 0x65),
|
||||
Color.FromRgb (0x06, 0x76, 0x72),
|
||||
Color.FromRgb (0x93, 0x3F, 0x2D),
|
||||
Color.FromRgb (0x3F, 0x65, 0x49),
|
||||
Color.FromRgb (0x6D, 0x52, 0x3B),
|
||||
Color.FromRgb (0x88, 0x4C, 0x38),
|
||||
Color.FromRgb (0xE5, 0x26, 0x17),
|
||||
Color.FromRgb (0xA6, 0x47, 0x1D),
|
||||
Color.FromRgb (0x43, 0x68, 0x7D),
|
||||
Color.FromRgb (0x23, 0x50, 0xE8),
|
||||
Color.FromRgb (0xE3, 0x24, 0x43),
|
||||
Color.FromRgb (0x94, 0x56, 0x1C),
|
||||
Color.FromRgb (0x60, 0x63, 0x64),
|
||||
Color.FromRgb (0xBC, 0x3E, 0x49),
|
||||
Color.FromRgb (0x06, 0x9C, 0x45),
|
||||
Color.FromRgb (0xC4, 0x44, 0x24),
|
||||
Color.FromRgb (0xB1, 0x55, 0x2B),
|
||||
Color.FromRgb (0x8D, 0x60, 0x53),
|
||||
Color.FromRgb (0x63, 0x46, 0xFB),
|
||||
Color.FromRgb (0x7B, 0x6C, 0x61),
|
||||
Color.FromRgb (0x91, 0x57, 0x97),
|
||||
Color.FromRgb (0xAA, 0x5A, 0x4C),
|
||||
Color.FromRgb (0x49, 0x7E, 0xA0),
|
||||
Color.FromRgb (0xF8, 0x3C, 0x29),
|
||||
Color.FromRgb (0xA9, 0x67, 0x20),
|
||||
Color.FromRgb (0xC9, 0x56, 0x36),
|
||||
Color.FromRgb (0xA2, 0x6A, 0x3E),
|
||||
Color.FromRgb (0xBF, 0x56, 0x6C),
|
||||
Color.FromRgb (0x77, 0x7A, 0x7B),
|
||||
Color.FromRgb (0x5D, 0x79, 0xD2),
|
||||
Color.FromRgb (0xCC, 0x62, 0x44),
|
||||
Color.FromRgb (0xA3, 0x75, 0x63),
|
||||
Color.FromRgb (0xDE, 0x60, 0x31),
|
||||
Color.FromRgb (0xB5, 0x79, 0x23),
|
||||
Color.FromRgb (0x45, 0x80, 0xF5),
|
||||
Color.FromRgb (0xFD, 0x56, 0x29),
|
||||
Color.FromRgb (0xEE, 0x52, 0x64),
|
||||
Color.FromRgb (0x8C, 0x83, 0x6E),
|
||||
Color.FromRgb (0xCD, 0x70, 0x2A),
|
||||
Color.FromRgb (0xC4, 0x6E, 0x53),
|
||||
Color.FromRgb (0x86, 0x87, 0x87),
|
||||
Color.FromRgb (0x5E, 0x95, 0xAC),
|
||||
Color.FromRgb (0x7D, 0x6C, 0xFD),
|
||||
Color.FromRgb (0x36, 0xC5, 0x22),
|
||||
Color.FromRgb (0xAC, 0x6F, 0xB2),
|
||||
Color.FromRgb (0xD9, 0x6E, 0x4E),
|
||||
Color.FromRgb (0xC1, 0x84, 0x2D),
|
||||
Color.FromRgb (0xDB, 0x6C, 0x72),
|
||||
Color.FromRgb (0xEB, 0x6F, 0x42),
|
||||
Color.FromRgb (0x9F, 0x8B, 0x81),
|
||||
Color.FromRgb (0x92, 0x94, 0x93),
|
||||
Color.FromRgb (0x76, 0x90, 0xDB),
|
||||
Color.FromRgb (0x85, 0x9A, 0x99),
|
||||
Color.FromRgb (0xE0, 0x79, 0x58),
|
||||
Color.FromRgb (0xBE, 0x87, 0x6D),
|
||||
Color.FromRgb (0xD5, 0x7E, 0x62),
|
||||
Color.FromRgb (0x5B, 0xA7, 0xDF),
|
||||
Color.FromRgb (0xCC, 0x91, 0x2A),
|
||||
Color.FromRgb (0xF5, 0x6F, 0x76),
|
||||
Color.FromRgb (0x7B, 0xA7, 0xA7),
|
||||
Color.FromRgb (0xF1, 0x7C, 0x54),
|
||||
Color.FromRgb (0xA1, 0x9C, 0x87),
|
||||
Color.FromRgb (0xE5, 0x81, 0x61),
|
||||
Color.FromRgb (0xF2, 0x8A, 0x47),
|
||||
Color.FromRgb (0xEE, 0x88, 0x67),
|
||||
Color.FromRgb (0xA1, 0xA3, 0xA3),
|
||||
Color.FromRgb (0x8A, 0xA0, 0xE5),
|
||||
Color.FromRgb (0xC4, 0x9A, 0x7F),
|
||||
Color.FromRgb (0xD9, 0x9F, 0x36),
|
||||
Color.FromRgb (0x95, 0xAC, 0xAA),
|
||||
Color.FromRgb (0xEC, 0x88, 0x8B),
|
||||
Color.FromRgb (0xAE, 0xA7, 0x92),
|
||||
Color.FromRgb (0xE8, 0x90, 0x70),
|
||||
Color.FromRgb (0xF5, 0x8F, 0x6F),
|
||||
Color.FromRgb (0xD5, 0x8B, 0xDC),
|
||||
Color.FromRgb (0x6A, 0xC2, 0xF7),
|
||||
Color.FromRgb (0xEE, 0x9A, 0x7A),
|
||||
Color.FromRgb (0xF7, 0x98, 0x74),
|
||||
Color.FromRgb (0x8D, 0xBA, 0xDB),
|
||||
Color.FromRgb (0xBA, 0xB1, 0x9C),
|
||||
Color.FromRgb (0xB2, 0xB3, 0xB1),
|
||||
Color.FromRgb (0xD2, 0xA8, 0x9B),
|
||||
Color.FromRgb (0xA6, 0xBA, 0xBD),
|
||||
Color.FromRgb (0xEC, 0xB4, 0x3A),
|
||||
Color.FromRgb (0xFC, 0x98, 0x9F),
|
||||
Color.FromRgb (0xF7, 0xA1, 0x80),
|
||||
Color.FromRgb (0xED, 0xA7, 0x85),
|
||||
Color.FromRgb (0xFA, 0xA9, 0x83),
|
||||
Color.FromRgb (0xDD, 0xB3, 0xAF),
|
||||
Color.FromRgb (0xFA, 0xA6, 0xA7),
|
||||
Color.FromRgb (0xC8, 0xC0, 0xAD),
|
||||
Color.FromRgb (0xFA, 0xB0, 0x8F),
|
||||
Color.FromRgb (0x89, 0xD9, 0xFC),
|
||||
Color.FromRgb (0xA9, 0xCF, 0xE8),
|
||||
Color.FromRgb (0xBB, 0xCC, 0xCB),
|
||||
Color.FromRgb (0xFB, 0xB2, 0xB2),
|
||||
Color.FromRgb (0xFB, 0xB9, 0x97),
|
||||
Color.FromRgb (0xE2, 0xC2, 0xAF),
|
||||
Color.FromRgb (0xFC, 0xCA, 0x40),
|
||||
Color.FromRgb (0xFA, 0xBF, 0x82),
|
||||
Color.FromRgb (0xC9, 0xCA, 0xC9),
|
||||
Color.FromRgb (0xF8, 0xAC, 0xF8),
|
||||
Color.FromRgb (0xD4, 0xCD, 0xC2),
|
||||
Color.FromRgb (0xFC, 0xC2, 0x9D),
|
||||
Color.FromRgb (0xFC, 0xBE, 0xBA),
|
||||
Color.FromRgb (0xD2, 0xD3, 0xD0),
|
||||
Color.FromRgb (0xEC, 0xC9, 0xC6),
|
||||
Color.FromRgb (0xCA, 0xD9, 0xD7),
|
||||
Color.FromRgb (0xFD, 0xCA, 0xA5),
|
||||
Color.FromRgb (0xFE, 0xDB, 0x5B),
|
||||
Color.FromRgb (0xD8, 0xD8, 0xD4),
|
||||
Color.FromRgb (0xFD, 0xCA, 0xC9),
|
||||
Color.FromRgb (0xC3, 0xDF, 0xF1),
|
||||
Color.FromRgb (0xFE, 0xD2, 0xB1),
|
||||
Color.FromRgb (0xFD, 0xD6, 0xA1),
|
||||
Color.FromRgb (0xEE, 0xD7, 0xCA),
|
||||
Color.FromRgb (0xFB, 0xCB, 0xF7),
|
||||
Color.FromRgb (0xFE, 0xDB, 0xB6),
|
||||
Color.FromRgb (0xFE, 0xF5, 0x2C),
|
||||
Color.FromRgb (0xFD, 0xD6, 0xD4),
|
||||
Color.FromRgb (0xE2, 0xE2, 0xDC),
|
||||
Color.FromRgb (0xFE, 0xEC, 0x74),
|
||||
Color.FromRgb (0xFE, 0xE1, 0xBE),
|
||||
Color.FromRgb (0xED, 0xE5, 0xDC),
|
||||
Color.FromRgb (0xD9, 0xEC, 0xF8),
|
||||
Color.FromRgb (0xFB, 0xE3, 0xD4),
|
||||
Color.FromRgb (0xFD, 0xDD, 0xFA),
|
||||
Color.FromRgb (0xFE, 0xE7, 0xC6),
|
||||
Color.FromRgb (0xFE, 0xFA, 0x91),
|
||||
Color.FromRgb (0xFE, 0xEF, 0xCD),
|
||||
Color.FromRgb (0xFC, 0xEB, 0xEA),
|
||||
Color.FromRgb (0xFE, 0xF6, 0xDC),
|
||||
Color.FromRgb (0xFE, 0xFD, 0xE4),
|
||||
Color.FromRgb (0x35, 0x29, 0x24),
|
||||
Color.FromRgb (0x1A, 0x43, 0x25),
|
||||
Color.FromRgb (0x01, 0x49, 0x96),
|
||||
Color.FromRgb (0x86, 0x27, 0x16),
|
||||
Color.FromRgb (0x4D, 0x52, 0x3F),
|
||||
Color.FromRgb (0xEB, 0x0E, 0x0A),
|
||||
Color.FromRgb (0x00, 0x6A, 0xCC),
|
||||
Color.FromRgb (0x80, 0x34, 0xC1),
|
||||
Color.FromRgb (0xFD, 0x00, 0xFF),
|
||||
Color.FromRgb (0x08, 0x87, 0xEF),
|
||||
Color.FromRgb (0x76, 0x70, 0x56),
|
||||
Color.FromRgb (0xB8, 0x55, 0x3F),
|
||||
Color.FromRgb (0x35, 0x9F, 0xE1),
|
||||
Color.FromRgb (0xAA, 0x7E, 0x60),
|
||||
Color.FromRgb (0x01, 0xFD, 0x00),
|
||||
Color.FromRgb (0xAB, 0x93, 0x8A),
|
||||
Color.FromRgb (0xD3, 0x8C, 0x56),
|
||||
Color.FromRgb (0x77, 0xC0, 0xAC),
|
||||
Color.FromRgb (0xB9, 0xA6, 0x9E),
|
||||
Color.FromRgb (0xE6, 0xAB, 0x63),
|
||||
Color.FromRgb (0x9D, 0xCC, 0xA5),
|
||||
Color.FromRgb (0xD1, 0xB6, 0x91),
|
||||
Color.FromRgb (0xA6, 0xD9, 0xCF),
|
||||
Color.FromRgb (0xEA, 0xC9, 0x9D),
|
||||
Color.FromRgb (0xDF, 0xE2, 0xBC),
|
||||
Color.FromRgb (0xFC, 0xE8, 0xA2),
|
||||
Color.FromRgb (0xF9, 0xF2, 0xDE),
|
||||
Color.FromRgb (0x23, 0x0D, 0x1A),
|
||||
Color.FromRgb (0x02, 0x58, 0x1A),
|
||||
Color.FromRgb (0x66, 0x39, 0x13),
|
||||
Color.FromRgb (0x36, 0x6D, 0x66),
|
||||
Color.FromRgb (0x90, 0x5F, 0x2A),
|
||||
Color.FromRgb (0x51, 0x9E, 0x7E),
|
||||
Color.FromRgb (0xC0, 0x91, 0x52),
|
||||
Color.FromRgb (0x7F, 0xC3, 0xAE),
|
||||
Color.FromRgb (0xE0, 0xBF, 0x78),
|
||||
Color.FromRgb (0xDC, 0xE8, 0xD4),
|
||||
Color.FromRgb (0x65, 0x39, 0x12),
|
||||
Color.FromRgb (0x22, 0x69, 0x49),
|
||||
Color.FromRgb (0x90, 0x5E, 0x2B),
|
||||
Color.FromRgb (0x36, 0x87, 0x5F),
|
||||
Color.FromRgb (0x53, 0x9F, 0x81),
|
||||
Color.FromRgb (0xBB, 0x85, 0x4C),
|
||||
Color.FromRgb (0xD9, 0xB9, 0x6F),
|
||||
Color.FromRgb (0x9A, 0xCE, 0xC2),
|
||||
Color.FromRgb (0xDF, 0xEF, 0xDE),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
static void LzssUnpack (IBinaryStream input, byte[] output)
|
||||
{
|
||||
int dst = 0;
|
||||
int mask = 0;
|
||||
int ctl = 0;
|
||||
while (dst < output.Length)
|
||||
{
|
||||
mask >>= 1;
|
||||
if (0 == mask)
|
||||
{
|
||||
ctl = input.ReadUInt8();
|
||||
mask = 0x80;
|
||||
}
|
||||
*/
|
||||
if ((ctl & mask) != 0)
|
||||
{
|
||||
int off = input.ReadUInt16();
|
||||
int count = (off & 0xF) + 3;
|
||||
off >>= 4;
|
||||
int src = dst - off - 1;
|
||||
Binary.CopyOverlapped (output, src, dst, count);
|
||||
dst += count;
|
||||
}
|
||||
else
|
||||
{
|
||||
output[dst++] = input.ReadUInt8();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BitmapPalette RetrievePalette ()
|
||||
{
|
||||
// find SYSTEM.LZS file, decompress and read it as text file
|
||||
// find 'P' line that denotes archive name and entry number
|
||||
// if entry number is zero, then it's just a file (possibly compressed)
|
||||
// open referenced file and retrieve palette
|
||||
try
|
||||
{
|
||||
string system_name = "SYSTEM.LZS";
|
||||
if (!File.Exists (system_name))
|
||||
{
|
||||
system_name = @"..\SYSTEM.LZS";
|
||||
if (!File.Exists (system_name))
|
||||
return null;
|
||||
}
|
||||
byte[] system_bin;
|
||||
using (var input = BinaryStream.FromFile (system_name))
|
||||
{
|
||||
int unpacked_size = input.ReadUInt16();
|
||||
input.ReadUInt16();
|
||||
system_bin = new byte[unpacked_size];
|
||||
LzssUnpack (input, system_bin);
|
||||
}
|
||||
string line;
|
||||
using (var mem = new MemoryStream (system_bin))
|
||||
using (var text = new StreamReader (mem, Encodings.cp932))
|
||||
{
|
||||
while ((line = text.ReadLine()) != null)
|
||||
{
|
||||
if (line.Length > 3 && line.StartsWith ("P:"))
|
||||
break;
|
||||
}
|
||||
if (null == line)
|
||||
return null;
|
||||
}
|
||||
var match = PLineRe.Match (line);
|
||||
if (!match.Success)
|
||||
return null;
|
||||
int id;
|
||||
if (!Int32.TryParse (match.Groups[2].Value, out id))
|
||||
return null;
|
||||
var arc_name = Path.Combine (Path.GetDirectoryName (system_name), match.Groups[1].Value);
|
||||
if (0 == id)
|
||||
{
|
||||
using (var file = BinaryStream.FromFile (arc_name))
|
||||
{
|
||||
Stream pal_stream;
|
||||
int unpacked_size = file.ReadUInt16();
|
||||
int packed_size = file.ReadUInt16();
|
||||
if (packed_size + 4 == file.Length)
|
||||
{
|
||||
var pal_data = new byte[unpacked_size];
|
||||
LzssUnpack (file, pal_data);
|
||||
pal_stream = new MemoryStream (pal_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
file.Position = 0;
|
||||
pal_stream = file.AsStream;
|
||||
}
|
||||
int colors = (int)pal_stream.Length / 3;
|
||||
using (pal_stream)
|
||||
return ImageFormat.ReadPalette (pal_stream, colors, PaletteFormat.Rgb);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var file = new ArcView (arc_name))
|
||||
{
|
||||
var arc = Nsc.Value.TryOpen (file);
|
||||
if (null == arc)
|
||||
return null;
|
||||
var entry = ((List<Entry>)arc.Dir)[id-1];
|
||||
using (var input = arc.OpenEntry (entry))
|
||||
return ImageFormat.ReadPalette (input, 0x100, PaletteFormat.Rgb);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static readonly Regex PLineRe = new Regex (@"^P:([^,]+),(\d+),(\d+)", RegexOptions.Compiled);
|
||||
static readonly ResourceInstance<ArchiveFormat> Nsc = new ResourceInstance<ArchiveFormat> ("NSC");
|
||||
|
||||
static readonly BitmapPalette DefaultPalette = new BitmapPalette (
|
||||
// [000317][PIL] Seek -remasters-
|
||||
#region colors
|
||||
new Color[] {
|
||||
Color.FromRgb (0x00, 0x00, 0x00),
|
||||
Color.FromRgb (0xFF, 0xFF, 0xFF),
|
||||
@ -792,6 +657,7 @@ namespace GameRes.Formats.Nekotaro
|
||||
Color.FromRgb (0x00, 0x00, 0x00),
|
||||
Color.FromRgb (0x00, 0x00, 0x00),
|
||||
}
|
||||
#endregion
|
||||
);
|
||||
|
||||
bool m_disposed = false;
|
||||
|
293
Legacy/Nekotaro/ImageNCG.cs
Normal file
293
Legacy/Nekotaro/ImageNCG.cs
Normal file
@ -0,0 +1,293 @@
|
||||
//! \file ImageNCG.cs
|
||||
//! \date 2023 Oct 10
|
||||
//! \brief Nekotaro Game System image format (PC-98).
|
||||
//
|
||||
// Copyright (C) 2023 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;
|
||||
|
||||
namespace GameRes.Formats.Nekotaro
|
||||
{
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class NcgFormat : ImageFormat
|
||||
{
|
||||
public override string Tag => "NCG";
|
||||
public override string Description => "Nekotaro Game System image format";
|
||||
public override uint Signature => 0;
|
||||
|
||||
public NcgFormat ()
|
||||
{
|
||||
Signatures = new[] { 0xC8500000u, 0u };
|
||||
}
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
var header = file.ReadHeader (4);
|
||||
int left = header[0] << 3;
|
||||
int top = header[1] << 1;
|
||||
int width = header[2] << 3;
|
||||
int height = header[3] << 1;
|
||||
int right = left + width;
|
||||
int bottom = top + height;
|
||||
if (right > 640 || bottom > 400 || 0 == width || 0 == height)
|
||||
return null;
|
||||
return new ImageMetaData {
|
||||
Width = (uint)width,
|
||||
Height = (uint)height,
|
||||
OffsetX = left,
|
||||
OffsetY = top,
|
||||
BPP = 4,
|
||||
};
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
var reader = new NcgReader (file, info);
|
||||
return reader.Unpack();
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("NcgFormat.Write not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
internal class NcgReader
|
||||
{
|
||||
IBinaryStream m_input;
|
||||
ImageMetaData m_info;
|
||||
|
||||
public NcgReader (IBinaryStream input, ImageMetaData info)
|
||||
{
|
||||
m_input = input;
|
||||
m_info = info;
|
||||
}
|
||||
|
||||
public ImageData Unpack ()
|
||||
{
|
||||
m_input.Position = 4;
|
||||
var palette = ReadPalette();
|
||||
int width = m_info.iWidth;
|
||||
int height = m_info.iHeight;
|
||||
int output_stride = width;
|
||||
var pixels = new byte[output_stride * height];
|
||||
int quart_width = width / 4;
|
||||
int half_height = height / 2;
|
||||
var blockmap = new bool[quart_width * half_height];
|
||||
var bits1 = new byte[8];
|
||||
var bits2 = new byte[8];
|
||||
byte ctl;
|
||||
int dst, pblk;
|
||||
do
|
||||
{
|
||||
for (int i = 0; i < 8; ++i)
|
||||
bits1[i] = bits2[i] = 0;
|
||||
for (int shift = 0; shift < 4; ++shift)
|
||||
{
|
||||
byte bit = (byte)(1 << shift);
|
||||
FillBits (bits1, bit);
|
||||
FillBits (bits2, bit);
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
ctl = m_input.ReadUInt8();
|
||||
if (0xFF == ctl || 0x7F == ctl)
|
||||
break;
|
||||
int pos = (ctl & 0x3F) << 8 | m_input.ReadUInt8();
|
||||
int x = (pos % 80) << 3;
|
||||
int y = (pos / 80) << 1;
|
||||
dst = width * y + x;
|
||||
pblk = x / 4 + quart_width * (y / 2);
|
||||
switch (ctl >> 6)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
int w_count = m_input.ReadUInt8();
|
||||
int h_count = m_input.ReadUInt8();
|
||||
int gap = quart_width - 2 * w_count;
|
||||
while (h_count --> 0)
|
||||
{
|
||||
for (int i = 0; i < w_count; ++i)
|
||||
{
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
pixels[dst+width] = bits2[j];
|
||||
pixels[dst++] = bits1[j];
|
||||
}
|
||||
blockmap[pblk++] = true;
|
||||
blockmap[pblk++] = true;
|
||||
}
|
||||
pblk += gap;
|
||||
dst += 2 * width - 8 * w_count;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
int count = m_input.ReadUInt8();
|
||||
while (count --> 0)
|
||||
{
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
pixels[dst+width] = bits2[j];
|
||||
pixels[dst++] = bits1[j];
|
||||
}
|
||||
blockmap[pblk++] = true;
|
||||
blockmap[pblk++] = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
int count = m_input.ReadUInt8();
|
||||
while (count --> 0)
|
||||
{
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
pixels[dst+width] = bits2[j];
|
||||
pixels[dst++] = bits1[j];
|
||||
}
|
||||
blockmap[pblk ] = true;
|
||||
blockmap[pblk+1] = true;
|
||||
dst += 2 * width - 8;
|
||||
pblk += quart_width;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
pixels[dst+width] = bits2[j];
|
||||
pixels[dst++] = bits1[j];
|
||||
}
|
||||
blockmap[pblk ] = true;
|
||||
blockmap[pblk+1] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (ctl != 0xFF);
|
||||
do
|
||||
{
|
||||
for (int i = 0; i < 8; ++i)
|
||||
bits1[i] = 0;
|
||||
for (int shift = 0; shift < 4; ++shift)
|
||||
FillBits (bits1, (byte)(1 << shift));
|
||||
for (;;)
|
||||
{
|
||||
ctl = m_input.ReadUInt8();
|
||||
if (0xFF == ctl || 0xFE == ctl)
|
||||
break;
|
||||
int pos = (ctl & 0x7F) << 8 | m_input.ReadUInt8();
|
||||
dst = 4 * (pos % 160) + width * 2 * (pos / 160);
|
||||
pblk = (pos % 160) + quart_width * (pos / 160);
|
||||
if ((ctl & 0x80) == 0)
|
||||
{
|
||||
int count = m_input.ReadUInt8();
|
||||
while (count --> 0)
|
||||
{
|
||||
for (int j = 0; j < 4; ++j)
|
||||
{
|
||||
pixels[dst+width] = bits1[j+4];
|
||||
pixels[dst++] = bits1[j];
|
||||
}
|
||||
blockmap[pblk] = true;
|
||||
pblk += quart_width;
|
||||
dst += 2 * width - 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = 0; j < 4; ++j)
|
||||
{
|
||||
pixels[dst+width] = bits1[j+4];
|
||||
pixels[dst++] = bits1[j];
|
||||
}
|
||||
blockmap[pblk] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (ctl != 0xFF);
|
||||
dst = 0;
|
||||
pblk = 0;
|
||||
for (int y = 0; y < half_height; ++y)
|
||||
{
|
||||
for (int x = 0; x < quart_width; ++x)
|
||||
{
|
||||
if (blockmap[pblk++])
|
||||
{
|
||||
dst += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 8; ++i)
|
||||
bits1[i] = 0;
|
||||
for (int shift = 0; shift < 4; ++shift)
|
||||
FillBits (bits1, (byte)(1 << shift));
|
||||
for (int j = 0; j < 4; ++j)
|
||||
{
|
||||
pixels[dst+width] = bits1[j+4];
|
||||
pixels[dst++] = bits1[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
dst += width;
|
||||
}
|
||||
return ImageData.Create (m_info, PixelFormats.Indexed8, palette, pixels, output_stride);
|
||||
}
|
||||
|
||||
void FillBits (byte[] bits, byte bit)
|
||||
{
|
||||
sbyte s = m_input.ReadInt8();
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (s < 0)
|
||||
bits[i] |= bit;
|
||||
s <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static readonly string PaletteKey = "NEKOTARO";
|
||||
|
||||
BitmapPalette ReadPalette ()
|
||||
{
|
||||
int k = 0;
|
||||
var colors = new Color[16];
|
||||
for (int c = 0; c < 16; ++c)
|
||||
{
|
||||
int g = m_input.ReadUInt8();
|
||||
int r = m_input.ReadUInt8();
|
||||
int b = m_input.ReadUInt8();
|
||||
b = (~b - PaletteKey[k++ & 7]) & 0xFF;
|
||||
r = (~r - PaletteKey[k++ & 7]) & 0xFF;
|
||||
g = (~g - PaletteKey[k++ & 7]) & 0xFF;
|
||||
colors[c] = Color.FromRgb ((byte)(r * 0x11), (byte)(g * 0x11), (byte)(b * 0x11));
|
||||
}
|
||||
return new BitmapPalette (colors);
|
||||
}
|
||||
}
|
||||
}
|
125
Legacy/Ponytail/ArcBND.cs
Normal file
125
Legacy/Ponytail/ArcBND.cs
Normal file
@ -0,0 +1,125 @@
|
||||
//! \file ArcBND.cs
|
||||
//! \date 2023 Sep 28
|
||||
//! \brief Ponytail Adventure System resource archive.
|
||||
//
|
||||
// Copyright (C) 2023 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 GameRes.Utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
// [951115][Ponytail Soft] Masuzume Yume
|
||||
|
||||
namespace GameRes.Formats.Ponytail
|
||||
{
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class BndOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag => "BND/NMI";
|
||||
public override string Description => "Ponytail Soft resource archive";
|
||||
public override uint Signature => 0x646E6942; // 'Bind'
|
||||
public override bool IsHierarchic => false;
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
if (!file.View.AsciiEqual (4, " ver.0"))
|
||||
return null;
|
||||
int count = file.View.ReadInt16 (0xD);
|
||||
if (!IsSaneCount (count))
|
||||
return null;
|
||||
uint index_offset = file.View.ReadUInt32 (0xF);
|
||||
if (index_offset >= file.MaxOffset)
|
||||
return null;
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
var name = file.View.ReadString (index_offset, 8).Trim();
|
||||
var ext = file.View.ReadString (index_offset+8, 3);
|
||||
name = name + '.' + ext;
|
||||
var entry = Create<PackedEntry> (name);
|
||||
entry.Size = file.View.ReadUInt32 (index_offset+0x0C);
|
||||
entry.Offset = file.View.ReadUInt32 (index_offset+0x14);
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
index_offset += 0x18;
|
||||
}
|
||||
foreach (PackedEntry entry in dir.Where (e => e.Name.EndsWith ("Z") && e.Type != "image"))
|
||||
{
|
||||
if (file.View.AsciiEqual (entry.Offset, "lz1_"))
|
||||
{
|
||||
entry.IsPacked = true;
|
||||
char last_chr =(char)file.View.ReadByte (entry.Offset+4);
|
||||
entry.UnpackedSize = file.View.ReadUInt32 (entry.Offset+5);
|
||||
string name = entry.Name.Remove (entry.Name.Length-1);
|
||||
entry.Name = name + char.ToUpperInvariant (last_chr);
|
||||
}
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
var pent = (PackedEntry)entry;
|
||||
if (!pent.IsPacked)
|
||||
return base.OpenEntry (arc, entry);
|
||||
var output = new byte[pent.UnpackedSize];
|
||||
using (var input = arc.File.CreateStream (pent.Offset+9, pent.Size-9))
|
||||
Lz1Unpack (input, output);
|
||||
return new BinMemoryStream (output, pent.Name);
|
||||
}
|
||||
|
||||
internal static void Lz1Unpack (IBinaryStream input, byte[] output)
|
||||
{
|
||||
byte mask = 0;
|
||||
int ctl = 0;
|
||||
int dst = 0;
|
||||
while (dst < output.Length)
|
||||
{
|
||||
mask <<= 1;
|
||||
if (0 == mask)
|
||||
{
|
||||
ctl = input.ReadUInt8();
|
||||
if (ctl < 0)
|
||||
break;
|
||||
mask = 1;
|
||||
}
|
||||
if ((ctl & mask) != 0)
|
||||
{
|
||||
output[dst++] = input.ReadUInt8();
|
||||
}
|
||||
else
|
||||
{
|
||||
int code = input.ReadUInt16();
|
||||
int offset = (code >> 5) + 1;
|
||||
int count = Math.Min (3 + (code & 0x1F), output.Length - dst);
|
||||
Binary.CopyOverlapped (output, dst - offset, dst, count);
|
||||
dst += count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
212
Legacy/Ponytail/ImageTCZ.cs
Normal file
212
Legacy/Ponytail/ImageTCZ.cs
Normal file
@ -0,0 +1,212 @@
|
||||
//! \file ImageTCZ.cs
|
||||
//! \date 2023 Sep 28
|
||||
//! \brief Ponytail NMI 2.5 image format (PC-98).
|
||||
//
|
||||
// Copyright (C) 2023 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 GameRes.Utility;
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
// Graphics driver version 0.3 95/10/30
|
||||
// by Y.Nakamura / NARIMI.A
|
||||
|
||||
namespace GameRes.Formats.Ponytail
|
||||
{
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class TczFormat : ImageFormat
|
||||
{
|
||||
public override string Tag => "TCZ";
|
||||
public override string Description => "Ponytail Soft NMI image format";
|
||||
public override uint Signature => 0x20494D4E; // 'NMI '
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
var header = file.ReadHeader (0x10);
|
||||
if (!header.AsciiEqual (4, "2.5\0"))
|
||||
return null;
|
||||
var info = new ImageMetaData {
|
||||
Width = header.ToUInt16 (0xC),
|
||||
Height = header.ToUInt16 (0xE),
|
||||
OffsetX = header.ToInt16 (0x8),
|
||||
OffsetY = header.ToInt16 (0xA),
|
||||
BPP = 4,
|
||||
};
|
||||
if (info.Height > TczReader.MaxHeight)
|
||||
return null;
|
||||
return info;
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
var reader = new TczReader (file, info);
|
||||
return reader.Unpack();
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("TczFormat.Write not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
internal class TczReader : TszReader
|
||||
{
|
||||
internal const int MaxHeight = 0x190;
|
||||
const int BufferSize = MaxHeight * 0x10;
|
||||
|
||||
public TczReader (IBinaryStream input, ImageMetaData info)
|
||||
{
|
||||
m_input = input;
|
||||
m_info = info;
|
||||
m_stride = m_info.iWidth >> 1;
|
||||
}
|
||||
|
||||
byte[] m_buffer;
|
||||
|
||||
static short[] s_offTable0 = { -4, -3, -2, -1, 0, 1, 2, 3 };
|
||||
static short[] s_offTable1 = { -16, -8, -6, -4, -3, -2, -1, 0, 1, 2, 3, 4, 6, 8, 10, 16 };
|
||||
|
||||
public new ImageData Unpack ()
|
||||
{
|
||||
m_input.Position = 0x10;
|
||||
var palette = ReadPalette();
|
||||
var output = new byte[m_stride * m_info.iHeight];
|
||||
FillBuffers();
|
||||
ResetBitReader();
|
||||
int dst = 2;
|
||||
int output_pos = 0;
|
||||
int x = 0;
|
||||
while (x < m_stride)
|
||||
{
|
||||
int y = 0;
|
||||
while (y < m_info.iHeight)
|
||||
{
|
||||
if (GetNextBit()) // @1@
|
||||
{
|
||||
int src = dst;
|
||||
if (!GetNextBit()) // @2@
|
||||
{
|
||||
src += m_lineOffsets1[1];
|
||||
int off = GetBits (4);
|
||||
src += s_offTable1[off];
|
||||
}
|
||||
else if (!GetNextBit()) // @3@
|
||||
{
|
||||
src += GetBits (2) - 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!GetNextBit()) // @4@
|
||||
{
|
||||
src += m_lineOffsets1[2];
|
||||
}
|
||||
else if (!GetNextBit()) // @5@
|
||||
{
|
||||
src += m_lineOffsets1[4];
|
||||
}
|
||||
else
|
||||
{
|
||||
src += m_lineOffsets1[8];
|
||||
}
|
||||
int off = GetBits (3);
|
||||
src += s_offTable0[off];
|
||||
}
|
||||
src &= 0xFFFF;
|
||||
int count = GetBitLength() + 1;
|
||||
Binary.CopyOverlapped (m_buffer, src, dst, count);
|
||||
y += count;
|
||||
dst += count;
|
||||
}
|
||||
else
|
||||
{
|
||||
int bx = m_buffer[dst-2];
|
||||
bx = (bx << 8 | bx) & 0xF00F;
|
||||
if (GetNextBit()) // @8@
|
||||
{
|
||||
int ax = GetBits (4);
|
||||
bx = (bx & 0xFF) | ax << 12;
|
||||
}
|
||||
if (GetNextBit()) // @9@
|
||||
{
|
||||
int ax = GetBits (4);
|
||||
bx = (bx & 0xFF00) | ax;
|
||||
}
|
||||
bx = (bx & 0xFF) | (bx >> 8);
|
||||
m_buffer[dst++] = (byte)bx;
|
||||
++y;
|
||||
}
|
||||
}
|
||||
++x;
|
||||
if ((x & 3) == 0)
|
||||
{
|
||||
CopyScanline (m_lineOffsets0[(x - 1) & 0xC], output, output_pos);
|
||||
output_pos += 4;
|
||||
}
|
||||
int z = x & 0xF;
|
||||
dst = m_lineOffsets0[z];
|
||||
if (z != 0)
|
||||
{
|
||||
m_lineOffsets1[z] -= BufferSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 1; i < 16; ++i)
|
||||
{
|
||||
m_lineOffsets1[i] += BufferSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ImageData.Create (m_info, PixelFormats.Indexed4, palette, output, m_stride);
|
||||
}
|
||||
|
||||
ushort[] m_lineOffsets0 = new ushort[16];
|
||||
ushort[] m_lineOffsets1 = new ushort[16];
|
||||
|
||||
void FillBuffers ()
|
||||
{
|
||||
m_buffer = new byte[BufferSize + MaxHeight];
|
||||
m_buffer[0] = m_buffer[1] = 3;
|
||||
ushort p = 2;
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
m_lineOffsets1[i] = (ushort)(((16 - i) & 0xF) * MaxHeight);
|
||||
m_lineOffsets0[i] = p;
|
||||
p += MaxHeight;
|
||||
}
|
||||
}
|
||||
|
||||
void CopyScanline (int src, byte[] output, int dst)
|
||||
{
|
||||
for (int i = 0; i < m_info.iHeight; ++i)
|
||||
{
|
||||
output[dst ] = m_buffer[src + i ];
|
||||
output[dst+1] = m_buffer[src + i + MaxHeight ];
|
||||
output[dst+2] = m_buffer[src + i + MaxHeight*2];
|
||||
output[dst+3] = m_buffer[src + i + MaxHeight*3];
|
||||
dst += m_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
330
Legacy/Ponytail/ImageTSZ.cs
Normal file
330
Legacy/Ponytail/ImageTSZ.cs
Normal file
@ -0,0 +1,330 @@
|
||||
//! \file ImageTSZ.cs
|
||||
//! \date 2023 Sep 27
|
||||
//! \brief Ponytail NMI 2.05 image format (PC-98).
|
||||
//
|
||||
// Copyright (C) 2023 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;
|
||||
|
||||
// [930413][Ponytail Soft] Yougen Doumu
|
||||
|
||||
namespace GameRes.Formats.Ponytail
|
||||
{
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class TszFormat : ImageFormat
|
||||
{
|
||||
public override string Tag => "TSZ";
|
||||
public override string Description => "Ponytail Soft NMI image format";
|
||||
public override uint Signature => 0x20494D4E; // 'NMI '
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
var header = file.ReadHeader (0x10);
|
||||
if (!header.AsciiEqual (4, "2.05"))
|
||||
return null;
|
||||
return new ImageMetaData {
|
||||
Width = (uint)header.ToUInt16 (0xC) << 2,
|
||||
Height = header.ToUInt16 (0xE),
|
||||
BPP = 4,
|
||||
};
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
var reader = new TszReader (file, info);
|
||||
return reader.Unpack();
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("TszFormat.Write not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
internal class TszReader
|
||||
{
|
||||
protected IBinaryStream m_input;
|
||||
protected ImageMetaData m_info;
|
||||
protected int m_stride;
|
||||
|
||||
protected TszReader () { }
|
||||
|
||||
public TszReader (IBinaryStream input, ImageMetaData info)
|
||||
{
|
||||
m_input = input;
|
||||
m_info = info;
|
||||
m_stride = m_info.iWidth >> 1;
|
||||
}
|
||||
|
||||
private int m_previous_row;
|
||||
private ushort[] m_linebuffer;
|
||||
private int m_dst;
|
||||
|
||||
public ImageData Unpack ()
|
||||
{
|
||||
m_input.Position = 0x10;
|
||||
var palette = ReadPalette();
|
||||
var output = new byte[m_stride * m_info.iHeight];
|
||||
m_linebuffer = new ushort[m_info.iHeight * 2];
|
||||
m_previous_row = m_info.iHeight;
|
||||
int width = m_info.iWidth >> 2;
|
||||
int dst_x = 0;
|
||||
int x = 0;
|
||||
ResetBitReader();
|
||||
while (x < width)
|
||||
{
|
||||
int y = 0;
|
||||
m_dst = 0;
|
||||
if ((x & 1) != 0)
|
||||
m_dst += m_info.iHeight;
|
||||
while (y < m_info.iHeight)
|
||||
{
|
||||
int ctl = 0;
|
||||
while (GetNextBit())
|
||||
{
|
||||
++ctl;
|
||||
}
|
||||
int count; // bx
|
||||
switch (ctl)
|
||||
{
|
||||
case 0: count = CopyMethod0(); break;
|
||||
case 1: count = CopyMethod1(); break;
|
||||
case 2:
|
||||
m_linebuffer[m_dst] = m_input.ReadUInt16();
|
||||
count = 1;
|
||||
break;
|
||||
case 3: count = CopyMethod3(); break;
|
||||
case 4: count = CopyMethod4(); break;
|
||||
default: throw new InvalidFormatException();
|
||||
}
|
||||
m_dst += count;
|
||||
y += count;
|
||||
}
|
||||
if ((x & 1) != 0)
|
||||
{
|
||||
CopyScanline (output, dst_x);
|
||||
dst_x += 4;
|
||||
}
|
||||
m_previous_row = -m_previous_row;
|
||||
++x;
|
||||
}
|
||||
return ImageData.Create (m_info, PixelFormats.Indexed4, palette, output, m_stride);
|
||||
}
|
||||
|
||||
void CopyScanline (byte[] output, int dst)
|
||||
{
|
||||
for (int i = 0; i < m_info.iHeight; ++i)
|
||||
{
|
||||
ushort px1 = m_linebuffer[i];
|
||||
ushort px2 = m_linebuffer[i + m_info.iHeight];
|
||||
// these bytes contain 8 pixels that are being put into 4 planes
|
||||
int b0 = (px1 << 4) & 0xF0 | (px2 ) & 0x0F;
|
||||
int b1 = (px1 ) & 0xF0 | (px2 >> 4) & 0x0F;
|
||||
int b2 = (px1 >> 4) & 0xF0 | (px2 >> 8) & 0x0F;
|
||||
int b3 = (px1 >> 8) & 0xF0 | (px2 >> 12) & 0x0F;
|
||||
// repack pixels into flat surface, 2 pixels per byte
|
||||
for (int j = 0; j < 8; j += 2)
|
||||
{
|
||||
byte px = (byte)((((b0 << j) & 0x80) >> 3)
|
||||
| (((b1 << j) & 0x80) >> 2)
|
||||
| (((b2 << j) & 0x80) >> 1)
|
||||
| (((b3 << j) & 0x80) ));
|
||||
px |= (byte)((((b0 << j) & 0x40) >> 6)
|
||||
| (((b1 << j) & 0x40) >> 5)
|
||||
| (((b2 << j) & 0x40) >> 4)
|
||||
| (((b3 << j) & 0x40) >> 3));
|
||||
output[dst+j/2] = px;
|
||||
}
|
||||
dst += m_stride;
|
||||
}
|
||||
}
|
||||
|
||||
int CopyMethod0 ()
|
||||
{
|
||||
int count = GetBitLength();
|
||||
int offset = GetBits (4);
|
||||
offset += m_previous_row - 8;
|
||||
CopyOverlapped (m_linebuffer, m_dst + offset, m_dst, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
int CopyMethod1 ()
|
||||
{
|
||||
int count = GetBitLength();
|
||||
int offset = m_input.ReadUInt8();
|
||||
offset += m_previous_row - 0x80;
|
||||
CopyOverlapped (m_linebuffer, m_dst + offset, m_dst, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
int CopyMethod3 ()
|
||||
{
|
||||
int count = GetBitLength();
|
||||
int offset = GetBits (4);
|
||||
offset -= 0x10;
|
||||
CopyOverlapped (m_linebuffer, m_dst + offset, m_dst, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
int CopyMethod4 ()
|
||||
{
|
||||
byte al = m_input.ReadUInt8();
|
||||
int nibble = al >> 4;
|
||||
ushort mask1 = s_pattern1[al >> 4];
|
||||
ushort mask2 = s_pattern2[al & 0xF];
|
||||
ushort pixel = m_linebuffer[m_dst + m_previous_row];
|
||||
pixel &= mask1;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
short carry = (short)(nibble & 1);
|
||||
nibble >>= 1;
|
||||
pixel |= (ushort)(-carry & mask2);
|
||||
pixel = RotU16R (pixel, 1);
|
||||
}
|
||||
pixel = RotU16L (pixel, 4);
|
||||
m_linebuffer[m_dst] = pixel;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static readonly ushort[] s_pattern1 = new ushort[] {
|
||||
0xFFFF, 0xEEEE, 0xDDDD, 0xCCCC, 0xBBBB, 0xAAAA, 0x9999, 0x8888,
|
||||
0x7777, 0x6666, 0x5555, 0x4444, 0x3333, 0x2222, 0x1111, 0x0000,
|
||||
};
|
||||
static readonly ushort[] s_pattern2 = new ushort[] {
|
||||
0x0000, 0x0001, 0x0010, 0x0011, 0x0100, 0x0101, 0x0110, 0x0111,
|
||||
0x1000, 0x1001, 0x1010, 0x1011, 0x1100, 0x1101, 0x1110, 0x1111,
|
||||
};
|
||||
|
||||
ushort m_bits;
|
||||
int m_bit_count;
|
||||
|
||||
protected void ResetBitReader ()
|
||||
{
|
||||
m_bits = 0;
|
||||
m_bit_count = 0;
|
||||
}
|
||||
|
||||
protected int GetBitLength ()
|
||||
{
|
||||
if (!GetNextBit())
|
||||
return 1;
|
||||
int count = 1;
|
||||
while (GetNextBit())
|
||||
{
|
||||
++count;
|
||||
}
|
||||
return GetBits (count) | 1 << count;
|
||||
}
|
||||
|
||||
protected bool GetNextBit ()
|
||||
{
|
||||
if (--m_bit_count < 0)
|
||||
{
|
||||
m_bits = m_input.ReadUInt16();
|
||||
m_bit_count = 15;
|
||||
}
|
||||
bool bit = (m_bits & 0x8000) != 0;
|
||||
m_bits <<= 1;
|
||||
return bit;
|
||||
}
|
||||
|
||||
static readonly ushort[] s_bit_mask = new ushort[] {
|
||||
0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
|
||||
};
|
||||
|
||||
protected int GetBits (int count)
|
||||
{
|
||||
m_bit_count -= count;
|
||||
if (m_bit_count < 0)
|
||||
{
|
||||
m_bits = RotU16L (m_bits, count);
|
||||
int cl = -m_bit_count;
|
||||
ushort bits = m_input.ReadUInt16();
|
||||
bits = RotU16L (bits, cl);
|
||||
ushort mask = s_bit_mask[cl];
|
||||
ushort new_bits = (ushort)(bits & ~mask);
|
||||
bits &= mask;
|
||||
bits |= m_bits;
|
||||
m_bits = new_bits;
|
||||
m_bit_count = 16 - cl;
|
||||
return bits;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bits = RotU16L (m_bits, count);
|
||||
ushort mask = s_bit_mask[count];
|
||||
int bits = m_bits & mask;
|
||||
m_bits &= (ushort)~mask;
|
||||
return bits;
|
||||
}
|
||||
}
|
||||
|
||||
protected BitmapPalette ReadPalette ()
|
||||
{
|
||||
const int count = 16;
|
||||
var colors = new Color[count];
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
byte r = m_input.ReadUInt8();
|
||||
byte g = m_input.ReadUInt8();
|
||||
byte b = m_input.ReadUInt8();
|
||||
colors[i] = Color.FromRgb ((byte)(r * 0x11), (byte)(g * 0x11), (byte)(b * 0x11));
|
||||
}
|
||||
return new BitmapPalette (colors);
|
||||
}
|
||||
|
||||
static internal ushort RotU16L (ushort val, int count)
|
||||
{
|
||||
return (ushort)(val << count | val >> (16 - count));
|
||||
}
|
||||
|
||||
static internal ushort RotU16R (ushort val, int count)
|
||||
{
|
||||
return (ushort)(val >> count | val << (16 - count));
|
||||
}
|
||||
|
||||
static internal void CopyOverlapped (ushort[] data, int src, int dst, int count)
|
||||
{
|
||||
src <<= 1;
|
||||
dst <<= 1;
|
||||
count <<= 1;
|
||||
if (dst > src)
|
||||
{
|
||||
while (count > 0)
|
||||
{
|
||||
int preceding = Math.Min (dst - src, count);
|
||||
Buffer.BlockCopy (data, src, data, dst, preceding);
|
||||
dst += preceding;
|
||||
count -= preceding;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy (data, src, data, dst, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion ("1.0.10.208")]
|
||||
[assembly: AssemblyFileVersion ("1.0.10.208")]
|
||||
[assembly: AssemblyVersion ("1.0.10.210")]
|
||||
[assembly: AssemblyFileVersion ("1.0.10.210")]
|
||||
|
146
Legacy/Sophia/ArcNOR.cs
Normal file
146
Legacy/Sophia/ArcNOR.cs
Normal file
@ -0,0 +1,146 @@
|
||||
//! \file ArcNOR.cs
|
||||
//! \date 2023 Sep 26
|
||||
//! \brief Sophia resource archive.
|
||||
//
|
||||
// Copyright (C) 2023 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;
|
||||
|
||||
// [991210][Sophia] Film Noir
|
||||
|
||||
namespace GameRes.Formats.Sophia
|
||||
{
|
||||
internal class NorEntry : PackedEntry
|
||||
{
|
||||
public int Method;
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class NorOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag => "NOR";
|
||||
public override string Description => "Sophia resource archive";
|
||||
public override uint Signature => 0;
|
||||
public override bool IsHierarchic => false;
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
int count = file.View.ReadInt32 (0);
|
||||
if (!file.View.AsciiEqual (4, "NRCOMB01\0") || !IsSaneCount (count))
|
||||
return null;
|
||||
var dir = new List<Entry> (count);
|
||||
using (var index = file.CreateStream())
|
||||
{
|
||||
index.Position = 0x10;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
uint offset = index.ReadUInt32();
|
||||
uint size = index.ReadUInt32();
|
||||
string name = index.ReadCString();
|
||||
var entry = Create<NorEntry> (name);
|
||||
entry.Offset = offset;
|
||||
entry.Size = size;
|
||||
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 nent = (NorEntry)entry;
|
||||
if (!nent.IsPacked)
|
||||
{
|
||||
if (nent.Method == 0x1F4 || nent.Method == 0x67
|
||||
|| !arc.File.View.AsciiEqual (nent.Offset, "NCMB01"))
|
||||
return base.OpenEntry (arc, nent);
|
||||
nent.Method = arc.File.View.ReadInt32 (nent.Offset+0x28);
|
||||
if (nent.Method == 0x1F4 || nent.Method == 0x67)
|
||||
{
|
||||
nent.Size = arc.File.View.ReadUInt32 (nent.Offset+0x24);
|
||||
nent.Offset += 0x2C;
|
||||
return base.OpenEntry (arc, nent);
|
||||
}
|
||||
nent.IsPacked = true;
|
||||
nent.UnpackedSize = arc.File.View.ReadUInt32 (nent.Offset+0x24);
|
||||
nent.Size = arc.File.View.ReadUInt32 (nent.Offset+0x10);
|
||||
nent.Offset += 0x2C;
|
||||
}
|
||||
using (var input = arc.File.CreateStream (nent.Offset, nent.Size))
|
||||
{
|
||||
var output = new byte[nent.UnpackedSize];
|
||||
NcmbDecompress (input, output);
|
||||
return new BinMemoryStream (output, nent.Name);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void NcmbDecompress (IBinaryStream input, byte[] output)
|
||||
{
|
||||
var dict = new int[0xC00];
|
||||
int root = input.ReadInt32();
|
||||
int tree_size = input.ReadInt32();
|
||||
int unpacked_size = input.ReadInt32();
|
||||
int count = root + tree_size - 0xFF;
|
||||
while (count --> 0)
|
||||
{
|
||||
int token = 6 * input.ReadInt32();
|
||||
dict[token ] = input.ReadInt32();
|
||||
dict[token + 1] = input.ReadInt32();
|
||||
}
|
||||
if (unpacked_size > 0)
|
||||
{
|
||||
int cur_byte = 0;
|
||||
int mask = 0;
|
||||
for (int dst = 0; dst < unpacked_size; ++dst)
|
||||
{
|
||||
int token = root;
|
||||
do
|
||||
{
|
||||
if (0 == mask)
|
||||
{
|
||||
cur_byte = input.ReadUInt8();
|
||||
mask = 0x80;
|
||||
}
|
||||
if ((cur_byte & mask) != 0)
|
||||
token = dict[6 * token + 1];
|
||||
else
|
||||
token = dict[6 * token];
|
||||
mask >>= 1;
|
||||
}
|
||||
while (dict[6 * token] != -1);
|
||||
output[dst] = (byte)token;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Export(typeof(ResourceAlias))]
|
||||
[ExportMetadata("Extension", "M")]
|
||||
[ExportMetadata("Target", "MP3")]
|
||||
[ExportMetadata("Type", "audio")]
|
||||
public class MFormat : ResourceAlias { }
|
||||
}
|
114
Legacy/SquadraD/ArcPLA.cs
Normal file
114
Legacy/SquadraD/ArcPLA.cs
Normal file
@ -0,0 +1,114 @@
|
||||
//! \file ArcPLA.cs
|
||||
//! \date 2023 Sep 26
|
||||
//! \brief Squadra D audio archive.
|
||||
//
|
||||
// Copyright (C) 2023 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.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
|
||||
namespace GameRes.Formats.SquadraD
|
||||
{
|
||||
internal class PlaEntry : PackedEntry
|
||||
{
|
||||
public int Id;
|
||||
public int n1;
|
||||
public uint SampleRate;
|
||||
public int Channels;
|
||||
public byte n2;
|
||||
public byte n3;
|
||||
public int[] Data;
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class PlaOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag => "PLA";
|
||||
public override string Description => "Squadra D audio archive";
|
||||
public override uint Signature => 0x2E616C50; // 'Pla.'
|
||||
public override bool IsHierarchic => false;
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
uint arc_size = file.View.ReadUInt32 (4);
|
||||
if (arc_size != file.MaxOffset || file.View.ReadUInt32 (0x10) != 2)
|
||||
return null;
|
||||
uint check = (arc_size & 0xD5555555u) << 1 | arc_size & 0xAAAAAAAAu;
|
||||
if (check != file.View.ReadUInt32 (8))
|
||||
return null;
|
||||
int count = file.View.ReadUInt16 (0xE);
|
||||
if (!IsSaneCount (count))
|
||||
return null;
|
||||
|
||||
var dir = new List<Entry> (count);
|
||||
using (var index = file.CreateStream())
|
||||
{
|
||||
index.Position = 0x14;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
var entry = new PlaEntry {
|
||||
Id = index.ReadInt32()
|
||||
};
|
||||
entry.Name = entry.Id.ToString ("D5");
|
||||
dir.Add (entry);
|
||||
}
|
||||
foreach (PlaEntry entry in dir)
|
||||
{
|
||||
entry.n1 = index.ReadInt32();
|
||||
entry.SampleRate = index.ReadUInt32();
|
||||
entry.Channels = index.ReadInt32();
|
||||
entry.n2 = index.ReadUInt8();
|
||||
entry.n3 = index.ReadUInt8();
|
||||
index.ReadInt16();
|
||||
}
|
||||
foreach (PlaEntry entry in dir)
|
||||
{
|
||||
entry.Offset = index.ReadUInt32();
|
||||
}
|
||||
foreach (PlaEntry entry in dir)
|
||||
{
|
||||
int n = entry.Channels * 2;
|
||||
entry.Data = new int[n];
|
||||
for (int j = 0; j < n; ++j)
|
||||
entry.Data[j] = index.ReadInt32();
|
||||
}
|
||||
}
|
||||
long last_offset = file.MaxOffset;
|
||||
for (int i = dir.Count - 1; i >= 0; --i)
|
||||
{
|
||||
dir[i].Size = (uint)(last_offset - dir[i].Offset);
|
||||
last_offset = dir[i].Offset;
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
|
||||
/*
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
return base.OpenEntry (arc, entry);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
121
Legacy/SquadraD/ArcSDA.cs
Normal file
121
Legacy/SquadraD/ArcSDA.cs
Normal file
@ -0,0 +1,121 @@
|
||||
//! \file ArcSDA.cs
|
||||
//! \date 2023 Sep 26
|
||||
//! \brief Squadra D resource archive format.
|
||||
//
|
||||
// Copyright (C) 2023 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.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
|
||||
namespace GameRes.Formats.SquadraD
|
||||
{
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class SdaOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag => "SDA/SD";
|
||||
public override string Description => "Squadra D resource archive";
|
||||
public override uint Signature => 0x4153; // 'SA'
|
||||
public override bool IsHierarchic => false;
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public SdaOpener ()
|
||||
{
|
||||
Signatures = new[] { 0x4153u, 0xCC004153u, 0u };
|
||||
}
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
if (!file.View.AsciiEqual (0, "SA\0"))
|
||||
return null;
|
||||
int data_offset = file.View.ReadInt32 (4);
|
||||
if (data_offset <= 8 || data_offset >= file.MaxOffset)
|
||||
return null;
|
||||
int count = (data_offset - 8) / 0x14;
|
||||
if (!IsSaneCount (count))
|
||||
return null;
|
||||
string arc_name = Path.GetFileNameWithoutExtension (file.Name);
|
||||
bool is_cg = arc_name == "g";
|
||||
uint index = 8;
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
var name = file.View.ReadString (index, 0x10).Trim();;
|
||||
var entry = Create<Entry> (name);
|
||||
entry.Offset = file.View.ReadUInt32 (index+0xC) + data_offset;
|
||||
entry.Size = file.View.ReadUInt32 (index+0x10);
|
||||
if (is_cg)
|
||||
entry.Type = "image";
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
index += 0x14;
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
using (var input = arc.File.CreateStream (entry.Offset, entry.Size))
|
||||
{
|
||||
var data = LzssDecompress (input);
|
||||
return new BinMemoryStream (data, entry.Name);
|
||||
}
|
||||
}
|
||||
|
||||
internal static byte[] LzssDecompress (IBinaryStream input)
|
||||
{
|
||||
int unpacked_size = input.ReadInt32();
|
||||
var output = new byte[unpacked_size];
|
||||
using (var bits = new LsbBitStream (input.AsStream, true))
|
||||
{
|
||||
var frame = new byte[0x1000];
|
||||
int frame_pos = 0xFC0;
|
||||
int dst = 0;
|
||||
while (dst < unpacked_size)
|
||||
{
|
||||
if (bits.GetNextBit() == 0)
|
||||
{
|
||||
byte b = (byte)bits.GetBits (8);
|
||||
output[dst++] = frame[frame_pos++ & 0xFFF] = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
int count_len = 4;
|
||||
if (bits.GetNextBit() != 0)
|
||||
count_len = 6;
|
||||
int offset = bits.GetBits (12);
|
||||
int count = bits.GetBits (count_len);
|
||||
count = Math.Min (count + 3, unpacked_size - dst);
|
||||
while (count --> 0)
|
||||
{
|
||||
byte b = frame[offset++ & 0xFFF];
|
||||
output[dst++] = frame[frame_pos++ & 0xFFF] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -74,13 +74,15 @@ namespace GameRes.Formats.WestGate
|
||||
uint next_offset = file.View.ReadUInt32 (index_offset+0xC);
|
||||
if (next_offset < data_offset)
|
||||
return null;
|
||||
string last_name = null;
|
||||
var invalid_chars = Path.GetInvalidFileNameChars();
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
var name = file.View.ReadString (index_offset, 0xC);
|
||||
if (string.IsNullOrWhiteSpace (name) || name.IndexOfAny (invalid_chars) != -1)
|
||||
if (last_name == name || string.IsNullOrWhiteSpace (name) || name.IndexOfAny (invalid_chars) != -1)
|
||||
return null;
|
||||
last_name = name;
|
||||
index_offset += 0x10;
|
||||
var entry = new Entry { Name = name, Type = entry_type };
|
||||
entry.Offset = next_offset;
|
||||
|
Loading…
Reference in New Issue
Block a user