Skip to content

Commit c953c10

Browse files
committed
feat: allow sheet export for animated textures
requires multiple file formats per format converter
1 parent 722b89f commit c953c10

21 files changed

Lines changed: 103 additions & 34 deletions

Core/Conversion/FormatConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace FEZRepacker.Core.Conversion
1111
/// </summary>
1212
public abstract class FormatConverter
1313
{
14-
public abstract string FileFormat { get; }
14+
public abstract string[] FileFormats { get; }
1515
public abstract Type FormatType { get; }
1616

1717
public abstract FileBundle Convert(object? data);

Core/Conversion/FormatConverterSettings.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,12 @@ public struct FormatConverterSettings()
1515
/// If the flag is true, the converter will use a legacy bundle with separate files.
1616
/// </summary>
1717
public bool UseTrixelArtBundle = false;
18+
19+
/// <summary>
20+
/// By default, <see cref="AnimatedTexture"/> is converted into GIF animation file. This is a lossy conversion,
21+
/// dropping original atlas texture arrangement and leading to minor precision loss to color and frame duration.
22+
/// If the flag is true, the converter will export animations into a bundle of atlas texture and JSON data.
23+
/// </summary>
24+
public bool UseAnimationSheet = false;
1825
}
1926
}

Core/Conversion/FormatConverters.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public static class FormatConverters
2828

2929
public static FormatConverter? FindByExtension(string extension)
3030
{
31-
return List.FirstOrDefault(x => x.FileFormat == extension);
31+
return List.FirstOrDefault(x => x.FileFormats.Contains(extension));
3232
}
3333

3434
public static FormatConverter? FindForFileBundle(FileBundle bundle)

Core/Conversion/Formats/AnimatedTextureConverter.cs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
using FEZRepacker.Core.Definitions.Game.XNA;
33
using FEZRepacker.Core.FileSystem;
44
using FEZRepacker.Core.Helpers;
5+
using FEZRepacker.Core.Helpers.Json;
56

67
using SixLabors.ImageSharp;
78
using SixLabors.ImageSharp.Formats.Gif;
9+
using SixLabors.ImageSharp.Formats.Png;
810
using SixLabors.ImageSharp.PixelFormats;
911
using SixLabors.ImageSharp.Processing;
1012

