add Sprite support

This commit is contained in:
Perfare 2018-01-18 08:08:48 +08:00
parent 468976db58
commit fc44ba373b
10 changed files with 330 additions and 12 deletions

View File

@ -0,0 +1,136 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
namespace Unity_Studio
{
class Sprite
{
public string m_Name;
public PPtr texture;
public PPtr m_SpriteAtlas;
public RectangleF textureRect;
public Sprite(AssetPreloadData preloadData, bool readSwitch)
{
var sourceFile = preloadData.sourceFile;
var a_Stream = preloadData.sourceFile.a_Stream;
a_Stream.Position = preloadData.Offset;
m_Name = a_Stream.ReadAlignedString(a_Stream.ReadInt32());
if (readSwitch)
{
//Rectf m_Rect
var m_Rect = new RectangleF(a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle());
//Vector2f m_Offset
a_Stream.Position += 8;
if (sourceFile.version[0] > 4 || (sourceFile.version[0] == 4 && sourceFile.version[1] >= 2)) //4.2 and up
{
//Vector4f m_Border
a_Stream.Position += 16;
}
var m_PixelsToUnits = a_Stream.ReadSingle();
if (sourceFile.version[0] > 5 || (sourceFile.version[0] == 5 && sourceFile.version[1] >= 5)) //5.5 and up
{
//Vector2f m_Pivot
a_Stream.Position += 8;
}
var m_Extrude = a_Stream.ReadUInt32();
if (sourceFile.version[0] > 5 || (sourceFile.version[0] == 5 && sourceFile.version[1] >= 1)) //5.1 and up
{
var m_IsPolygon = a_Stream.ReadBoolean();
a_Stream.AlignStream(4);
}
if (sourceFile.version[0] >= 2017) //2017 and up
{
//pair m_RenderDataKey
a_Stream.Position += 24;
//vector m_AtlasTags
var size = a_Stream.ReadInt32();
for (int i = 0; i < size; i++)
{
var data = a_Stream.ReadAlignedString(a_Stream.ReadInt32());
}
//PPtr<SpriteAtlas> m_SpriteAtlas
m_SpriteAtlas = sourceFile.ReadPPtr();
}
//SpriteRenderData m_RD
// PPtr<Texture2D> texture
texture = sourceFile.ReadPPtr();
// PPtr<Texture2D> alphaTexture
if (sourceFile.version[0] >= 5) //5.0 and up
{
var alphaTexture = sourceFile.ReadPPtr();
}
if (sourceFile.version[0] > 5 || (sourceFile.version[0] == 5 && sourceFile.version[1] >= 6)) //5.6 and up
{
// vector m_SubMeshes
var size = a_Stream.ReadInt32();
// SubMesh data
if (sourceFile.version[0] > 2017 || (sourceFile.version[0] == 2017 && sourceFile.version[1] >= 3)) //2017.3 and up
{
a_Stream.Position += 48 * size;
}
else
{
a_Stream.Position += 44 * size;
}
// vector m_IndexBuffer
size = a_Stream.ReadInt32();
a_Stream.Position += size; //UInt8 data
a_Stream.AlignStream(4);
// VertexData m_VertexData
var m_CurrentChannels = a_Stream.ReadInt32();
var m_VertexCount = a_Stream.ReadUInt32();
// vector m_Channels
size = a_Stream.ReadInt32();
a_Stream.Position += size * 4; //ChannelInfo data
// TypelessData m_DataSize
size = a_Stream.ReadInt32();
a_Stream.Position += size; //UInt8 data
a_Stream.AlignStream(4);
}
else
{
// vector vertices
var size = a_Stream.ReadInt32();
for (int i = 0; i < size; i++)
{
//SpriteVertex data
a_Stream.Position += 12; //Vector3f pos
if (sourceFile.version[0] < 4 || (sourceFile.version[0] == 4 && sourceFile.version[1] <= 1)) //4.1 and down
a_Stream.Position += 8; //Vector2f uv
}
// vector indices
size = a_Stream.ReadInt32();
a_Stream.Position += 2 * size; //UInt16 data
a_Stream.AlignStream(4);
}
// Rectf textureRect
textureRect = new RectangleF(a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle());
// Vector2f textureRectOffset
// Vector2f atlasRectOffset - 5.6 and up
// unsigned int settingsRaw
// Vector4f uvTransform - 4.2 and up
// float downscaleMultiplier - 2017 and up
//vector m_PhysicsShape - 2017 and up
}
else
{
preloadData.extension = ".png";
preloadData.Text = m_Name;
}
}
}
}

