Skip to content

Commit

Permalink
build from combined image, Fix #66
Browse files Browse the repository at this point in the history
  • Loading branch information
UlyssesWu committed Aug 14, 2021
1 parent b106040 commit 7ab7dd7
Show file tree
Hide file tree
Showing 18 changed files with 168 additions and 29 deletions.
7 changes: 4 additions & 3 deletions FreeMote.PsBuild/PsbDecompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,11 @@ public static void DecompileToFile(PSB psb, string outputPath, Dictionary<string
/// <param name="useResx">if false, use array-based resource json (legacy)</param>
/// <param name="key">PSB CryptKey</param>
/// <param name="type">Specify PSB type, if not set, infer type automatically</param>
/// <param name="contextDic">Context, used to set some configurations</param>
public static void DecompileToFile(string inputPath, PsbExtractOption extractOption = PsbExtractOption.Original,
PsbImageFormat extractFormat = PsbImageFormat.png, bool useResx = true, uint? key = null, PsbType type = PsbType.PSB)
PsbImageFormat extractFormat = PsbImageFormat.png, bool useResx = true, uint? key = null, PsbType type = PsbType.PSB, Dictionary<string, object> contextDic = null)
{
var context = FreeMount.CreateContext();
var context = FreeMount.CreateContext(contextDic);
if (key != null)
{
context.Context[Consts.Context_CryptKey] = key;
Expand Down Expand Up @@ -326,7 +327,7 @@ public static void ExtractImageFiles(string inputPath, PsbImageFormat format = P
var bitmaps = TextureCombiner.CombineTachie(psb);
foreach (var kv in bitmaps)
{
kv.Value.Save(Path.Combine(dirPath, $"{kv.Key}{texExt}"), texFormat);
kv.Value.CombinedImage.Save(Path.Combine(dirPath, $"{kv.Key}{texExt}"), texFormat);
}
return;
}
Expand Down
1 change: 1 addition & 0 deletions FreeMote.Psb/IResourceMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public interface IResourceMetadata
string Name { get; set; }
public uint Index { get; }
PsbSpec Spec { get; set; }
public PsbType PsbType { get; set; }
void Link(string fullPath, FreeMountContext context);
}

Expand Down
22 changes: 22 additions & 0 deletions FreeMote.Psb/Plugins/FreeMountContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,28 @@ public FreeMountContext(Dictionary<string, object> context)
Context = context;
}

public bool TryGet<T>(string key, out T result)
{
result = default;
if (Context == null)
{
return false;
}

if (!Context.ContainsKey(key))
{
return false;
}

if (Context[key] is not T)
{
return false;
}

result = (T)Context[key];
return true;
}

public bool HasShell => Context.ContainsKey(Consts.Context_PsbShellType) && Context[Consts.Context_PsbShellType] != null && !string.IsNullOrEmpty(Context[Consts.Context_PsbShellType].ToString());

public bool SupportImageExt(string ext)
Expand Down
12 changes: 10 additions & 2 deletions FreeMote.Psb/PsbResHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ public static void LinkImages(PSB psb, FreeMountContext context, IList<string> r
}

