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
{
preloadData.InfoText = "Width: " + m_Width + "\nHeight: " + m_Height + "\nFormat: ";
preloadData.InfoText = $"Width: {m_Width}\nHeight: {m_Height}\nFormat: ";
string type = m_TextureFormat.ToString();
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)
{

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
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
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
private static Dictionary<AssetPreloadData, Bitmap> spriteCache = new Dictionary<AssetPreloadData, Bitmap>();
public static string productName = "";
public static string mainPath = "";
@ -303,12 +305,18 @@ namespace Unity_Studio
exportable = true;
break;
}
case 21: //Material
case 213: //Sprite
{
var m_Sprite = new Sprite(asset, false);
exportable = true;
break;
}
/*case 21: //Material
case 74: //AnimationClip
case 90: //Avatar
case 91: //AnimatorController
case 115: //MonoScript
case 213: //Sprite
case 687078895: //SpriteAtlas
{
if (asset.Offset + 4 > asset.sourceFile.a_Stream.BaseStream.Length)
break;
@ -320,7 +328,7 @@ namespace Unity_Studio
asset.Text = Encoding.UTF8.GetString(bytes);
}
break;
}
}*/
}
if (!exportable && displayAll)
{
@ -1823,6 +1831,20 @@ namespace Unity_Studio
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)
{
var exportFullName = exportPath + asset.Text + asset.extension;
@ -1884,5 +1906,61 @@ namespace Unity_Studio
}
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 Include="Unity Classes\AssetBundle.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 Studio Classes\AssetPreloadData.cs" />
<Compile Include="Unity Classes\AudioClip.cs" />

View File

@ -143,6 +143,8 @@
</Compile>
<Compile Include="Unity Classes\AssetBundle.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 Studio Classes\AssetPreloadData.cs" />
<Compile Include="Unity Classes\AudioClip.cs" />

View File

@ -424,6 +424,7 @@ namespace Unity_Studio
switch (lastLoadedAsset.Type2)
{
case 28:
case 213:
{
if (enablePreview.Checked && imageTexture != null)
{
@ -737,14 +738,16 @@ namespace Unity_Studio
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)
{
lastLoadedAsset = lastSelectedItem;
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;
#endregion
#region VideoClip
case 329:
#region VideoClip and MovieTexture
case 329: //VideoClip
case 152: //MovieTexture
{
StatusStripUpdate("Only supported export.");
break;
}
#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:
{
var str = asset.ViewStruct();
@ -1545,6 +1568,12 @@ namespace Unity_Studio
exportedCount++;
}
break;
case 213: //Sprite
if (ExportSprite(asset, exportpath))
{
exportedCount++;
}
break;
default:
if (ExportRawFile(asset, exportpath))
{