View File

@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
namespace Unity_Studio
{
class SpriteAtlas
{
public List<PPtr> m_PackedSprites = new List<PPtr>();
public List<PPtr> textures = new List<PPtr>();
public List<RectangleF> textureRects = new List<RectangleF>();
public SpriteAtlas(AssetPreloadData preloadData)
{
var sourceFile = preloadData.sourceFile;
var a_Stream = preloadData.sourceFile.a_Stream;
a_Stream.Position = preloadData.Offset;
var m_Name = a_Stream.ReadAlignedString(a_Stream.ReadInt32());
//vector m_PackedSprites
var size = a_Stream.ReadInt32();
for (int i = 0; i < size; i++)
{
//PPtr<Sprite> data
m_PackedSprites.Add(sourceFile.ReadPPtr());
}
//vector m_PackedSpriteNamesToIndex
size = a_Stream.ReadInt32();
for (int i = 0; i < size; i++)
{
var data = a_Stream.ReadAlignedString(a_Stream.ReadInt32());
}
//map m_RenderDataMap
size = a_Stream.ReadInt32();
for (int i = 0; i < size; i++)
{
//pair first
a_Stream.Position += 24;
//SpriteAtlasData second
// PPtr<Texture2D> texture
textures.Add(sourceFile.ReadPPtr());
// PPtr<Texture2D> alphaTexture
var alphaTexture = sourceFile.ReadPPtr();
// Rectf textureRect
textureRects.Add(new RectangleF(a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle()));
// Vector2f textureRectOffset
a_Stream.Position += 8;
if (sourceFile.version[0] > 2017 || (sourceFile.version[0] == 2017 && sourceFile.version[1] >= 2))//2017.2 and up
{
// Vector2f atlasRectOffset
a_Stream.Position += 8;
}
// Vector4f uvTransform
// float downscaleMultiplier
// unsigned int settingsRaw
a_Stream.Position += 24;
}
//string m_Tag
//bool m_IsVariant
}
}
}

View File