internal static void LinkImages(PSB psb, FreeMountContext context, IDictionary<string, string> resources,
string baseDir = null)
string baseDir = null, bool overwrite = true)
{
var resList = psb.CollectResources<ImageMetadata>();

Expand Down Expand Up @@ -241,7 +241,15 @@ internal static void LinkImages(PSB psb, FreeMountContext context, IDictionary<s

if (resMd == null)
{
Console.WriteLine($"[WARN]{resxResource.Key} is not used.");
if (overwrite)
{
Console.WriteLine($"[WARN]{resxResource.Key} is not used.");
}
continue;
}

if (!overwrite && resMd.Data is { Length: > 0 }) //skip if resource is already filled and we don't want not overwrite
{
continue;
}

Expand Down
1 change: 1 addition & 0 deletions FreeMote.Psb/Resources/AudioMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public uint Index

public PsbAudioFormat AudioFormat => ChannelList.Count > 0 ? ChannelList[0].Format : PsbAudioFormat.Unknown;
public PsbSpec Spec { get; set; } = PsbSpec.other;
public PsbType PsbType { get; set; } = PsbType.SoundArchive;

public PsbAudioPan Pan
{
Expand Down
2 changes: 2 additions & 0 deletions FreeMote.Psb/Resources/FlattenArrayMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ internal set
public Span<float> FloatValues => MemoryMarshal.Cast<byte, float>(Data.AsSpan());

public PsbSpec Spec { get; set; }
public PsbType PsbType { get; set; }

public void Link(string fullPath, FreeMountContext context)
{
Data = File.ReadAllBytes(fullPath);
Expand Down
37 changes: 37 additions & 0 deletions FreeMote.Psb/Resources/ImageMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Drawing;
using System.IO;
using System.Linq;
using FastBitmapLib;
using FreeMote.Plugins;

namespace FreeMote.Psb
Expand Down Expand Up @@ -170,6 +171,8 @@ internal set
/// </summary>
public PsbSpec Spec { get; set; } = PsbSpec.other;

public PsbType PsbType { get; set; } = PsbType.Motion;

/// <summary>
/// Check if the <see cref="Data"/> looks correct
/// </summary>
Expand Down Expand Up @@ -198,6 +201,11 @@ internal set
return (true, string.Empty);
}

/// <summary>
/// Load <see cref="Data"/> and <see cref="PalData"/> from image file
/// </summary>
/// <param name="fullPath"></param>
/// <param name="context"></param>
public void Link(string fullPath, FreeMountContext context)
{
Data = LoadImageBytes(fullPath, context, out var palette);
Expand Down Expand Up @@ -247,6 +255,7 @@ public Bitmap ToImage()

/// <summary>
/// Set Image to <see cref="PsbResource.Data"/>
/// <para>(in memory version of <seealso cref="Link"/>)</para>
/// </summary>
/// <param name="bmp"></param>
public void SetData(Bitmap bmp)
Expand Down Expand Up @@ -401,6 +410,34 @@ internal byte[] LoadImageBytes(string path, FreeMountContext context,
break;
}

//From now we have get the image, now fetch pixel data
context.TryGet(Consts.Context_DisableCombinedImage, out bool disableCombinedImage);
if (PsbType == PsbType.Tachie && !disableCombinedImage) //Let's split Tachie
{
static bool IsPowOf2(int n)
{
return n >= 2 && (n & (n - 1)) == 0;
}

//Check if the source image is a combined image
if (image.Width == Width && image.Height == Height && IsPowOf2(Width) && IsPowOf2(Height))
{
//it's not a combined image, do nothing
}
else if((image.Width >= Width || image.Height >= Height) && image.Width >= Left && image.Height >= Height)
{
Bitmap chunk = new Bitmap(Width, Height, image.PixelFormat);
//it should be a combined image
using (FastBitmap f = chunk.FastLock())
{
f.CopyRegion(image, new Rectangle(Left, Top, Width, Height), new Rectangle(0, 0, Width, Height));
}

image.Dispose();
image = chunk;
}
}

switch (PixelFormat)
{
case PsbPixelFormat.ASTC_8BPP:
Expand Down
19 changes: 11 additions & 8 deletions FreeMote.Psb/Textures/TextureCombiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,15 @@ static class TextureCombiner
/// </summary>
/// <param name="psb">Image (image) type PSB</param>
/// <returns></returns>
public static Dictionary<string, Bitmap> CombineTachie(PSB psb)
public static Dictionary<string, (Bitmap CombinedImage, List<ImageMetadata> Parts)> CombineTachie(PSB psb)
{
if (psb.Type != PsbType.Tachie)
{
throw new NotSupportedException("PSB is not image type");
}

Dictionary<string, Bitmap> images = new Dictionary<string, Bitmap>();
PsbList imageList = psb.Objects["imageList"] as PsbList;
if (imageList == null)
Dictionary<string, (Bitmap CombinedImage, List<ImageMetadata> Parts)> images = new();
if (psb.Objects["imageList"] is not PsbList imageList)
{
return images;
}
Expand All @@ -43,24 +42,28 @@ public static Dictionary<string, Bitmap> CombineTachie(PSB psb)
var label = imageItem["label"].ToString();

Bitmap img = new Bitmap(width, height, PixelFormat.Format32bppArgb);
List<ImageMetadata> parts = new List<ImageMetadata>(texture.Count);
using (var f = img.FastLock())
{
foreach (var texObj in texture)
{
var tex = (PsbDictionary)texObj;
var md = PsbResHelper.GenerateImageMetadata(tex.Children("image") as PsbDictionary);
md.Spec = psb.Platform;
md.PsbType = PsbType.Tachie;
md.Part = label;
parts.Add(md);

var left = tex["left"].GetInt();
var top = tex["top"].GetInt();
var tHeight = tex["height"].GetInt();
var tWidth = tex["width"].GetInt();

f.CopyRegion(md.ToImage(), new Rectangle(0,0, md.Width, md.Height), new Rectangle(left, top, tWidth, tHeight));
f.CopyRegion(md.ToImage(), new Rectangle(0, 0, md.Width, md.Height), new Rectangle(left, top, tWidth, tHeight));
}
}
images.Add(label, img);

images.Add(label, (img, parts));
}

return images;
Expand Down Expand Up @@ -96,7 +99,7 @@ public static void CombineImagesToFile(string inputPath, PsbImageFormat extractF
var bitmaps = CombineTachie(psb);
foreach (var kv in bitmaps)
{
kv.Value.Save(Path.Combine(dirPath, $"{kv.Key}.{extractFormat}"), extractFormat.ToImageFormat());
kv.Value.CombinedImage.Save(Path.Combine(dirPath, $"{kv.Key}.{extractFormat}"), extractFormat.ToImageFormat());
}
}

Expand Down
4 changes: 2 additions & 2 deletions FreeMote.Psb/Textures/TextureSpliter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace FreeMote.Psb.Textures
public static class TextureSpliter
{
/// <summary>
/// <see cref="PsbResHelper.CollectResources"/> for packed-texture specs, like <see cref="PsbSpec.win"/>
/// <see cref="PsbResHelper.CollectResources"/> for packed-texture specs, especially for <see cref="PsbSpec.win"/>
/// </summary>
/// <param name="psb"></param>
/// <returns></returns>
Expand Down Expand Up @@ -59,7 +59,7 @@ public static Dictionary<string, Bitmap> SplitTexture(PsbDictionary tex, PsbSpec
Dictionary<string, Bitmap> textures = new Dictionary<string, Bitmap>(icon.Count);

var pixel = texture[Consts.ResourceKey];
if (pixel == null || !(pixel is PsbResource pixelRes))
if (pixel is not PsbResource pixelRes)
{
throw new PsbBadFormatException(PsbBadFormatReason.Resources,
"External Texture PSB is not supported. Please Link textures into PSB.");
Expand Down
4 changes: 3 additions & 1 deletion FreeMote.Psb/Types/FontType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ public List<ImageMetadata> FindFontResources(PSB psb, bool deDuplication = true)

foreach (var item in list)
{
if (!(item is PsbDictionary obj))
if (item is not PsbDictionary obj)
{
continue;
}

//TODO: deDuplication for resource (besides pal)
var md = PsbResHelper.GenerateImageMetadata(obj, null);
md.PsbType = PsbType.BmpFont;
md.Spec = psb.Platform;
resList.Add(md);
}

Expand Down
38 changes: 35 additions & 3 deletions FreeMote.Psb/Types/ImageType.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using FreeMote.Plugins;
using FreeMote.Psb.Textures;

Expand All @@ -13,10 +15,11 @@ public bool IsThisType(PSB psb)
{
return psb.TypeId == "image"; //&& psb.Objects.ContainsKey("imageList")
}

public override Dictionary<string, string> OutputResources(PSB psb, FreeMountContext context, string name, string dirPath,
PsbExtractOption extractOption = PsbExtractOption.Original)
{
bool allExtracted = true;
//Extra Extract
if (extractOption == PsbExtractOption.Extract)
{
Expand All @@ -25,8 +28,36 @@ public override Dictionary<string, string> OutputResources(PSB psb, FreeMountCon
var bitmaps = TextureCombiner.CombineTachie(psb);
foreach (var kv in bitmaps)
{
kv.Value.Save(Path.Combine(dirPath, $"{kv.Key}{context.ImageFormat.DefaultExtension()}"), context.ImageFormat.ToImageFormat());
kv.Value.CombinedImage.Save(Path.Combine(dirPath, $"{kv.Key}{context.ImageFormat.DefaultExtension()}"), context.ImageFormat.ToImageFormat());
}

//Only output combined image
context.TryGet(Consts.Context_DisableCombinedImage, out bool disableCombinedImage);
if (!disableCombinedImage)
{
Dictionary<string, string> resources = new Dictionary<string, string>();
var images = psb.CollectResources<ImageMetadata>();
foreach (var md in images)
{
if (bitmaps.ContainsKey(md.Part))
{
if (!bitmaps[md.Part].Parts.Any(p => p.Resource.Index != null && p.Index == md.Index))
{
Console.WriteLine($"[WARN] Image is not fully combined: {md}");
allExtracted = false;
break;
}
resources.Add(md.Index.ToString(), $"{name}/{md.Part}{context.ImageFormat.DefaultExtension()}");
}
}

if (allExtracted)
{
return resources;
}
}

Console.WriteLine("[WARN] Combined image won't be used when compiling. Now extracting all chunks...");
}
}

Expand Down Expand Up @@ -114,6 +145,7 @@ private static ImageMetadata GenerateTachieResMetadata(PsbDictionary d, PsbResou
Name = r.Index.ToString(),
Part = label,
Resource = r,
PsbType = PsbType.Tachie
};

if (md.PixelFormat == PsbPixelFormat.ASTC_8BPP)
Expand Down
5 changes: 5 additions & 0 deletions FreeMote.Psb/Types/MmoType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public List<T> CollectResources<T>(PSB psb, bool deDuplication = true) where T :
FindMmoResources(resourceList, psb.Objects[MmoBgSourceKey], MmoBgSourceKey, deDuplication);
FindMmoResources(resourceList, psb.Objects[MmoSourceKey], MmoSourceKey, deDuplication);

resourceList.ForEach(r =>
{
r.PsbType = PsbType.Mmo;
r.Spec = psb.Platform;
});
return resourceList;
}

Expand Down
8 changes: 7 additions & 1 deletion FreeMote.Psb/Types/MotionType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,13 @@ public List<T> CollectResources<T>(PSB psb, bool deDuplication = true) where T :
{
FindMotionResources(resourceList, psb.Objects[MotionSourceKey], deDuplication);
}


resourceList.ForEach(r =>
{
r.PsbType = psb.Type;
r.Spec = psb.Platform;
});

return resourceList;
}

Expand Down
4 changes: 3 additions & 1 deletion FreeMote.Psb/Types/PimgType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ public List<T> CollectResources<T>(PSB psb, bool deDuplication = true) where T :
{
Name = k.Key,
Resource = k.Value as PsbResource,
Compress = k.Key.EndsWith(".tlg", true, null) ? PsbCompressType.Tlg : PsbCompressType.ByName
Compress = k.Key.EndsWith(".tlg", true, null) ? PsbCompressType.Tlg : PsbCompressType.ByName,
PsbType = PsbType.Pimg,
Spec = psb.Platform
}).Cast<T>());
FindPimgResources(resourceList, psb.Objects[PimgSourceKey], deDuplication);

Expand Down
4 changes: 3 additions & 1 deletion FreeMote.Psb/Types/ScnType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ public List<T> CollectResources<T>(PSB psb, bool deDuplication = true) where T :
{
Name = k.Key,
Resource = k.Value as PsbResource,
Compress = k.Key.EndsWith(".tlg", true, null) ? PsbCompressType.Tlg : PsbCompressType.ByName
Compress = k.Key.EndsWith(".tlg", true, null) ? PsbCompressType.Tlg : PsbCompressType.ByName,
Spec = psb.Platform,
PsbType = PsbType.Scn
}).Cast<T>());

return resourceList;
Expand Down
2 changes: 1 addition & 1 deletion FreeMote.Psb/Types/SoundArchiveType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public List<T> CollectResources<T>(PSB psb, bool deDuplication = true) where T :

internal AudioMetadata GenerateAudioMetadata(PSB psb, string name, PsbDictionary voice, FreeMountContext context)
{
var md = new AudioMetadata {Name = name, Spec = psb.Platform};
var md = new AudioMetadata { Name = name, Spec = psb.Platform, PsbType = psb.Type };

if (voice["file"] is PsbString fileStr)
{
Expand Down
Loading

0 comments on commit 7ab7dd7

Please sign in to comment.