diff --git a/AssetStudio/Classes/Sprite.cs b/AssetStudio/Classes/Sprite.cs index 488ab1c..a987620 100644 --- a/AssetStudio/Classes/Sprite.cs +++ b/AssetStudio/Classes/Sprite.cs @@ -6,6 +6,40 @@ using System.Text; namespace AssetStudio { + public enum SpritePackingRotation + { + kSPRNone = 0, + kSPRFlipHorizontal = 1, + kSPRFlipVertical = 2, + kSPRRotate180 = 3, + kSPRRotate90 = 4 + }; + + public enum SpritePackingMode + { + kSPMTight = 0, + kSPMRectangle + }; + + public class SpriteSettings + { + public uint settingsRaw; + + public uint packed => settingsRaw & 1; //1 + public SpritePackingMode packingMode => (SpritePackingMode)((settingsRaw >> 1) & 1); //1 + public SpritePackingRotation packingRotation => (SpritePackingRotation)((settingsRaw >> 2) & 0xf); //4 + public uint reserved => settingsRaw >> 6; //26 + /* + *public uint meshType => (settingsRaw >> 6) & 1; //1 + *public uint reserved => settingsRaw >> 7; //25 + */ + + public SpriteSettings(ObjectReader reader) + { + settingsRaw = reader.ReadUInt32(); + } + } + public sealed class Sprite : NamedObject { public RectangleF m_Rect; @@ -15,6 +49,7 @@ namespace AssetStudio public PPtr texture; public PPtr m_SpriteAtlas; public RectangleF textureRect; + public SpriteSettings settingsRaw; public PointF[][] m_PhysicsShape; public Sprite(ObjectReader reader) : base(reader) @@ -145,7 +180,7 @@ namespace AssetStudio reader.Position += 8; } // unsigned int settingsRaw - reader.Position += 4; + settingsRaw = new SpriteSettings(reader); // Vector4f uvTransform - 4.5 and up if (version[0] > 4 || (version[0] == 4 && version[1] >= 5)) //4.5 and up { diff --git a/AssetStudio/Classes/SpriteAtlas.cs b/AssetStudio/Classes/SpriteAtlas.cs index 75a8ab3..a5c0ca3 100644 --- a/AssetStudio/Classes/SpriteAtlas.cs +++ b/AssetStudio/Classes/SpriteAtlas.cs @@ -1,4 +1,5 @@ -using System; +using SharpDX; +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; @@ -6,53 +7,60 @@ using System.Text; namespace AssetStudio { + public class SpriteAtlasData + { + public PPtr texture; + public PPtr alphaTexture; + public System.Drawing.RectangleF textureRect; + public Vector2 textureRectOffset; + public Vector2 atlasRectOffset; + public Vector4 uvTransform; + public float downscaleMultiplier; + public SpriteSettings settingsRaw; + + public SpriteAtlasData(ObjectReader reader) + { + var version = reader.version; + texture = reader.ReadPPtr(); + alphaTexture = reader.ReadPPtr(); + textureRect = reader.ReadRectangleF(); + textureRectOffset = reader.ReadVector2(); + if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up + { + atlasRectOffset = reader.ReadVector2(); + } + uvTransform = reader.ReadVector4(); + downscaleMultiplier = reader.ReadSingle(); + settingsRaw = new SpriteSettings(reader); + } + } + public sealed class SpriteAtlas : NamedObject { - public List textures = new List(); - public List textureRects = new List(); - public List guids = new List(); - + public Dictionary, SpriteAtlasData> m_RenderDataMap; public SpriteAtlas(ObjectReader reader) : base(reader) { - //vector m_PackedSprites - var size = reader.ReadInt32(); - for (int i = 0; i < size; i++) + var m_PackedSpritesSize = reader.ReadInt32(); + for (int i = 0; i < m_PackedSpritesSize; i++) { - //PPtr data - reader.ReadPPtr(); + reader.ReadPPtr(); //PPtr data } - //vector m_PackedSpriteNamesToIndex - size = reader.ReadInt32(); - for (int i = 0; i < size; i++) + + var m_PackedSpriteNamesToIndexSize = reader.ReadInt32(); + for (int i = 0; i < m_PackedSpriteNamesToIndexSize; i++) { - var data = reader.ReadAlignedString(); + reader.ReadAlignedString(); } - //map m_RenderDataMap - size = reader.ReadInt32(); - for (int i = 0; i < size; i++) + + var m_RenderDataMapSize = reader.ReadInt32(); + m_RenderDataMap = new Dictionary, SpriteAtlasData>(m_RenderDataMapSize); + for (int i = 0; i < m_RenderDataMapSize; i++) { - //pair first - guids.Add(new Guid(reader.ReadBytes(16))); + var first = new Guid(reader.ReadBytes(16)); var second = reader.ReadInt64(); - //SpriteAtlasData second - // PPtr texture - textures.Add(reader.ReadPPtr()); - // PPtr alphaTexture - var alphaTexture = reader.ReadPPtr(); - // Rectf textureRect - textureRects.Add(new RectangleF(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle())); - // Vector2f textureRectOffset - reader.Position += 8; - if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2))//2017.2 and up - { - // Vector2f atlasRectOffset - reader.Position += 8; - } - // Vector4f uvTransform - // float downscaleMultiplier - // unsigned int settingsRaw - reader.Position += 24; + var value = new SpriteAtlasData(reader); + m_RenderDataMap.Add(new Tuple(first, second), value); } //string m_Tag //bool m_IsVariant diff --git a/AssetStudio/StudioClasses/BinaryReaderExtensions.cs b/AssetStudio/StudioClasses/BinaryReaderExtensions.cs index 8c8f1f0..4141e46 100644 --- a/AssetStudio/StudioClasses/BinaryReaderExtensions.cs +++ b/AssetStudio/StudioClasses/BinaryReaderExtensions.cs @@ -21,11 +21,7 @@ namespace AssetStudio public static string ReadAlignedString(this BinaryReader reader) { - return ReadAlignedString(reader, reader.ReadInt32()); - } - - public static string ReadAlignedString(this BinaryReader reader, int length) - { + var length = reader.ReadInt32(); if (length > 0 && length < (reader.BaseStream.Length - reader.BaseStream.Position)) { var stringData = reader.ReadBytes(length); @@ -47,47 +43,27 @@ namespace AssetStudio public static Quaternion ReadQuaternion(this BinaryReader reader) { - var q = new Quaternion - { - X = reader.ReadSingle(), - Y = reader.ReadSingle(), - Z = reader.ReadSingle(), - W = reader.ReadSingle() - }; - return q; + return new Quaternion(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); } public static Vector2 ReadVector2(this BinaryReader reader) { - Vector2 v = new Vector2 - { - X = reader.ReadSingle(), - Y = reader.ReadSingle() - }; - return v; + return new Vector2(reader.ReadSingle(), reader.ReadSingle()); } public static Vector3 ReadVector3(this BinaryReader reader) { - var v = new Vector3 - { - X = reader.ReadSingle(), - Y = reader.ReadSingle(), - Z = reader.ReadSingle() - }; - return v; + return new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); } public static Vector4 ReadVector4(this BinaryReader reader) { - var v = new Vector4 - { - X = reader.ReadSingle(), - Y = reader.ReadSingle(), - Z = reader.ReadSingle(), - W = reader.ReadSingle() - }; - return v; + return new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + } + + public static System.Drawing.RectangleF ReadRectangleF(this BinaryReader reader) + { + return new System.Drawing.RectangleF(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); } private static T[] ReadArray(Func del, int length) diff --git a/AssetStudio/StudioClasses/Exporter.cs b/AssetStudio/StudioClasses/Exporter.cs index 1cff27e..7c8ccc0 100644 --- a/AssetStudio/StudioClasses/Exporter.cs +++ b/AssetStudio/StudioClasses/Exporter.cs @@ -266,6 +266,7 @@ namespace AssetStudio if (bitmap != null) { bitmap.Save(exportFullName, format); + bitmap.Dispose(); return true; } return false; diff --git a/AssetStudio/StudioClasses/SpriteHelper.cs b/AssetStudio/StudioClasses/SpriteHelper.cs index 14e98b6..c6cd8e9 100644 --- a/AssetStudio/StudioClasses/SpriteHelper.cs +++ b/AssetStudio/StudioClasses/SpriteHelper.cs @@ -12,39 +12,50 @@ namespace AssetStudio { public static Bitmap GetImageFromSprite(Sprite m_Sprite) { + Bitmap bitmap = null; + SpriteSettings settingsRaw = null; if (m_Sprite.m_SpriteAtlas != null && m_Sprite.m_SpriteAtlas.TryGet(out var objectReader)) { var m_SpriteAtlas = new SpriteAtlas(objectReader); - var index = m_SpriteAtlas.guids.FindIndex(x => x == m_Sprite.first); - - if (index >= 0 && m_SpriteAtlas.textures[index].TryGet(out objectReader)) + var spriteAtlasData = m_SpriteAtlas.m_RenderDataMap.FirstOrDefault(x => x.Key.Item1 == m_Sprite.first).Value; + if (spriteAtlasData != null && spriteAtlasData.texture.TryGet(out objectReader)) { + settingsRaw = spriteAtlasData.settingsRaw; try { - if (m_Sprite.m_PhysicsShape.Length > 0) + if (settingsRaw.packingMode == SpritePackingMode.kSPMTight && m_Sprite.m_PhysicsShape.Length > 0) //Tight { - return CutImage(objectReader, m_SpriteAtlas.textureRects[index], m_Sprite); + bitmap = CutTightImage(objectReader, spriteAtlasData.textureRect, m_Sprite); + } + else + { + bitmap = CutRectangleImage(objectReader, spriteAtlasData.textureRect); } - return CutImage(objectReader, m_SpriteAtlas.textureRects[index]); } catch { - return CutImage(objectReader, m_SpriteAtlas.textureRects[index]); + bitmap = CutRectangleImage(objectReader, spriteAtlasData.textureRect); } } } else { + //TODO Tight if (m_Sprite.texture.TryGet(out objectReader)) { - return CutImage(objectReader, m_Sprite.textureRect); + settingsRaw = m_Sprite.settingsRaw; + bitmap = CutRectangleImage(objectReader, m_Sprite.textureRect); } } - + if (bitmap != null) + { + RotateAndFlip(bitmap, settingsRaw.packingRotation); + return bitmap; + } return null; } - private static Bitmap CutImage(ObjectReader texture2DAsset, RectangleF textureRect) + private static Bitmap CutRectangleImage(ObjectReader texture2DAsset, RectangleF textureRect) { var texture2D = new Texture2DConverter(new Texture2D(texture2DAsset, true)); using (var originalImage = texture2D.ConvertToBitmap(false)) @@ -60,7 +71,7 @@ namespace AssetStudio return null; } - private static Bitmap CutImage(ObjectReader texture2DAsset, RectangleF textureRect, Sprite sprite) + private static Bitmap CutTightImage(ObjectReader texture2DAsset, RectangleF textureRect, Sprite sprite) { var texture2D = new Texture2DConverter(new Texture2D(texture2DAsset, true)); using (var originalImage = texture2D.ConvertToBitmap(false)) @@ -94,5 +105,24 @@ namespace AssetStudio return null; } + + private static void RotateAndFlip(Bitmap bitmap, SpritePackingRotation packingRotation) + { + switch (packingRotation) + { + case SpritePackingRotation.kSPRFlipHorizontal: + bitmap.RotateFlip(RotateFlipType.RotateNoneFlipX); + break; + case SpritePackingRotation.kSPRFlipVertical: + bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY); + break; + case SpritePackingRotation.kSPRRotate180: + bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone); + break; + case SpritePackingRotation.kSPRRotate90: + bitmap.RotateFlip(RotateFlipType.Rotate270FlipNone); + break; + } + } } }