@ -658,7 +658,7 @@ namespace Unity_Studio
} }
else else
{ {
preloadData.InfoText = "Width: " + m_Width + "\nHeight: " + m_Height + "\nFormat: "; preloadData.InfoText = $"Width: {m_Width}\nHeight: {m_Height}\nFormat: ";
string type = m_TextureFormat.ToString(); string type = m_TextureFormat.ToString();
preloadData.InfoText += type; preloadData.InfoText += type;
@ -737,7 +737,7 @@ namespace Unity_Studio
} }
preloadData.InfoText += "\nAnisotropic level: " + m_Aniso + "\nMip map bias: " + m_MipBias; preloadData.InfoText += $"\nAnisotropic level: {m_Aniso}\nMip map bias: {m_MipBias}";
switch (m_WrapMode) switch (m_WrapMode)
{ {

View File

@ -12,7 +12,7 @@ namespace Unity_Studio
public uint Offset; public uint Offset;
public int Size; public int Size;
public int Type1; public int Type1;
public ushort Type2; public int Type2;
public string TypeString; public string TypeString;
public int fullSize; public int fullSize;

View File

@ -321,7 +321,7 @@ namespace Unity_Studio
{ {
int index = a_Stream.ReadInt32(); int index = a_Stream.ReadInt32();
asset.Type1 = classIDs[index][0]; asset.Type1 = classIDs[index][0];
asset.Type2 = (ushort)classIDs[index][1]; asset.Type2 = classIDs[index][1];
} }
else else
{ {

View File

@ -266,6 +266,12 @@ namespace Unity_Studio
{1112, "SubstanceImporter"}, {1112, "SubstanceImporter"},
{1113, "LightmapParameters"}, {1113, "LightmapParameters"},
{1120, "LightmapSnapshot"}, {1120, "LightmapSnapshot"},
{367388927, "SubDerived"},
{334799969, "SiblingDerived"},
{687078895, "SpriteAtlas"},
{1091556383, "Derived"},
{1480428607, "LowerResBlitTexture"},
{1571458007, "RenderPassAttachment"}
}; };
} }
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.IO; using System.IO;
@ -22,6 +23,7 @@ namespace Unity_Studio
public static List<AssetPreloadData> exportableAssets = new List<AssetPreloadData>(); //used to hold all assets while the ListView is filtered public static List<AssetPreloadData> exportableAssets = new List<AssetPreloadData>(); //used to hold all assets while the ListView is filtered
private static HashSet<string> exportableAssetsHash = new HashSet<string>(); //avoid the same name asset private static HashSet<string> exportableAssetsHash = new HashSet<string>(); //avoid the same name asset
public static List<AssetPreloadData> visibleAssets = new List<AssetPreloadData>(); //used to build the ListView from all or filtered assets public static List<AssetPreloadData> visibleAssets = new List<AssetPreloadData>(); //used to build the ListView from all or filtered assets
private static Dictionary<AssetPreloadData, Bitmap> spriteCache = new Dictionary<AssetPreloadData, Bitmap>();
public static string productName = ""; public static string productName = "";
public static string mainPath = ""; public static string mainPath = "";
@ -303,12 +305,18 @@ namespace Unity_Studio
exportable = true; exportable = true;
break; break;
} }
case 21: //Material case 213: //Sprite
{
var m_Sprite = new Sprite(asset, false);
exportable = true;
break;
}
/*case 21: //Material
case 74: //AnimationClip case 74: //AnimationClip
case 90: //Avatar case 90: //Avatar
case 91: //AnimatorController case 91: //AnimatorController
case 115: //MonoScript case 115: //MonoScript
case 213: //Sprite case 687078895: //SpriteAtlas
{ {
if (asset.Offset + 4 > asset.sourceFile.a_Stream.BaseStream.Length) if (asset.Offset + 4 > asset.sourceFile.a_Stream.BaseStream.Length)
break; break;
@ -320,7 +328,7 @@ namespace Unity_Studio
asset.Text = Encoding.UTF8.GetString(bytes); asset.Text = Encoding.UTF8.GetString(bytes);
} }
break; break;
} }*/
} }
if (!exportable && displayAll) if (!exportable && displayAll)
{ {
@ -1823,6 +1831,20 @@ namespace Unity_Studio
return true; return true;
} }
public static bool ExportSprite(AssetPreloadData asset, string exportPath)
{
var exportFullName = exportPath + asset.Text + asset.extension;
if (ExportFileExists(exportFullName))
return false;
var bitmap = GetImageFromSprite(asset);
if (bitmap != null)
{
bitmap.Save(exportFullName, ImageFormat.Png);
return true;
}
return false;
}
public static bool ExportRawFile(AssetPreloadData asset, string exportPath) public static bool ExportRawFile(AssetPreloadData asset, string exportPath)
{ {
var exportFullName = exportPath + asset.Text + asset.extension; var exportFullName = exportPath + asset.Text + asset.extension;
@ -1884,5 +1906,61 @@ namespace Unity_Studio
} }
return selectFile.Distinct().ToArray(); return selectFile.Distinct().ToArray();
} }
//TODO Tight方式的Sprite需要读取多边形信息进行绘图
public static Bitmap GetImageFromSprite(AssetPreloadData asset)
{
if (spriteCache.TryGetValue(asset, out var bitmap))
return (Bitmap)bitmap.Clone();
var m_Sprite = new Sprite(asset, true);
if (m_Sprite.m_SpriteAtlas != null && assetsfileList.TryGetPD(m_Sprite.m_SpriteAtlas, out var assetPreloadData))
{
var m_SpriteAtlas = new SpriteAtlas(assetPreloadData);
bool find = false;
int index = 0;
for (; index < m_SpriteAtlas.m_PackedSprites.Count; index++)
{
if (assetsfileList.TryGetPD(m_SpriteAtlas.m_PackedSprites[index], out assetPreloadData) && assetPreloadData == asset)
{
find = true;
break;
}
}
if (find && assetsfileList.TryGetPD(m_SpriteAtlas.textures[index], out assetPreloadData))
{
return CutImage(asset, assetPreloadData, m_SpriteAtlas.textureRects[index]);
}
}
else
{
if (assetsfileList.TryGetPD(m_Sprite.texture, out assetPreloadData))
{
return CutImage(asset, assetPreloadData, m_Sprite.textureRect);
}
}
return null;
}
private static Bitmap CutImage(AssetPreloadData asset, AssetPreloadData texture2DAsset, RectangleF textureRect)
{
var texture2D = new Texture2D(texture2DAsset, true);
using (var originalImage = texture2D.ConvertToBitmap(false))
{
if (originalImage != null)
{
var info = texture2DAsset.InfoText;
var start = info.IndexOf("Format");
info = info.Substring(start, info.Length - start);
asset.InfoText = $"Width: {textureRect.Width}\nHeight: {textureRect.Height}\n" + info;
var spriteImage = originalImage.Clone(textureRect, PixelFormat.Format32bppArgb);
spriteImage.RotateFlip(RotateFlipType.RotateNoneFlipY);
spriteCache.Add(asset, spriteImage);
return (Bitmap)spriteImage.Clone();
}
}
return null;
}
} }
} }

