From ab24f049cfb76dd64704524d1f24518aa4f1709a Mon Sep 17 00:00:00 2001 From: Perfare Date: Sun, 25 Nov 2018 12:37:55 +0800 Subject: [PATCH] Completed tight Sprite export --- AssetStudio/Classes/Sprite.cs | 2 + AssetStudioUtility/SpriteHelper.cs | 132 +++++++++++++++++++++++++++-- 2 files changed, 125 insertions(+), 9 deletions(-) diff --git a/AssetStudio/Classes/Sprite.cs b/AssetStudio/Classes/Sprite.cs index 750a557..7306273 100644 --- a/AssetStudio/Classes/Sprite.cs +++ b/AssetStudio/Classes/Sprite.cs @@ -79,6 +79,8 @@ namespace AssetStudio public byte dividerOp; public ushort frequency; + public StreamInfo() { } + public StreamInfo(ObjectReader reader) { var version = reader.version; diff --git a/AssetStudioUtility/SpriteHelper.cs b/AssetStudioUtility/SpriteHelper.cs index eb3595b..6f24d57 100644 --- a/AssetStudioUtility/SpriteHelper.cs +++ b/AssetStudioUtility/SpriteHelper.cs @@ -1,7 +1,11 @@ -using System.Drawing; +using System.Collections.Generic; +using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; +using System.IO; using System.Linq; +using SharpDX; +using RectangleF = System.Drawing.RectangleF; namespace AssetStudio { @@ -53,25 +57,23 @@ namespace AssetStudio break; } - /* TODO Tight - * 2017之前没有PhysicsShape - * 5.6之前使用vertices - * 5.6需要使用VertexData - */ - if (settingsRaw.packingMode == SpritePackingMode.kSPMTight && m_Sprite.m_PhysicsShape?.Length > 0) //Tight + //Tight + //TODO 2017 and up use m_PhysicsShape should be better + if (settingsRaw.packingMode == SpritePackingMode.kSPMTight) { try { + var polygon = GetPolygon(m_Sprite.m_RD); + var points = polygon.Select(x => x.Select(y => new PointF(y.X, y.Y)).ToArray()); using (var brush = new TextureBrush(spriteImage)) { using (var path = new GraphicsPath()) { - var points = m_Sprite.m_PhysicsShape.Select(x => x.Select(y => new PointF(y.X, y.Y)).ToArray()); foreach (var p in points) { path.AddPolygon(p); } - using (var matr = new Matrix()) + using (var matr = new System.Drawing.Drawing2D.Matrix()) { matr.Translate(m_Sprite.m_Rect.Width * m_Sprite.m_Pivot.X, m_Sprite.m_Rect.Height * m_Sprite.m_Pivot.Y); matr.Scale(m_Sprite.m_PixelsToUnits, m_Sprite.m_PixelsToUnits); @@ -103,5 +105,117 @@ namespace AssetStudio return null; } + + private static Vector2[][] GetPolygon(SpriteRenderData m_RD) + { + if (m_RD.vertices != null) //5.6 down + { + var vertices = m_RD.vertices; + var polygon = new Vector2[1][]; + polygon[0] = new Vector2[vertices.Length]; + for (int i = 0; i < vertices.Length; i++) + { + polygon[0][i] = (Vector2)vertices[i].pos; + } + return polygon; + } + + return GetTriangles(m_RD); //5.6 and up + } + + private static Vector2[][] GetTriangles(SpriteRenderData m_RD) + { + var triangles = new List(); + var m_VertexData = m_RD.m_VertexData; + GetStreams(m_VertexData); + var m_Channel = m_VertexData.m_Channels[0]; //kShaderChannelVertex + var m_Stream = m_VertexData.m_Streams[m_Channel.stream]; + using (var vertexReader = new BinaryReader(new MemoryStream(m_VertexData.m_DataSize))) + { + foreach (var subMesh in m_RD.m_SubMeshes) + { + var vertices = new Vector2[subMesh.vertexCount]; + + vertexReader.BaseStream.Position = m_Stream.offset + subMesh.firstVertex * m_Stream.stride + m_Channel.offset; + for (int v = 0; v < subMesh.vertexCount; v++) + { + vertices[v] = (Vector2)vertexReader.ReadVector3(); + vertexReader.BaseStream.Position += m_Stream.stride - 12; + } + + var triangleCount = subMesh.indexCount / 3u; + using (var indexReader = new BinaryReader(new MemoryStream(m_RD.m_IndexBuffer))) + { + indexReader.BaseStream.Position = subMesh.firstByte; + for (int i = 0; i < triangleCount; i++) + { + int first = indexReader.ReadInt16(); + int second = indexReader.ReadInt16(); + int third = indexReader.ReadInt16(); + var triangle = new[] { vertices[first], vertices[second], vertices[third] }; + triangles.Add(triangle); + } + } + } + } + return triangles.ToArray(); + } + + private static void GetStreams(VertexData vertexData) + { + var m_Channels = vertexData.m_Channels; + var streamCount = m_Channels.Max(x => x.stream) + 1; + var m_Streams = new StreamInfo[streamCount]; + uint offset = 0; + for (int s = 0; s < streamCount; s++) + { + uint chnMask = 0; + uint stride = 0; + for (int chn = 0; chn < m_Channels.Length; chn++) + { + var m_Channel = m_Channels[chn]; + if (m_Channel.stream == s) + { + if (m_Channel.dimension > 0) + { + chnMask |= 1u << chn; + stride += m_Channel.dimension * GetChannelFormatSize(m_Channel.format); + } + } + } + m_Streams[s] = new StreamInfo + { + channelMask = chnMask, + offset = offset, + stride = stride, + dividerOp = 0, + frequency = 0 + }; + offset += vertexData.m_VertexCount * stride; + //static size_t AlignStreamSize (size_t size) { return (size + (kVertexStreamAlign-1)) & ~(kVertexStreamAlign-1); } + offset = (offset + (16u - 1u)) & ~(16u - 1u); + } + + vertexData.m_Streams = m_Streams; + } + + private static uint GetChannelFormatSize(int format) + { + switch (format) + { + case 0: //kChannelFormatFloat + return 4u; + case 1: //kChannelFormatFloat16 + return 2u; + case 2: //kChannelFormatColor, in 4.x is size 4 + return 1u; + case 3: //kChannelFormatByte + return 1u; + case 11: //kChannelFormatInt32 + return 4u; + default: + return 0; + } + } } }