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
3 changes: 2 additions & 1 deletion MaiChartManager.CLI/Commands/MakeAbCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ await Task.Run(() =>
Path.Combine(jacketDir, $"ui_jacket_{id}.ab"),
$"UI_Jacket_{id}",
$"assets/assetbundle/jacket/ui_jacket_{id}.png",
$"jacket/ui_jacket_{id}.ab");
$"jacket/ui_jacket_{id}.ab",
maxDimension: AssetBundleCreator.MaxJacketDimension);

AssetBundleCreator.CreateTextureAssetBundle(
path!,
Expand Down
3 changes: 2 additions & 1 deletion MaiChartManager/Controllers/Music/MusicTransferController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,8 @@ private void MoveJacketSoundVideo(MusicXmlWithABJacket music, int newId, string
abJacketTarget,
$"UI_Jacket_{idPad}",
$"assets/assetbundle/jacket/ui_jacket_{idPad}.png",
$"jacket/ui_jacket_{idPad}.ab");
$"jacket/ui_jacket_{idPad}.ab",
maxDimension: AssetBundleCreator.MaxJacketDimension);

// 对小jacket:如果存在,重打包;如果不存在,则从png重新缩放,重新CreateTextureAssetBundle
if (oldSmallAb is not null && System.IO.File.Exists(oldSmallAb))
Expand Down
3 changes: 2 additions & 1 deletion MaiChartManager/Controllers/Tools/ImageToAbToolController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ await WriteEvent(
fullAbPath,
$"UI_Jacket_{id}",
$"assets/assetbundle/jacket/ui_jacket_{id}.png",
$"jacket/ui_jacket_{id}.ab");
$"jacket/ui_jacket_{id}.ab",
maxDimension: AssetBundleCreator.MaxJacketDimension);

var smallAbPath = Path.Combine(jacketSmallDir, $"ui_jacket_{id}_s.ab");
AssetBundleCreator.CreateTextureAssetBundle(
Expand Down
55 changes: 47 additions & 8 deletions MaiChartManager/Utils/AssetBundleCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ public static class AssetBundleCreator
{
private const int TextureFormatRgba32 = 4;

/// <summary>
/// 大封面(jacket)允许的最大边长。游戏内官方封面是 400×400 的 BC7,
/// 显示区域也用不到更大尺寸;而自制封面如果按原图尺寸写进 AB,
/// 3000×3000 的 RGBA32 一张就是 34 MB 显存、18 MB 文件,
/// 选歌/结算时同步加载会造成明显掉帧,所以在打包时钳制到这个尺寸。
/// </summary>
public const int MaxJacketDimension = 400;

private static string TemplateAbPath =>
Path.Combine(StaticSettings.StreamingAssets, "A000", "AssetBundleImages", "jacket", "ui_jacket_000000.ab");

Expand All @@ -22,25 +30,54 @@ public static void CreateTextureAssetBundle(
string containerPath,
string abName,
int? resizeWidth = null,
int? resizeHeight = null)
int? resizeHeight = null,
int? maxDimension = null)
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
Resolved
{
if (!File.Exists(imagePath))
throw new FileNotFoundException($"Image file not found: {imagePath}", imagePath);
CreateTextureAssetBundle(File.ReadAllBytes(imagePath), outputAbPath, assetName, containerPath, abName, resizeWidth, resizeHeight);
CreateTextureAssetBundle(File.ReadAllBytes(imagePath), outputAbPath, assetName, containerPath, abName, resizeWidth, resizeHeight,
maxDimension);
}

/// <summary>
/// 把图片写成 Texture2D 的 AssetBundle。
/// </summary>
/// <param name="resizeWidth">显式目标宽度,需与 <paramref name="resizeHeight"/> 成对给出;给出时会强制拉伸到该尺寸(可能改变宽高比)</param>
/// <param name="resizeHeight">显式目标高度</param>
/// <param name="maxDimension">
/// 长边上限,超出时等比缩小(只缩不放、不裁剪)。
/// 无论是否给了显式尺寸都会生效:显式尺寸先应用,之后仍按上限钳制。
/// </param>
public static void CreateTextureAssetBundle(
ReadOnlySpan<byte> pngImageData,
string outputAbPath,
string assetName,
string containerPath,
string abName,
int? resizeWidth = null,
int? resizeHeight = null)
int? resizeHeight = null,
int? maxDimension = null)
{
using var image = SixLabors.ImageSharp.Image.Load<Rgba32>(pngImageData);
if (resizeWidth.HasValue && resizeHeight.HasValue)
image.Mutate(x => x.Resize(resizeWidth.Value, resizeHeight.Value));

if (resizeWidth is > 0 && resizeHeight is > 0)
// 显式尺寸按拉伸处理,和原来的 x.Resize(w, h) 一致;ResizeOptions 默认 Mode 是 Crop,必须显式写 Stretch
image.Mutate(x => x.Resize(new ResizeOptions
{
Size = new Size(resizeWidth.Value, resizeHeight.Value),
Mode = ResizeMode.Stretch,
Sampler = KnownResamplers.Bicubic,
}));

// 上限独立判断,不是 else if:任何调用组合都不该写出超过上限的纹理
if (maxDimension is > 0 && (image.Width > maxDimension.Value || image.Height > maxDimension.Value))
// 等比缩到长边不超过上限,只缩不放,避免改变原本的宽高比
image.Mutate(x => x.Resize(new ResizeOptions
{
Size = new Size(maxDimension.Value, maxDimension.Value),
Mode = ResizeMode.Max,
Sampler = KnownResamplers.Lanczos3,
}));

image.Mutate(x => x.Flip(FlipMode.Vertical));

Expand Down Expand Up @@ -170,7 +207,8 @@ public static string CreateMusicJacketAssetBundles(ReadOnlySpan<byte> pngImageDa
Path.Combine(abiDir, $"{key.ToLowerInvariant()}.ab"),
key,
$"assets/assetbundle/jacket/{key.ToLowerInvariant()}.png",
$"jacket/{key.ToLowerInvariant()}.ab");
$"jacket/{key.ToLowerInvariant()}.ab",
maxDimension: MaxJacketDimension);

CreateTextureAssetBundle(
pngImageData,
Expand All @@ -193,15 +231,16 @@ public static void RepackTextureAssetBundle(
string outputAbPath,
string assetName,
string containerPath,
string abName)
string abName,
int? maxDimension = null)
{
if (!File.Exists(inputAbPath))
throw new FileNotFoundException($"Input AB not found: {inputAbPath}", inputAbPath);

var pngBytes = ImageConvert.GetTextureAsPngData(inputAbPath);
if (pngBytes is null || pngBytes.Length == 0)
throw new InvalidOperationException($"Could not decode jacket texture to PNG from: {inputAbPath}");
CreateTextureAssetBundle(pngBytes, outputAbPath, assetName, containerPath, abName);
CreateTextureAssetBundle(pngBytes, outputAbPath, assetName, containerPath, abName, maxDimension: maxDimension);
}

private static void WriteUncompressedBundle(byte[] assetsData, string cabName, Stream output)
Expand Down
Loading