View File

@ -143,6 +143,8 @@
</Compile> </Compile>
<Compile Include="Unity Classes\AssetBundle.cs" /> <Compile Include="Unity Classes\AssetBundle.cs" />
<Compile Include="Unity Classes\MovieTexture.cs" /> <Compile Include="Unity Classes\MovieTexture.cs" />
<Compile Include="Unity Classes\Sprite.cs" />
<Compile Include="Unity Classes\SpriteAtlas.cs" />
<Compile Include="Unity Classes\VideoClip.cs" /> <Compile Include="Unity Classes\VideoClip.cs" />
<Compile Include="Unity Studio Classes\AssetPreloadData.cs" /> <Compile Include="Unity Studio Classes\AssetPreloadData.cs" />
<Compile Include="Unity Classes\AudioClip.cs" /> <Compile Include="Unity Classes\AudioClip.cs" />

View File

@ -143,6 +143,8 @@
</Compile> </Compile>
<Compile Include="Unity Classes\AssetBundle.cs" /> <Compile Include="Unity Classes\AssetBundle.cs" />
<Compile Include="Unity Classes\MovieTexture.cs" /> <Compile Include="Unity Classes\MovieTexture.cs" />
<Compile Include="Unity Classes\Sprite.cs" />
<Compile Include="Unity Classes\SpriteAtlas.cs" />
<Compile Include="Unity Classes\VideoClip.cs" /> <Compile Include="Unity Classes\VideoClip.cs" />
<Compile Include="Unity Studio Classes\AssetPreloadData.cs" /> <Compile Include="Unity Studio Classes\AssetPreloadData.cs" />
<Compile Include="Unity Classes\AudioClip.cs" /> <Compile Include="Unity Classes\AudioClip.cs" />

View File

@ -424,6 +424,7 @@ namespace Unity_Studio
switch (lastLoadedAsset.Type2) switch (lastLoadedAsset.Type2)
{ {
case 28: case 28:
case 213:
{ {
if (enablePreview.Checked && imageTexture != null) if (enablePreview.Checked && imageTexture != null)
{ {
@ -737,14 +738,16 @@ namespace Unity_Studio
if (e.IsSelected) if (e.IsSelected)
{ {
assetInfoLabel.Text = lastSelectedItem.InfoText;
if (displayInfo.Checked && assetInfoLabel.Text != null) { assetInfoLabel.Visible = true; } //only display the label if asset has info text
if (enablePreview.Checked) if (enablePreview.Checked)
{ {
lastLoadedAsset = lastSelectedItem; lastLoadedAsset = lastSelectedItem;
PreviewAsset(lastLoadedAsset); PreviewAsset(lastLoadedAsset);
} }
if (displayInfo.Checked && assetInfoLabel.Text != null)//only display the label if asset has info text
{
assetInfoLabel.Text = lastSelectedItem.InfoText;
assetInfoLabel.Visible = true;
}
} }
} }
@ -1049,14 +1052,34 @@ namespace Unity_Studio
} }
break; break;
#endregion #endregion
#region VideoClip #region VideoClip and MovieTexture
case 329: case 329: //VideoClip
case 152: //MovieTexture case 152: //MovieTexture
{ {
StatusStripUpdate("Only supported export."); StatusStripUpdate("Only supported export.");
break; break;
} }
#endregion #endregion
#region Sprite
case 213: //Sprite
{
imageTexture?.Dispose();
imageTexture = GetImageFromSprite(asset);
if (imageTexture != null)
{
previewPanel.BackgroundImage = imageTexture;
if (imageTexture.Width > previewPanel.Width || imageTexture.Height > previewPanel.Height)
previewPanel.BackgroundImageLayout = ImageLayout.Zoom;
else
previewPanel.BackgroundImageLayout = ImageLayout.Center;
}
else
{
StatusStripUpdate("Unsupported sprite for preview");
}
break;
}
#endregion
default: default:
{ {
var str = asset.ViewStruct(); var str = asset.ViewStruct();
@ -1545,6 +1568,12 @@ namespace Unity_Studio
exportedCount++; exportedCount++;
} }
break; break;
case 213: //Sprite
if (ExportSprite(asset, exportpath))
{
exportedCount++;
}
break;
default: default:
if (ExportRawFile(asset, exportpath)) if (ExportRawFile(asset, exportpath))
{ {