Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ArcFormats/ArcFormats.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@
<Compile Include="Psp\ArcQPK.cs" />
<Compile Include="QoiCodec.cs" />
<Compile Include="ScrPlayer\ImageIMG.cs" />
<Compile Include="Silky\ImageMMO.cs" />
<Compile Include="SingleFileArchive.cs" />
<Compile Include="Software House Parsley\ArcCG3.cs" />
<Compile Include="Software House Parsley\ArcScn.cs" />
Expand Down
26 changes: 24 additions & 2 deletions ArcFormats/Silky/ImageAKB.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ internal class AkbMetaData : ImageMetaData
public uint Flags;
public string BaseFileName;
public uint DataOffset;
public bool TopDownOrder;
}

[Export(typeof(ImageFormat))]
Expand Down Expand Up @@ -150,13 +151,34 @@ public byte[] Unpack (byte[] background = null)
var pixels = new byte[m_info.InnerHeight * inner_stride];
using (var lz = new LzssStream (m_input, LzssMode.Decompress, true))
{
for (int pos = pixels.Length - inner_stride; pos >= 0; pos -= inner_stride)
if (m_info.TopDownOrder)
{
if (inner_stride != lz.Read (pixels, pos, inner_stride))
if (lz.Read(pixels, 0, pixels.Length) != pixels.Length)
{
throw new InvalidFormatException();
}
}
else
{
for (int pos = pixels.Length - inner_stride; pos >= 0; pos -= inner_stride)
{
if (inner_stride != lz.Read (pixels, pos, inner_stride))
throw new InvalidFormatException();
}
}

}
RestoreDelta (pixels, inner_stride);
if (m_info.TopDownOrder)
{
var tmp_stride = new byte[inner_stride];
for (int i = 0, j = m_info.InnerHeight - 1; i < j; ++i, --j)
{
Buffer.BlockCopy(pixels, j * inner_stride, tmp_stride, 0, inner_stride);
Buffer.BlockCopy(pixels, i * inner_stride, pixels, j * inner_stride, inner_stride);
Buffer.BlockCopy(tmp_stride, 0, pixels, i * inner_stride, inner_stride);
}
}
if (null == background && m_info.InnerWidth == m_info.Width && m_info.InnerHeight == m_info.Height)
return pixels;

Expand Down
46 changes: 46 additions & 0 deletions ArcFormats/Silky/ImageMMO.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System.ComponentModel.Composition;

// [070223][Silky's] Himekishi Angelica ~Anata tte, Hontou ni Saitei no Kuzu Da wa!~

namespace GameRes.Formats.Silky
{
[Export(typeof(ImageFormat))]
public class MmoFormat : AkbFormat
{
public override string Tag => "MMO";
public override string Description => "Silky's MMO image format";
public override uint Signature => 0x204F4D4D; // 'MMO '

public MmoFormat()
{
Signatures = new[] { Signature };
}

public override ImageMetaData ReadMetaData(IBinaryStream file)
{
file.Position += 4;
var metaData = new AkbMetaData();
metaData.TopDownOrder = true;
metaData.Flags = 0;
metaData.OffsetX = file.ReadInt32();
metaData.OffsetY = file.ReadInt32();
metaData.InnerWidth = file.ReadInt32() - metaData.OffsetX;
metaData.InnerHeight = file.ReadInt32() - metaData.OffsetY;
// Not sure if there are any other pixel encoding
metaData.BPP = 24;
// Skip 8 byte unknown field
file.Position += 8;
metaData.Width = file.ReadUInt32();
metaData.Height = file.ReadUInt32();
// Skip another 4 byte unknown field
file.Position += 4;
metaData.DataOffset = (uint)file.Position;
// FIXME: Implement reliable way to detect difference image and find the corresponding base image name Find base image
// Unlike AKB format, MMO format has neither mark for difference image nor the name of its base image file embedded.
// Also, there doesn't seem to have a constant naming pattern even in the same game.
metaData.BaseFileName = null;
metaData.Background = new byte[4];
return metaData;
}
}
}
Loading