mirror of
https://github.com/aelurum/AssetStudio.git
synced 2025-06-03 00:58:13 -04:00
[AK][GUI] Add support for portrait sprites
This commit is contained in:
parent
3d7d51b54f
commit
572e3bf0d6
@ -3,6 +3,7 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
public enum ClassIDType
|
public enum ClassIDType
|
||||||
{
|
{
|
||||||
|
AkPortraitSprite = -2,
|
||||||
UnknownType = -1,
|
UnknownType = -1,
|
||||||
Object = 0,
|
Object = 0,
|
||||||
GameObject = 1,
|
GameObject = 1,
|
||||||
|
@ -182,6 +182,13 @@ namespace AssetStudio
|
|||||||
public float width;
|
public float width;
|
||||||
public float height;
|
public float height;
|
||||||
|
|
||||||
|
public Rectf(float x, float y, float w, float h) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
width = w;
|
||||||
|
height = h;
|
||||||
|
}
|
||||||
|
|
||||||
public Rectf(BinaryReader reader)
|
public Rectf(BinaryReader reader)
|
||||||
{
|
{
|
||||||
x = reader.ReadSingle();
|
x = reader.ReadSingle();
|
||||||
|
@ -360,7 +360,7 @@ namespace AssetStudioGUI
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (lastSelectedItem?.Type == ClassIDType.Sprite && !((Sprite)lastSelectedItem.Asset).m_RD.alphaTexture.IsNull)
|
else if ((lastSelectedItem?.Type == ClassIDType.Sprite && !((Sprite)lastSelectedItem.Asset).m_RD.alphaTexture.IsNull) || lastSelectedItem?.Type == ClassIDType.AkPortraitSprite)
|
||||||
{
|
{
|
||||||
switch (e.KeyCode)
|
switch (e.KeyCode)
|
||||||
{
|
{
|
||||||
@ -430,6 +430,7 @@ namespace AssetStudioGUI
|
|||||||
switch (lastSelectedItem.Type)
|
switch (lastSelectedItem.Type)
|
||||||
{
|
{
|
||||||
case ClassIDType.Texture2D:
|
case ClassIDType.Texture2D:
|
||||||
|
case ClassIDType.AkPortraitSprite:
|
||||||
case ClassIDType.Sprite:
|
case ClassIDType.Sprite:
|
||||||
{
|
{
|
||||||
if (enablePreview.Checked && imageTexture != null)
|
if (enablePreview.Checked && imageTexture != null)
|
||||||
@ -798,42 +799,45 @@ namespace AssetStudioGUI
|
|||||||
return;
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
switch (assetItem.Asset)
|
switch (assetItem.Type)
|
||||||
{
|
{
|
||||||
case Texture2D m_Texture2D:
|
case ClassIDType.Texture2D:
|
||||||
PreviewTexture2D(assetItem, m_Texture2D);
|
PreviewTexture2D(assetItem, assetItem.Asset as Texture2D);
|
||||||
break;
|
break;
|
||||||
case AudioClip m_AudioClip:
|
case ClassIDType.AudioClip:
|
||||||
PreviewAudioClip(assetItem, m_AudioClip);
|
PreviewAudioClip(assetItem, assetItem.Asset as AudioClip);
|
||||||
break;
|
break;
|
||||||
case Shader m_Shader:
|
case ClassIDType.Shader:
|
||||||
PreviewShader(m_Shader);
|
PreviewShader(assetItem.Asset as Shader);
|
||||||
break;
|
break;
|
||||||
case TextAsset m_TextAsset:
|
case ClassIDType.TextAsset:
|
||||||
PreviewTextAsset(m_TextAsset);
|
PreviewTextAsset(assetItem.Asset as TextAsset);
|
||||||
break;
|
break;
|
||||||
case MonoBehaviour m_MonoBehaviour:
|
case ClassIDType.MonoBehaviour:
|
||||||
PreviewMonoBehaviour(m_MonoBehaviour);
|
PreviewMonoBehaviour(assetItem.Asset as MonoBehaviour);
|
||||||
break;
|
break;
|
||||||
case Font m_Font:
|
case ClassIDType.Font:
|
||||||
PreviewFont(m_Font);
|
PreviewFont(assetItem.Asset as Font);
|
||||||
break;
|
break;
|
||||||
case Mesh m_Mesh:
|
case ClassIDType.Mesh:
|
||||||
PreviewMesh(m_Mesh);
|
PreviewMesh(assetItem.Asset as Mesh);
|
||||||
break;
|
break;
|
||||||
case VideoClip m_VideoClip:
|
case ClassIDType.VideoClip:
|
||||||
PreviewVideoClip(assetItem, m_VideoClip);
|
PreviewVideoClip(assetItem, assetItem.Asset as VideoClip);
|
||||||
break;
|
break;
|
||||||
case MovieTexture _:
|
case ClassIDType.MovieTexture:
|
||||||
StatusStripUpdate("Only supported export.");
|
StatusStripUpdate("Only supported export.");
|
||||||
break;
|
break;
|
||||||
case Sprite m_Sprite:
|
case ClassIDType.Sprite:
|
||||||
PreviewSprite(assetItem, m_Sprite);
|
PreviewSprite(assetItem, assetItem.Asset as Sprite);
|
||||||
break;
|
break;
|
||||||
case Animator _:
|
case ClassIDType.AkPortraitSprite:
|
||||||
|
PreviewAkPortraitSprite(assetItem);
|
||||||
|
break;
|
||||||
|
case ClassIDType.Animator:
|
||||||
StatusStripUpdate("Can be exported to FBX file.");
|
StatusStripUpdate("Can be exported to FBX file.");
|
||||||
break;
|
break;
|
||||||
case AnimationClip _:
|
case ClassIDType.AnimationClip:
|
||||||
StatusStripUpdate("Can be exported with Animator or Objects");
|
StatusStripUpdate("Can be exported with Animator or Objects");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -1344,6 +1348,25 @@ namespace AssetStudioGUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void PreviewAkPortraitSprite(AssetItem assetItem)
|
||||||
|
{
|
||||||
|
var image = assetItem.AkPortraitSprite.AkGetImage(spriteMaskMode: spriteMaskVisibleMode);
|
||||||
|
if (image != null)
|
||||||
|
{
|
||||||
|
var bitmap = new DirectBitmap(image);
|
||||||
|
image.Dispose();
|
||||||
|
assetItem.InfoText = $"Width: {bitmap.Width}\nHeight: {bitmap.Height}\n";
|
||||||
|
assetItem.InfoText += $"Alpha mask: {spriteMaskVisibleMode}";
|
||||||
|
PreviewTexture(bitmap);
|
||||||
|
|
||||||
|
StatusStripUpdate("'Ctrl'+'A' - Enable/Disable alpha mask usage. 'Ctrl'+'M' - Show alpha mask only.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StatusStripUpdate("Unsupported sprite for preview.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void PreviewTexture(DirectBitmap bitmap)
|
private void PreviewTexture(DirectBitmap bitmap)
|
||||||
{
|
{
|
||||||
imageTexture?.Dispose();
|
imageTexture?.Dispose();
|
||||||
@ -1449,19 +1472,20 @@ namespace AssetStudioGUI
|
|||||||
var assetItem = (AssetItem)assetListView.Items[i];
|
var assetItem = (AssetItem)assetListView.Items[i];
|
||||||
if (assetItem.Type == ClassIDType.Sprite)
|
if (assetItem.Type == ClassIDType.Sprite)
|
||||||
{
|
{
|
||||||
var sprite = (Sprite)assetItem.Asset;
|
var m_Sprite = (Sprite)assetItem.Asset;
|
||||||
if (akFixFaceSpriteNamesToolStripMenuItem.Checked)
|
if (akFixFaceSpriteNamesToolStripMenuItem.Checked)
|
||||||
{
|
{
|
||||||
if ((sprite.m_Name.Length < 3 && sprite.m_Name.All(char.IsDigit)) //not grouped ("spriteIndex")
|
var groupedPattern = new Regex(@"^\d{1,2}\$\d{1,2}$"); // "spriteIndex$groupIndex"
|
||||||
|| (sprite.m_Name.Length < 5 && sprite.m_Name.Contains('$') && sprite.m_Name.Split('$')[0].All(char.IsDigit))) //grouped ("spriteIndex$groupIndex")
|
var notGroupedPattern = new Regex(@"^\d{1,2}$"); // "spriteIndex"
|
||||||
|
if (groupedPattern.IsMatch(m_Sprite.m_Name) || notGroupedPattern.IsMatch(m_Sprite.m_Name))
|
||||||
{
|
{
|
||||||
var fullName = Path.GetFileNameWithoutExtension(assetItem.Container);
|
var fullName = Path.GetFileNameWithoutExtension(assetItem.Container);
|
||||||
assetItem.Text = $"{fullName}#{sprite.m_Name}";
|
assetItem.Text = $"{fullName}#{m_Sprite.m_Name}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (assetItem.Text != sprite.m_Name)
|
else if (assetItem.Text != m_Sprite.m_Name)
|
||||||
{
|
{
|
||||||
assetItem.Text = sprite.m_Name;
|
assetItem.Text = m_Sprite.m_Name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1968,7 +1992,7 @@ namespace AssetStudioGUI
|
|||||||
Properties.Settings.Default.useExternalAlpha = akUseExternalAlphaToolStripMenuItem.Checked;
|
Properties.Settings.Default.useExternalAlpha = akUseExternalAlphaToolStripMenuItem.Checked;
|
||||||
Properties.Settings.Default.Save();
|
Properties.Settings.Default.Save();
|
||||||
|
|
||||||
if (lastSelectedItem?.Asset.type == ClassIDType.Sprite)
|
if (lastSelectedItem?.Type == ClassIDType.Sprite)
|
||||||
{
|
{
|
||||||
StatusStripUpdate("");
|
StatusStripUpdate("");
|
||||||
PreviewAsset(lastSelectedItem);
|
PreviewAsset(lastSelectedItem);
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
using AssetStudio;
|
using Arknights.PortraitSpriteMono;
|
||||||
|
using AssetStudio;
|
||||||
using AssetStudioGUI;
|
using AssetStudioGUI;
|
||||||
using AssetStudioGUI.Properties;
|
using AssetStudioGUI.Properties;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using SixLabors.ImageSharp;
|
using SixLabors.ImageSharp;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
using SixLabors.ImageSharp.Processing;
|
using SixLabors.ImageSharp.Processing;
|
||||||
using SixLabors.ImageSharp.Processing.Processors.Transforms;
|
using SixLabors.ImageSharp.Processing.Processors.Transforms;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Arknights
|
namespace Arknights
|
||||||
@ -44,8 +47,8 @@ namespace Arknights
|
|||||||
{
|
{
|
||||||
if (m_Sprite.m_RD.texture.TryGet(out var m_Texture2D) && m_Sprite.m_RD.alphaTexture.TryGet(out var m_AlphaTexture2D) && spriteMaskMode != SpriteMaskMode.Off)
|
if (m_Sprite.m_RD.texture.TryGet(out var m_Texture2D) && m_Sprite.m_RD.alphaTexture.TryGet(out var m_AlphaTexture2D) && spriteMaskMode != SpriteMaskMode.Off)
|
||||||
{
|
{
|
||||||
Image<Bgra32> tex;
|
Image<Bgra32> tex = null;
|
||||||
Image<Bgra32> alphaTex;
|
Image<Bgra32> alphaTex = null;
|
||||||
|
|
||||||
if (avgSprite != null && avgSprite.IsHubParsed)
|
if (avgSprite != null && avgSprite.IsHubParsed)
|
||||||
{
|
{
|
||||||
@ -70,22 +73,14 @@ namespace Arknights
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tex = CutImage(m_Texture2D.ConvertToImage(false), m_Sprite.m_RD.textureRect, m_Sprite.m_RD.downscaleMultiplier);
|
if (spriteMaskMode != SpriteMaskMode.MaskOnly)
|
||||||
|
{
|
||||||
|
tex = CutImage(m_Texture2D.ConvertToImage(false), m_Sprite.m_RD.textureRect, m_Sprite.m_RD.downscaleMultiplier);
|
||||||
|
}
|
||||||
alphaTex = CutImage(m_AlphaTexture2D.ConvertToImage(false), m_Sprite.m_RD.textureRect, m_Sprite.m_RD.downscaleMultiplier);
|
alphaTex = CutImage(m_AlphaTexture2D.ConvertToImage(false), m_Sprite.m_RD.textureRect, m_Sprite.m_RD.downscaleMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (spriteMaskMode)
|
return ImageRender(tex, alphaTex, spriteMaskMode);
|
||||||
{
|
|
||||||
case SpriteMaskMode.On:
|
|
||||||
tex.ApplyRGBMask(alphaTex, isPreview: true);
|
|
||||||
return tex;
|
|
||||||
case SpriteMaskMode.Export:
|
|
||||||
tex.ApplyRGBMask(alphaTex);
|
|
||||||
return tex;
|
|
||||||
case SpriteMaskMode.MaskOnly:
|
|
||||||
tex.Dispose();
|
|
||||||
return alphaTex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (m_Sprite.m_RD.texture.TryGet(out m_Texture2D))
|
else if (m_Sprite.m_RD.texture.TryGet(out m_Texture2D))
|
||||||
{
|
{
|
||||||
@ -95,6 +90,83 @@ namespace Arknights
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Image<Bgra32> AkGetImage(this PortraitSprite portraitSprite, SpriteMaskMode spriteMaskMode = SpriteMaskMode.On)
|
||||||
|
{
|
||||||
|
if (portraitSprite.Texture != null && portraitSprite.AlphaTexture != null)
|
||||||
|
{
|
||||||
|
Image<Bgra32> tex = null;
|
||||||
|
Image<Bgra32> alphaTex = null;
|
||||||
|
|
||||||
|
if (spriteMaskMode != SpriteMaskMode.MaskOnly)
|
||||||
|
{
|
||||||
|
tex = CutImage(portraitSprite.Texture.ConvertToImage(false), portraitSprite.TextureRect, portraitSprite.DownscaleMultiplier, portraitSprite.Rotate);
|
||||||
|
}
|
||||||
|
if (spriteMaskMode != SpriteMaskMode.Off)
|
||||||
|
{
|
||||||
|
alphaTex = CutImage(portraitSprite.AlphaTexture.ConvertToImage(false), portraitSprite.TextureRect, portraitSprite.DownscaleMultiplier, portraitSprite.Rotate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ImageRender(tex, alphaTex, spriteMaskMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<PortraitSprite> GeneratePortraits(AssetItem asset)
|
||||||
|
{
|
||||||
|
var portraits = new List<PortraitSprite>();
|
||||||
|
|
||||||
|
var portraitsDict = ((MonoBehaviour)asset.Asset).ToType();
|
||||||
|
if (portraitsDict == null)
|
||||||
|
{
|
||||||
|
Logger.Warning("Portraits MonoBehaviour is not readable.");
|
||||||
|
return portraits;
|
||||||
|
}
|
||||||
|
var portraitsJson = JsonConvert.SerializeObject(portraitsDict);
|
||||||
|
var portraitsData = JsonConvert.DeserializeObject<PortraitSpriteConfig>(portraitsJson);
|
||||||
|
|
||||||
|
var atlasTex = (Texture2D)Studio.exportableAssets.Find(x => x.m_PathID == portraitsData._atlas.Texture.m_PathID).Asset;
|
||||||
|
var atlasAlpha = (Texture2D)Studio.exportableAssets.Find(x => x.m_PathID == portraitsData._atlas.Alpha.m_PathID).Asset;
|
||||||
|
|
||||||
|
foreach (var portraitData in portraitsData._sprites)
|
||||||
|
{
|
||||||
|
var portraitSprite = new PortraitSprite()
|
||||||
|
{
|
||||||
|
Name = portraitData.Name,
|
||||||
|
AssetsFile = atlasTex.assetsFile,
|
||||||
|
Container = asset.Container,
|
||||||
|
Texture = atlasTex,
|
||||||
|
AlphaTexture = atlasAlpha,
|
||||||
|
TextureRect = new Rectf(portraitData.Rect.X, portraitData.Rect.Y, portraitData.Rect.W, portraitData.Rect.H),
|
||||||
|
Rotate = portraitData.Rotate,
|
||||||
|
};
|
||||||
|
portraits.Add(portraitSprite);
|
||||||
|
}
|
||||||
|
|
||||||
|
return portraits;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Image<Bgra32> ImageRender(Image<Bgra32> tex, Image<Bgra32> alpha, SpriteMaskMode maskMode)
|
||||||
|
{
|
||||||
|
switch (maskMode)
|
||||||
|
{
|
||||||
|
case SpriteMaskMode.On:
|
||||||
|
tex.ApplyRGBMask(alpha, isPreview: true);
|
||||||
|
return tex;
|
||||||
|
case SpriteMaskMode.Off:
|
||||||
|
alpha?.Dispose();
|
||||||
|
return tex;
|
||||||
|
case SpriteMaskMode.MaskOnly:
|
||||||
|
tex?.Dispose();
|
||||||
|
return alpha;
|
||||||
|
case SpriteMaskMode.Export:
|
||||||
|
tex.ApplyRGBMask(alpha);
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private static IResampler GetResampler(bool isPreview)
|
private static IResampler GetResampler(bool isPreview)
|
||||||
{
|
{
|
||||||
IResampler resampler;
|
IResampler resampler;
|
||||||
@ -169,29 +241,31 @@ namespace Arknights
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Image<Bgra32> CutImage(Image<Bgra32> originalImage, Rectf textureRect, float downscaleMultiplier)
|
private static Image<Bgra32> CutImage(Image<Bgra32> originalImage, Rectf textureRect, float downscaleMultiplier, bool rotate = false)
|
||||||
{
|
{
|
||||||
if (originalImage != null)
|
if (originalImage != null)
|
||||||
{
|
{
|
||||||
using (originalImage)
|
if (downscaleMultiplier > 0f && downscaleMultiplier != 1f)
|
||||||
{
|
{
|
||||||
if (downscaleMultiplier > 0f && downscaleMultiplier != 1f)
|
var newSize = (Size)(originalImage.Size() / downscaleMultiplier);
|
||||||
{
|
originalImage.Mutate(x => x.Resize(newSize, KnownResamplers.Lanczos3, compand: true));
|
||||||
var newSize = (Size)(originalImage.Size() / downscaleMultiplier);
|
|
||||||
originalImage.Mutate(x => x.Resize(newSize, KnownResamplers.Lanczos3, compand: true));
|
|
||||||
}
|
|
||||||
var rectX = (int)Math.Floor(textureRect.x);
|
|
||||||
var rectY = (int)Math.Floor(textureRect.y);
|
|
||||||
var rectRight = (int)Math.Ceiling(textureRect.x + textureRect.width);
|
|
||||||
var rectBottom = (int)Math.Ceiling(textureRect.y + textureRect.height);
|
|
||||||
rectRight = Math.Min(rectRight, originalImage.Width);
|
|
||||||
rectBottom = Math.Min(rectBottom, originalImage.Height);
|
|
||||||
var rect = new Rectangle(rectX, rectY, rectRight - rectX, rectBottom - rectY);
|
|
||||||
var spriteImage = originalImage.Clone(x => x.Crop(rect));
|
|
||||||
spriteImage.Mutate(x => x.Flip(FlipMode.Vertical));
|
|
||||||
|
|
||||||
return spriteImage;
|
|
||||||
}
|
}
|
||||||
|
var rectX = (int)Math.Floor(textureRect.x);
|
||||||
|
var rectY = (int)Math.Floor(textureRect.y);
|
||||||
|
var rectRight = (int)Math.Ceiling(textureRect.x + textureRect.width);
|
||||||
|
var rectBottom = (int)Math.Ceiling(textureRect.y + textureRect.height);
|
||||||
|
rectRight = Math.Min(rectRight, originalImage.Width);
|
||||||
|
rectBottom = Math.Min(rectBottom, originalImage.Height);
|
||||||
|
var rect = new Rectangle(rectX, rectY, rectRight - rectX, rectBottom - rectY);
|
||||||
|
var spriteImage = originalImage.Clone(x => x.Crop(rect));
|
||||||
|
originalImage.Dispose();
|
||||||
|
if (rotate)
|
||||||
|
{
|
||||||
|
spriteImage.Mutate(x => x.Rotate(RotateMode.Rotate270));
|
||||||
|
}
|
||||||
|
spriteImage.Mutate(x => x.Flip(FlipMode.Vertical));
|
||||||
|
|
||||||
|
return spriteImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using Arknights.AvgCharHub;
|
using Arknights.AvgCharHubMono;
|
||||||
using AssetStudio;
|
using AssetStudio;
|
||||||
using AssetStudioGUI;
|
using AssetStudioGUI;
|
||||||
using SixLabors.ImageSharp;
|
using SixLabors.ImageSharp;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
using AssetStudio;
|
using AssetStudio;
|
||||||
|
|
||||||
namespace Arknights.AvgCharHub
|
namespace Arknights.AvgCharHubMono
|
||||||
{
|
{
|
||||||
internal class AvgAssetIDs
|
internal class AvgAssetIDs
|
||||||
{
|
{
|
||||||
|
24
AssetStudioGUI/Components/Arknights/PortraitSprite.cs
Normal file
24
AssetStudioGUI/Components/Arknights/PortraitSprite.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using AssetStudio;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Arknights
|
||||||
|
{
|
||||||
|
internal class PortraitSprite
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public ClassIDType Type { get; }
|
||||||
|
public SerializedFile AssetsFile { get; set; }
|
||||||
|
public string Container { get; set; }
|
||||||
|
public Texture2D Texture { get; set; }
|
||||||
|
public Texture2D AlphaTexture { get; set; }
|
||||||
|
public Rectf TextureRect { get; set; }
|
||||||
|
public bool Rotate { get; set; }
|
||||||
|
public float DownscaleMultiplier { get; }
|
||||||
|
|
||||||
|
public PortraitSprite()
|
||||||
|
{
|
||||||
|
Type = ClassIDType.AkPortraitSprite;
|
||||||
|
DownscaleMultiplier = 1f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
AssetStudioGUI/Components/Arknights/PortraitSpriteConfig.cs
Normal file
41
AssetStudioGUI/Components/Arknights/PortraitSpriteConfig.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
namespace Arknights.PortraitSpriteMono
|
||||||
|
{
|
||||||
|
internal class PortraitRect
|
||||||
|
{
|
||||||
|
public float X { get; set; }
|
||||||
|
public float Y { get; set; }
|
||||||
|
public float W { get; set; }
|
||||||
|
public float H { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class AtlasSprite
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Guid { get; set; }
|
||||||
|
public int Atlas { get; set; }
|
||||||
|
public PortraitRect Rect { get; set; }
|
||||||
|
public bool Rotate { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class TextureIDs
|
||||||
|
{
|
||||||
|
public int m_FileID { get; set; }
|
||||||
|
public long m_PathID { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class AtlasInfo
|
||||||
|
{
|
||||||
|
public int Index { get; set; }
|
||||||
|
public TextureIDs Texture { get; set; }
|
||||||
|
public TextureIDs Alpha { get; set; }
|
||||||
|
public int Size { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class PortraitSpriteConfig
|
||||||
|
{
|
||||||
|
public string m_Name { get; set; }
|
||||||
|
public AtlasSprite[] _sprites { get; set; }
|
||||||
|
public AtlasInfo _atlas { get; set; }
|
||||||
|
public int _index { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using AssetStudio;
|
using AssetStudio;
|
||||||
|
using Arknights;
|
||||||
|
|
||||||
namespace AssetStudioGUI
|
namespace AssetStudioGUI
|
||||||
{
|
{
|
||||||
@ -15,6 +16,7 @@ namespace AssetStudioGUI
|
|||||||
public string InfoText;
|
public string InfoText;
|
||||||
public string UniqueID;
|
public string UniqueID;
|
||||||
public GameObjectTreeNode TreeNode;
|
public GameObjectTreeNode TreeNode;
|
||||||
|
public PortraitSprite AkPortraitSprite;
|
||||||
|
|
||||||
public AssetItem(Object asset)
|
public AssetItem(Object asset)
|
||||||
{
|
{
|
||||||
@ -26,6 +28,19 @@ namespace AssetStudioGUI
|
|||||||
FullSize = asset.byteSize;
|
FullSize = asset.byteSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AssetItem(PortraitSprite akPortraitSprite)
|
||||||
|
{
|
||||||
|
Asset = null;
|
||||||
|
SourceFile = akPortraitSprite.AssetsFile;
|
||||||
|
Container = akPortraitSprite.Container;
|
||||||
|
Type = akPortraitSprite.Type;
|
||||||
|
TypeString = Type.ToString();
|
||||||
|
Text = akPortraitSprite.Name;
|
||||||
|
m_PathID = -1;
|
||||||
|
FullSize = (long)(akPortraitSprite.TextureRect.width * akPortraitSprite.TextureRect.height * 4);
|
||||||
|
AkPortraitSprite = akPortraitSprite;
|
||||||
|
}
|
||||||
|
|
||||||
public void SetSubItems()
|
public void SetSubItems()
|
||||||
{
|
{
|
||||||
SubItems.AddRange(new[]
|
SubItems.AddRange(new[]
|
||||||
|
@ -247,7 +247,7 @@ namespace AssetStudioGUI
|
|||||||
var alias = "";
|
var alias = "";
|
||||||
var m_Sprite = (Sprite)item.Asset;
|
var m_Sprite = (Sprite)item.Asset;
|
||||||
var spriteMaskMode = Properties.Settings.Default.exportSpriteWithMask ? SpriteMaskMode.Export : SpriteMaskMode.Off;
|
var spriteMaskMode = Properties.Settings.Default.exportSpriteWithMask ? SpriteMaskMode.Export : SpriteMaskMode.Off;
|
||||||
var type = Properties.Settings.Default.convertType;
|
var type = Properties.Settings.Default.convertType;
|
||||||
var isCharAvgSprite = item.Container.Contains("avg/characters");
|
var isCharAvgSprite = item.Container.Contains("avg/characters");
|
||||||
var isCharArt = item.Container.Contains("arts/characters");
|
var isCharArt = item.Container.Contains("arts/characters");
|
||||||
|
|
||||||
@ -296,8 +296,32 @@ namespace AssetStudioGUI
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool ExportPortraitSprite(AssetItem item, string exportPath)
|
||||||
|
{
|
||||||
|
var type = Properties.Settings.Default.convertType;
|
||||||
|
var spriteMaskMode = Properties.Settings.Default.exportSpriteWithMask ? SpriteMaskMode.Export : SpriteMaskMode.Off;
|
||||||
|
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var image = item.AkPortraitSprite.AkGetImage(spriteMaskMode: spriteMaskMode);
|
||||||
|
if (image != null)
|
||||||
|
{
|
||||||
|
using (image)
|
||||||
|
{
|
||||||
|
using (var file = File.OpenWrite(exportFullPath))
|
||||||
|
{
|
||||||
|
image.WriteToStream(file, type);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool ExportRawFile(AssetItem item, string exportPath)
|
public static bool ExportRawFile(AssetItem item, string exportPath)
|
||||||
{
|
{
|
||||||
|
if (item.Asset == null)
|
||||||
|
return false;
|
||||||
if (!TryExportFile(exportPath, item, ".dat", out var exportFullPath))
|
if (!TryExportFile(exportPath, item, ".dat", out var exportFullPath))
|
||||||
return false;
|
return false;
|
||||||
File.WriteAllBytes(exportFullPath, item.Asset.GetRawData());
|
File.WriteAllBytes(exportFullPath, item.Asset.GetRawData());
|
||||||
@ -375,6 +399,8 @@ namespace AssetStudioGUI
|
|||||||
|
|
||||||
public static bool ExportDumpFile(AssetItem item, string exportPath)
|
public static bool ExportDumpFile(AssetItem item, string exportPath)
|
||||||
{
|
{
|
||||||
|
if (item.Asset == null)
|
||||||
|
return false;
|
||||||
if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath))
|
if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath))
|
||||||
return false;
|
return false;
|
||||||
var str = item.Asset.Dump();
|
var str = item.Asset.Dump();
|
||||||
@ -415,6 +441,8 @@ namespace AssetStudioGUI
|
|||||||
return ExportMovieTexture(item, exportPath);
|
return ExportMovieTexture(item, exportPath);
|
||||||
case ClassIDType.Sprite:
|
case ClassIDType.Sprite:
|
||||||
return ExportSprite(item, exportPath);
|
return ExportSprite(item, exportPath);
|
||||||
|
case ClassIDType.AkPortraitSprite:
|
||||||
|
return ExportPortraitSprite(item, exportPath);
|
||||||
case ClassIDType.Animator:
|
case ClassIDType.Animator:
|
||||||
return ExportAnimator(item, exportPath);
|
return ExportAnimator(item, exportPath);
|
||||||
case ClassIDType.AnimationClip:
|
case ClassIDType.AnimationClip:
|
||||||
|
@ -263,8 +263,18 @@ namespace AssetStudioGUI
|
|||||||
{
|
{
|
||||||
if (pptr.TryGet(out var obj))
|
if (pptr.TryGet(out var obj))
|
||||||
{
|
{
|
||||||
objectAssetItemDic[obj].Container = container;
|
var asset = objectAssetItemDic[obj];
|
||||||
|
asset.Container = container;
|
||||||
allContainers[obj] = container;
|
allContainers[obj] = container;
|
||||||
|
|
||||||
|
if (asset.Type == ClassIDType.MonoBehaviour && container.Contains("/arts/charportraits/portraits"))
|
||||||
|
{
|
||||||
|
var portraitsList = Arknights.AkSpriteHelper.GeneratePortraits(asset);
|
||||||
|
foreach (var portrait in portraitsList)
|
||||||
|
{
|
||||||
|
exportableAssets.Add(new AssetItem(portrait));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (var tmp in exportableAssets)
|
foreach (var tmp in exportableAssets)
|
||||||
@ -726,7 +736,7 @@ namespace AssetStudioGUI
|
|||||||
|
|
||||||
public static string DumpAsset(Object obj)
|
public static string DumpAsset(Object obj)
|
||||||
{
|
{
|
||||||
var str = obj.Dump();
|
var str = obj?.Dump();
|
||||||
if (str == null && obj is MonoBehaviour m_MonoBehaviour)
|
if (str == null && obj is MonoBehaviour m_MonoBehaviour)
|
||||||
{
|
{
|
||||||
var type = MonoBehaviourToTypeTree(m_MonoBehaviour);
|
var type = MonoBehaviourToTypeTree(m_MonoBehaviour);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user