@@ -14,23 +16,53 @@ namespace FEZRepacker.Core.Conversion.Formats
1416
{
1517
internal class AnimatedTextureConverter : FormatConverter<AnimatedTexture>
1618
{
17-
const int FramePadding = 1;
19+
private const string GifFileFormat = ".gif";
20+
private const string BundleFileFormat = ".fezanim";
1821

19-
public override string FileFormat => ".gif";
22+
public override string[] FileFormats => [GifFileFormat, BundleFileFormat];
2023

2124
public override FileBundle ConvertTyped(AnimatedTexture txt)
2225
{
26+
if (Settings.UseAnimationSheet)
27+
{
28+
var bundle = ConfiguredJsonSerializer.SerializeToFileBundle(BundleFileFormat, txt);
29+
var atlasTexture = new Texture2D()
30+
{
31+
Format = SurfaceFormat.Color,
32+
Width = txt.AtlasWidth,
33+
Height = txt.AtlasHeight,
34+
TextureData = txt.TextureData
35+
};
36+
using var animationAtlas = TexturesUtil.ImageFromTexture2D(atlasTexture);
37+
bundle.AddFile(animationAtlas.SaveAsMemoryStream(new PngEncoder()), ".png");
38+
39+
return bundle;
40+
}
41+
2342
using var animation = AnimatedTextureToGif(txt);
2443

2544
var outStream = animation.SaveAsMemoryStream(
2645
new GifEncoder { ColorTableMode = GifColorTableMode.Local }
2746
);
2847

29-
return FileBundle.Single(outStream, FileFormat);
48+
return FileBundle.Single(outStream, GifFileFormat);
3049
}
3150

3251
public override AnimatedTexture DeconvertTyped(FileBundle bundle)
3352
{
53+
if (bundle.MainExtension == BundleFileFormat)
54+
{
55+
var animatedTexture = ConfiguredJsonSerializer.DeserializeFromFileBundle<AnimatedTexture>(bundle);
56+
57+
using var atlasImage = Image.Load<Rgba32>(bundle.RequireData(".png"));
58+
var atlasTexture = TexturesUtil.ImageToTexture2D(atlasImage);
59+
60+
animatedTexture.AtlasWidth = atlasTexture.Width;
61+
animatedTexture.AtlasHeight = atlasTexture.Height;
62+
animatedTexture.TextureData = atlasTexture.TextureData;
63+
return animatedTexture;
64+
}
65+
3466
using var animation = Image.Load<Rgba32>(bundle.RequireData(""));
3567
return AnimationImageToAnimatedTexture(animation);
3668
}

Core/Conversion/Formats/ArtObjectConverter.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,18 @@ namespace FEZRepacker.Core.Conversion.Formats
1313
{
1414
internal class ArtObjectConverter : FormatConverter<ArtObject>
1515
{
16-
public override string FileFormat => ".fezao";
16+
private const string BundleFileFormat = ".fezao";
17+
18+
public override string[] FileFormats => [BundleFileFormat];
1719

1820
public override FileBundle ConvertTyped(ArtObject data)
1921
{
2022
if (!Settings.UseTrixelArtBundle)
2123
{
22-
return FileBundle.Single(GetTransmissionFormatStream(data), FileFormat, ".glb");
24+
return FileBundle.Single(GetTransmissionFormatStream(data), BundleFileFormat, ".glb");
2325
}
2426

25-
var bundle = ConfiguredJsonSerializer.SerializeToFileBundle(FileFormat, data);
27+
var bundle = ConfiguredJsonSerializer.SerializeToFileBundle(BundleFileFormat, data);
2628

2729
bundle.AddFile(GetTextureStream(data, TexturesUtil.CubemapPart.Albedo), ".png");
2830
bundle.AddFile(GetTextureStream(data, TexturesUtil.CubemapPart.Emission), ".apng");

Core/Conversion/Formats/EffectConverter.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ namespace FEZRepacker.Core.Conversion.Formats
55
{
66
internal class EffectConverter : FormatConverter<Effect>
77
{
8-
public override string FileFormat => ".fxb";
8+
private const string FileFormat = ".fxb";
9+
public override string[] FileFormats => [FileFormat];
910

1011
public override FileBundle ConvertTyped(Effect data)
1112
{

Core/Conversion/Formats/LevelConverter.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ namespace FEZRepacker.Core.Conversion.Formats
77
{
88
internal class LevelConverter : FormatConverter<Level>
99
{
10-
public override string FileFormat => ".fezlvl";
10+
private const string BundleFileFormat = ".fezlvl";
11+
public override string[] FileFormats => [BundleFileFormat];
1112

1213
public override FileBundle ConvertTyped(Level data)
1314
{
1415
var levelModel = new LevelJsonModel(data);
15-
return ConfiguredJsonSerializer.SerializeToFileBundle(FileFormat, levelModel);
16+
return ConfiguredJsonSerializer.SerializeToFileBundle(BundleFileFormat, levelModel);
1617
}
1718

1819
public override Level DeconvertTyped(FileBundle bundle)

Core/Conversion/Formats/MapTreeConverter.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ namespace FEZRepacker.Core.Conversion.Formats
77
{
88
internal class MapTreeConverter : FormatConverter<MapTree>
99
{
10-
public override string FileFormat => ".fezmap";
10+
private const string BundleFileFormat = ".fezmap";
11+
public override string[] FileFormats => [BundleFileFormat];
1112

1213
public override FileBundle ConvertTyped(MapTree data)
1314
{
1415
var mapModel = new MapTreeJsonModel();
1516
mapModel.SerializeFrom(data);
16-
return ConfiguredJsonSerializer.SerializeToFileBundle(FileFormat, mapModel);
17+
return ConfiguredJsonSerializer.SerializeToFileBundle(BundleFileFormat, mapModel);
1718
}
1819

1920
public override MapTree DeconvertTyped(FileBundle bundle)

Core/Conversion/Formats/NpcMetadataConverter.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ namespace FEZRepacker.Core.Conversion.Formats
66
{
77
internal class NpcMetadataConverter : FormatConverter<NpcMetadata>
88
{
9-
public override string FileFormat => ".feznpc";
9+
private const string BundleFileFormat = ".feznpc";
10+
public override string[] FileFormats => [BundleFileFormat];
1011

1112
public override FileBundle ConvertTyped(NpcMetadata data)
1213
{
13-
return ConfiguredJsonSerializer.SerializeToFileBundle(FileFormat, data);
14+
return ConfiguredJsonSerializer.SerializeToFileBundle(BundleFileFormat, data);
1415
}
1516

1617
public override NpcMetadata DeconvertTyped(FileBundle bundle)

Core/Conversion/Formats/SkyConverter.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ namespace FEZRepacker.Core.Conversion.Formats
66
{
77
internal class SkyConverter : FormatConverter<Sky>
88
{
9-
public override string FileFormat => ".fezsky";
9+
private const string BundleFileFormat = ".fezsky";
10+
public override string[] FileFormats => [BundleFileFormat];
1011

1112
public override FileBundle ConvertTyped(Sky data)
1213
{
13-
return ConfiguredJsonSerializer.SerializeToFileBundle(FileFormat, data);
14+
return ConfiguredJsonSerializer.SerializeToFileBundle(BundleFileFormat, data);
1415
}
1516

1617
public override Sky DeconvertTyped(FileBundle bundle)

0 commit comments

Comments
 (0)