(Gx4Lib): support diff images.

This commit is contained in:
morkt 2018-11-17 00:43:20 +04:00
parent 8f21e7558a
commit bd79789a30

View File

@ -23,6 +23,8 @@
// IN THE SOFTWARE. // IN THE SOFTWARE.
// //
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition; using System.ComponentModel.Composition;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -32,6 +34,13 @@ using GameRes.Utility;
namespace GameRes.Formats.Unity.Gx4Lib namespace GameRes.Formats.Unity.Gx4Lib
{ {
internal class VisualDiffData
{
public string BaseFileName;
public int PosX;
public int PosY;
}
[Export(typeof(ArchiveFormat))] [Export(typeof(ArchiveFormat))]
public class DatOpener : ArchiveFormat public class DatOpener : ArchiveFormat
{ {
@ -41,6 +50,8 @@ namespace GameRes.Formats.Unity.Gx4Lib
public override bool IsHierarchic { get { return false; } } public override bool IsHierarchic { get { return false; } }
public override bool CanWrite { get { return false; } } public override bool CanWrite { get { return false; } }
Lazy<Dictionary<string, VisualDiffData>> DefaultVisualMap = new Lazy<Dictionary<string, VisualDiffData>> (ReadVisualData);
public override ArcFile TryOpen (ArcView file) public override ArcFile TryOpen (ArcView file)
{ {
uint index_size = file.View.ReadUInt32 (0); uint index_size = file.View.ReadUInt32 (0);
@ -103,6 +114,25 @@ namespace GameRes.Formats.Unity.Gx4Lib
int buf_width = input.ReadInt32(); int buf_width = input.ReadInt32();
int buf_height = input.ReadInt32(); int buf_height = input.ReadInt32();
var info = new ImageMetaData { Width = width, Height = height, BPP = 32 }; var info = new ImageMetaData { Width = width, Height = height, BPP = 32 };
if (DefaultVisualMap.Value.ContainsKey (entry.Name))
{
var diff_info = DefaultVisualMap.Value[entry.Name];
if (VFS.FileExists (diff_info.BaseFileName))
{
var base_entry = VFS.FindFile (diff_info.BaseFileName);
using (var visbase = VFS.OpenImage (base_entry))
{
var base_decoder = visbase as Gx4ImageDecoder;
if (base_decoder != null)
{
info.OffsetX = diff_info.PosX;
info.OffsetY = diff_info.PosY;
var pixels = base_decoder.ReadPixels();
return new Gx4OverlayDecoder (pixels, base_decoder.Info, input, info);
}
}
}
}
return new Gx4ImageDecoder (input, info); return new Gx4ImageDecoder (input, info);
} }
@ -204,26 +234,97 @@ namespace GameRes.Formats.Unity.Gx4Lib
bits >>= 1; bits >>= 1;
} }
} }
internal static Dictionary<string, VisualDiffData> ReadVisualData ()
{
var map = new Dictionary<string, VisualDiffData>();
try
{
FormatCatalog.Instance.ReadFileList ("gx4_bsz_visual.lst", (line) => {
var parts = line.Split (':', ',');
if (parts.Length > 3)
{
var diff = new VisualDiffData { BaseFileName = parts[1] };
if (int.TryParse (parts[2], out diff.PosX) && int.TryParse (parts[3], out diff.PosY))
map[parts[0]] = diff;
}
});
}
catch { /* ignore errors */ }
return map;
}
} }
internal class Gx4ImageDecoder : BinaryImageDecoder internal class Gx4ImageDecoder : BinaryImageDecoder
{ {
public int Stride { get; private set; }
public Gx4ImageDecoder (IBinaryStream input, ImageMetaData info) : base (input, info) public Gx4ImageDecoder (IBinaryStream input, ImageMetaData info) : base (input, info)
{ {
Stride = (int)info.Width * 4;
} }
protected override ImageData GetImageData () public byte[] ReadPixels ()
{ {
m_input.Position = 0x10; m_input.Position = 0x10;
int stride = (int)Info.Width * 4; var pixels = m_input.ReadBytes (Stride * (int)Info.Height);
var pixels = m_input.ReadBytes (stride * (int)Info.Height);
for (int i = 0; i < pixels.Length; i += 4) for (int i = 0; i < pixels.Length; i += 4)
{ {
byte t = pixels[i]; byte t = pixels[i];
pixels[i] = pixels[i+2]; pixels[i] = pixels[i+2];
pixels[i+2] = t; pixels[i+2] = t;
} }
return ImageData.CreateFlipped (Info, PixelFormats.Bgra32, null, pixels, stride); return pixels;
}
protected override ImageData GetImageData ()
{
var pixels = ReadPixels();
return ImageData.CreateFlipped (Info, PixelFormats.Bgra32, null, pixels, Stride);
}
}
internal class Gx4OverlayDecoder : BinaryImageDecoder
{
byte[] m_pixels;
ImageMetaData OverlayInfo { get; set; }
public Gx4OverlayDecoder (byte[] pixels, ImageMetaData info, IBinaryStream input, ImageMetaData overlay_info)
: base (input, info)
{
m_pixels = pixels;
OverlayInfo = overlay_info;
}
protected override ImageData GetImageData ()
{
m_input.Position = 0x10;
int base_stride = (int)Info.Width * 4;
int diff_stride = (int)OverlayInfo.Width * 4;
var diff = m_input.ReadBytes (diff_stride * (int)OverlayInfo.Height);
int dst_line = m_pixels.Length - base_stride * (OverlayInfo.OffsetY + 1) + OverlayInfo.OffsetX * 4;
int src_line = diff.Length - diff_stride;
for (int y = 0; y < (int)OverlayInfo.Height; ++y)
{
int dst = dst_line;
int src = src_line;
for (int x = 0; x < (int)OverlayInfo.Width; ++x)
{
if (!(0 == diff[src] && 0 == diff[src+1] && 0 == diff[src+2] && 0xFF == diff[src+3]))
{
m_pixels[dst ] = diff[src+2];
m_pixels[dst+1] = diff[src+1];
m_pixels[dst+2] = diff[src ];
m_pixels[dst+3] = diff[src+3];
}
dst += 4;
src += 4;
}
dst_line -= base_stride;
src_line -= diff_stride;
}
return ImageData.CreateFlipped (Info, PixelFormats.Bgra32, null, m_pixels, base_stride);
} }
} }
} }