AssetStudio/AssetStudioGUI/Exporter.cs

421 lines
16 KiB
C#
Raw Normal View History

2018-11-18 22:48:06 +00:00
using System.Collections.Generic;
2018-03-01 12:01:25 +00:00
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
2018-11-18 22:48:06 +00:00
using AssetStudio;
2020-03-14 08:06:21 +00:00
using TGASharpLib;
2018-03-01 12:01:25 +00:00
2018-11-18 22:48:06 +00:00
namespace AssetStudioGUI
2018-03-01 12:01:25 +00:00
{
2018-11-18 22:48:06 +00:00
internal static class Exporter
2018-03-01 12:01:25 +00:00
{
2020-08-06 13:07:37 +00:00
public static bool ExportTexture2D(AssetItem item, string exportPath)
2018-03-01 12:01:25 +00:00
{
2020-03-23 22:41:58 +00:00
var m_Texture2D = (Texture2D)item.Asset;
2020-03-25 03:18:12 +00:00
if (Properties.Settings.Default.convertTexture)
2018-03-01 12:01:25 +00:00
{
2020-03-23 22:41:58 +00:00
var bitmap = m_Texture2D.ConvertToBitmap(true);
2018-09-26 17:15:37 +00:00
if (bitmap == null)
return false;
2018-03-01 12:01:25 +00:00
ImageFormat format = null;
2020-03-25 03:18:12 +00:00
var ext = Properties.Settings.Default.convertType;
2020-03-03 03:23:36 +00:00
bool tga = false;
2018-03-01 12:01:25 +00:00
switch (ext)
{
case "BMP":
format = ImageFormat.Bmp;
break;
case "PNG":
format = ImageFormat.Png;
break;
case "JPEG":
format = ImageFormat.Jpeg;
break;
2020-03-03 03:23:36 +00:00
case "TGA":
tga = true;
break;
2018-03-01 12:01:25 +00:00
}
2020-08-06 13:07:37 +00:00
if (!TryExportFile(exportPath, item, "." + ext.ToLower(), out var exportFullPath))
2018-03-01 12:01:25 +00:00
return false;
2020-03-03 03:23:36 +00:00
if (tga)
{
2020-03-14 08:06:21 +00:00
var file = new TGA(bitmap);
2020-08-06 13:07:37 +00:00
file.Save(exportFullPath);
2020-03-03 03:23:36 +00:00
}
else
2020-08-06 13:07:37 +00:00
{
bitmap.Save(exportFullPath, format);
}
2018-03-01 12:01:25 +00:00
bitmap.Dispose();
return true;
}
2018-04-11 15:45:39 +00:00
else
2018-03-01 12:01:25 +00:00
{
2020-08-06 13:07:37 +00:00
if (!TryExportFile(exportPath, item, ".tex", out var exportFullPath))
2018-03-01 12:01:25 +00:00
return false;
2020-08-06 13:07:37 +00:00
File.WriteAllBytes(exportFullPath, m_Texture2D.image_data.GetData());
2018-03-01 12:01:25 +00:00
return true;
}
}
2018-11-18 22:48:06 +00:00
public static bool ExportAudioClip(AssetItem item, string exportPath)
2018-03-01 12:01:25 +00:00
{
2018-11-21 07:37:56 +00:00
var m_AudioClip = (AudioClip)item.Asset;
2020-03-28 05:33:37 +00:00
var m_AudioData = m_AudioClip.m_AudioData.GetData();
2018-11-21 07:37:56 +00:00
if (m_AudioData == null || m_AudioData.Length == 0)
2018-03-01 12:01:25 +00:00
return false;
2018-09-26 17:15:37 +00:00
var converter = new AudioClipConverter(m_AudioClip);
2020-04-10 10:51:43 +00:00
if (Properties.Settings.Default.convertAudio && converter.IsSupport)
2018-03-01 12:01:25 +00:00
{
2020-08-06 13:07:37 +00:00
if (!TryExportFile(exportPath, item, ".wav", out var exportFullPath))
2018-03-01 12:01:25 +00:00
return false;
2018-09-26 17:15:37 +00:00
var buffer = converter.ConvertToWav();
if (buffer == null)
2018-03-01 12:01:25 +00:00
return false;
2020-08-06 13:07:37 +00:00
File.WriteAllBytes(exportFullPath, buffer);
2018-03-01 12:01:25 +00:00
}
else
{
2020-08-06 13:07:37 +00:00
if (!TryExportFile(exportPath, item, converter.GetExtensionName(), out var exportFullPath))
2018-03-01 12:01:25 +00:00
return false;
2020-08-06 13:07:37 +00:00
File.WriteAllBytes(exportFullPath, m_AudioData);
2018-03-01 12:01:25 +00:00
}
return true;
}
2018-11-18 22:48:06 +00:00
public static bool ExportShader(AssetItem item, string exportPath)
2018-03-01 12:01:25 +00:00
{
2020-08-06 13:07:37 +00:00
if (!TryExportFile(exportPath, item, ".shader", out var exportFullPath))
2018-03-01 12:01:25 +00:00
return false;
2019-07-17 04:51:00 +00:00
var m_Shader = (Shader)item.Asset;
2018-12-11 05:01:10 +00:00
if (m_Shader.compressedBlob != null) //5.5 and up
{
var strs = ShaderConverter.ConvertMultiple(m_Shader);
for (int i = 0; i < strs.Length; i++)
{
var platformName = ShaderConverter.GetPlatformString(m_Shader.platforms[i]);
File.WriteAllText($"{exportPath}{item.Text}_{platformName}.shader", strs[i]);
}
}
else
{
var str = ShaderConverter.Convert(m_Shader);
2020-08-06 13:07:37 +00:00
File.WriteAllText(exportFullPath, str);
2018-12-11 05:01:10 +00:00
}
2018-03-01 12:01:25 +00:00
return true;
}
2018-11-18 22:48:06 +00:00
public static bool ExportTextAsset(AssetItem item, string exportPath)
2018-03-01 12:01:25 +00:00
{
2018-11-21 07:37:56 +00:00
var m_TextAsset = (TextAsset)(item.Asset);
2020-03-25 17:01:02 +00:00
var extension = ".txt";
if (Properties.Settings.Default.restoreExtensionName)
{
if (!string.IsNullOrEmpty(item.Container))
{
extension = Path.GetExtension(item.Container);
}
}
2020-08-06 13:07:37 +00:00
if (!TryExportFile(exportPath, item, extension, out var exportFullPath))
2018-03-01 12:01:25 +00:00
return false;
2020-08-06 13:07:37 +00:00
File.WriteAllBytes(exportFullPath, m_TextAsset.m_Script);
2018-03-01 12:01:25 +00:00
return true;
}
2018-11-18 22:48:06 +00:00
public static bool ExportMonoBehaviour(AssetItem item, string exportPath)
2018-03-01 12:01:25 +00:00
{
2020-08-06 13:07:37 +00:00
if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath))
2018-03-01 12:01:25 +00:00
return false;
2018-11-21 07:37:56 +00:00
var m_MonoBehaviour = (MonoBehaviour)item.Asset;
var str = m_MonoBehaviour.Dump() ?? Studio.GetScriptString(item.Asset.reader);
2020-08-06 13:07:37 +00:00
File.WriteAllText(exportFullPath, str);
2018-03-01 12:01:25 +00:00
return true;
}
2018-11-18 22:48:06 +00:00
public static bool ExportFont(AssetItem item, string exportPath)
2018-03-01 12:01:25 +00:00
{
2018-11-21 07:37:56 +00:00
var m_Font = (Font)item.Asset;
2018-03-01 12:01:25 +00:00
if (m_Font.m_FontData != null)
{
2018-11-07 21:00:53 +00:00
var extension = ".ttf";
2018-09-26 17:15:37 +00:00
if (m_Font.m_FontData[0] == 79 && m_Font.m_FontData[1] == 84 && m_Font.m_FontData[2] == 84 && m_Font.m_FontData[3] == 79)
{
extension = ".otf";
}
2020-08-06 13:07:37 +00:00
if (!TryExportFile(exportPath, item, extension, out var exportFullPath))
2018-03-01 12:01:25 +00:00
return false;
2020-08-06 13:07:37 +00:00
File.WriteAllBytes(exportFullPath, m_Font.m_FontData);
2018-03-01 12:01:25 +00:00
return true;
}
return false;
}
2018-11-18 22:48:06 +00:00
public static bool ExportMesh(AssetItem item, string exportPath)
2018-03-01 12:01:25 +00:00
{
2018-11-21 07:37:56 +00:00
var m_Mesh = (Mesh)item.Asset;
2018-03-01 12:01:25 +00:00
if (m_Mesh.m_VertexCount <= 0)
return false;
2020-08-06 13:07:37 +00:00
if (!TryExportFile(exportPath, item, ".obj", out var exportFullPath))
2018-03-01 12:01:25 +00:00
return false;
var sb = new StringBuilder();
sb.AppendLine("g " + m_Mesh.m_Name);
#region Vertices
2018-07-14 10:22:14 +00:00
if (m_Mesh.m_Vertices == null || m_Mesh.m_Vertices.Length == 0)
{
return false;
}
2018-03-01 12:01:25 +00:00
int c = 3;
if (m_Mesh.m_Vertices.Length == m_Mesh.m_VertexCount * 4)
{
c = 4;
}
for (int v = 0; v < m_Mesh.m_VertexCount; v++)
{
sb.AppendFormat("v {0} {1} {2}\r\n", -m_Mesh.m_Vertices[v * c], m_Mesh.m_Vertices[v * c + 1], m_Mesh.m_Vertices[v * c + 2]);
}
#endregion
#region UV
2019-07-27 14:54:18 +00:00
if (m_Mesh.m_UV0?.Length > 0)
2018-03-01 12:01:25 +00:00
{
2019-07-27 14:54:18 +00:00
if (m_Mesh.m_UV0.Length == m_Mesh.m_VertexCount * 2)
2018-03-01 12:01:25 +00:00
{
2019-07-27 14:54:18 +00:00
c = 2;
}
else if (m_Mesh.m_UV0.Length == m_Mesh.m_VertexCount * 3)
{
c = 3;
2018-03-01 12:01:25 +00:00
}
for (int v = 0; v < m_Mesh.m_VertexCount; v++)
{
2019-07-27 14:54:18 +00:00
sb.AppendFormat("vt {0} {1}\r\n", m_Mesh.m_UV0[v * c], m_Mesh.m_UV0[v * c + 1]);
2018-03-01 12:01:25 +00:00
}
}
#endregion
#region Normals
2019-07-27 14:54:18 +00:00
if (m_Mesh.m_Normals?.Length > 0)
2018-03-01 12:01:25 +00:00
{
if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 3)
{
c = 3;
}
else if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 4)
{
c = 4;
}
for (int v = 0; v < m_Mesh.m_VertexCount; v++)
{
sb.AppendFormat("vn {0} {1} {2}\r\n", -m_Mesh.m_Normals[v * c], m_Mesh.m_Normals[v * c + 1], m_Mesh.m_Normals[v * c + 2]);
}
}
#endregion
#region Face
int sum = 0;
for (var i = 0; i < m_Mesh.m_SubMeshes.Length; i++)
2018-03-01 12:01:25 +00:00
{
sb.AppendLine($"g {m_Mesh.m_Name}_{i}");
int indexCount = (int)m_Mesh.m_SubMeshes[i].indexCount;
var end = sum + indexCount / 3;
for (int f = sum; f < end; f++)
{
sb.AppendFormat("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\r\n", m_Mesh.m_Indices[f * 3 + 2] + 1, m_Mesh.m_Indices[f * 3 + 1] + 1, m_Mesh.m_Indices[f * 3] + 1);
}
sum = end;
}
#endregion
sb.Replace("NaN", "0");
2020-08-06 13:07:37 +00:00
File.WriteAllText(exportFullPath, sb.ToString());
2018-03-01 12:01:25 +00:00
return true;
}
2018-11-18 22:48:06 +00:00
public static bool ExportVideoClip(AssetItem item, string exportPath)
2018-03-01 12:01:25 +00:00
{
2018-11-21 07:37:56 +00:00
var m_VideoClip = (VideoClip)item.Asset;
2020-03-28 05:33:37 +00:00
var m_VideoData = m_VideoClip.m_VideoData.GetData();
2018-11-21 07:37:56 +00:00
if (m_VideoData != null && m_VideoData.Length != 0)
2018-03-01 12:01:25 +00:00
{
2020-08-06 13:07:37 +00:00
if (!TryExportFile(exportPath, item, Path.GetExtension(m_VideoClip.m_OriginalPath), out var exportFullPath))
2018-03-01 12:01:25 +00:00
return false;
2020-08-06 13:07:37 +00:00
File.WriteAllBytes(exportFullPath, m_VideoData);
2018-03-01 12:01:25 +00:00
return true;
}
return false;
}
2018-11-18 22:48:06 +00:00
public static bool ExportMovieTexture(AssetItem item, string exportPath)
2018-03-01 12:01:25 +00:00
{
2018-11-21 07:37:56 +00:00
var m_MovieTexture = (MovieTexture)item.Asset;
2020-08-06 13:07:37 +00:00
if (!TryExportFile(exportPath, item, ".ogv", out var exportFullPath))
2018-03-01 12:01:25 +00:00
return false;
2020-08-06 13:07:37 +00:00
File.WriteAllBytes(exportFullPath, m_MovieTexture.m_MovieData);
2018-03-01 12:01:25 +00:00
return true;
}
2018-11-18 22:48:06 +00:00
public static bool ExportSprite(AssetItem item, string exportPath)
2018-03-01 12:01:25 +00:00
{
ImageFormat format = null;
2020-03-25 03:18:12 +00:00
var type = Properties.Settings.Default.convertType;
2020-03-03 03:23:36 +00:00
bool tga = false;
2018-03-01 12:01:25 +00:00
switch (type)
{
case "BMP":
format = ImageFormat.Bmp;
break;
case "PNG":
format = ImageFormat.Png;
break;
case "JPEG":
format = ImageFormat.Jpeg;
break;
2020-03-03 03:23:36 +00:00
case "TGA":
tga = true;
break;
2018-03-01 12:01:25 +00:00
}
2020-08-06 13:07:37 +00:00
if (!TryExportFile(exportPath, item, "." + type.ToLower(), out var exportFullPath))
2018-03-01 12:01:25 +00:00
return false;
var bitmap = ((Sprite)item.Asset).GetImage();
2018-03-01 12:01:25 +00:00
if (bitmap != null)
{
2020-03-03 03:23:36 +00:00
if (tga)
{
2020-03-25 17:01:02 +00:00
var file = new TGA(bitmap);
2020-08-06 13:07:37 +00:00
file.Save(exportFullPath);
2020-03-03 03:23:36 +00:00
}
else
2020-08-06 13:07:37 +00:00
{
bitmap.Save(exportFullPath, format);
}
2018-11-08 01:09:55 +00:00
bitmap.Dispose();
2018-03-01 12:01:25 +00:00
return true;
}
return false;
}
2018-11-18 22:48:06 +00:00
public static bool ExportRawFile(AssetItem item, string exportPath)
2018-03-01 12:01:25 +00:00
{
2020-08-06 13:07:37 +00:00
if (!TryExportFile(exportPath, item, ".dat", out var exportFullPath))
2018-03-01 12:01:25 +00:00
return false;
2020-08-06 13:07:37 +00:00
File.WriteAllBytes(exportFullPath, item.Asset.GetRawData());
2018-03-01 12:01:25 +00:00
return true;
}
2020-08-06 13:07:37 +00:00
private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath)
2018-03-01 12:01:25 +00:00
{
2020-08-06 13:07:37 +00:00
var fileName = FixFileName(item.Text);
fullPath = Path.Combine(dir, fileName + extension);
if (!File.Exists(fullPath))
{
Directory.CreateDirectory(dir);
return true;
}
fullPath = Path.Combine(dir, fileName + item.UniqueID + extension);
if (!File.Exists(fullPath))
2018-03-01 12:01:25 +00:00
{
2020-08-06 13:07:37 +00:00
Directory.CreateDirectory(dir);
2018-03-01 12:01:25 +00:00
return true;
}
return false;
}
2018-04-06 23:51:33 +00:00
2018-11-18 22:48:06 +00:00
public static bool ExportAnimator(AssetItem item, string exportPath, List<AssetItem> animationList = null)
2018-04-11 07:52:37 +00:00
{
2020-08-06 13:07:37 +00:00
var exportFullPath = Path.Combine(exportPath, item.Text, item.Text + ".fbx");
if (File.Exists(exportFullPath))
{
exportFullPath = Path.Combine(exportPath, item.Text + item.UniqueID, item.Text + ".fbx");
}
2018-11-21 07:37:56 +00:00
var m_Animator = (Animator)item.Asset;
var convert = animationList != null ? new ModelConverter(m_Animator, animationList.Select(x => (AnimationClip)x.Asset).ToArray()) : new ModelConverter(m_Animator);
2020-08-06 13:07:37 +00:00
ExportFbx(convert, exportFullPath);
2019-07-17 04:51:00 +00:00
return true;
2018-04-11 07:52:37 +00:00
}
2019-07-17 04:51:00 +00:00
public static void ExportGameObject(GameObject gameObject, string exportPath, List<AssetItem> animationList = null)
2018-04-11 07:52:37 +00:00
{
2018-11-21 07:37:56 +00:00
var convert = animationList != null ? new ModelConverter(gameObject, animationList.Select(x => (AnimationClip)x.Asset).ToArray()) : new ModelConverter(gameObject);
2020-08-06 13:07:37 +00:00
exportPath = exportPath + FixFileName(gameObject.m_Name) + ".fbx";
2019-07-17 04:51:00 +00:00
ExportFbx(convert, exportPath);
2018-04-11 07:52:37 +00:00
}
2019-07-17 04:51:00 +00:00
public static void ExportGameObjectMerge(List<GameObject> gameObject, string exportPath, List<AssetItem> animationList = null)
{
var rootName = Path.GetFileNameWithoutExtension(exportPath);
var convert = animationList != null ? new ModelConverter(rootName, gameObject, animationList.Select(x => (AnimationClip)x.Asset).ToArray()) : new ModelConverter(rootName, gameObject);
ExportFbx(convert, exportPath);
}
private static void ExportFbx(IImported convert, string exportPath)
2018-04-06 23:51:33 +00:00
{
2020-03-25 03:18:12 +00:00
var eulerFilter = Properties.Settings.Default.eulerFilter;
var filterPrecision = (float)Properties.Settings.Default.filterPrecision;
var exportAllNodes = Properties.Settings.Default.exportAllNodes;
var exportSkins = Properties.Settings.Default.exportSkins;
var exportAnimations = Properties.Settings.Default.exportAnimations;
var exportBlendShape = Properties.Settings.Default.exportBlendShape;
var castToBone = Properties.Settings.Default.castToBone;
var boneSize = (int)Properties.Settings.Default.boneSize;
var scaleFactor = (float)Properties.Settings.Default.scaleFactor;
var fbxVersion = Properties.Settings.Default.fbxVersion;
var fbxFormat = Properties.Settings.Default.fbxFormat;
2019-07-28 10:55:08 +00:00
ModelExporter.ExportFbx(exportPath, convert, eulerFilter, filterPrecision,
exportAllNodes, exportSkins, exportAnimations, exportBlendShape, castToBone, boneSize, scaleFactor, fbxVersion, fbxFormat == 1);
2018-04-06 23:51:33 +00:00
}
2019-08-06 09:43:51 +00:00
public static bool ExportDumpFile(AssetItem item, string exportPath)
{
2020-08-06 13:07:37 +00:00
if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath))
2019-08-06 09:43:51 +00:00
return false;
var str = item.Asset.Dump();
if (str != null)
{
2020-08-06 13:07:37 +00:00
File.WriteAllText(exportFullPath, str);
2019-08-06 09:43:51 +00:00
return true;
}
return false;
}
2020-03-25 17:01:02 +00:00
public static bool ExportConvertFile(AssetItem item, string exportPath)
{
switch (item.Type)
{
case ClassIDType.Texture2D:
return ExportTexture2D(item, exportPath);
case ClassIDType.AudioClip:
return ExportAudioClip(item, exportPath);
case ClassIDType.Shader:
return ExportShader(item, exportPath);
case ClassIDType.TextAsset:
return ExportTextAsset(item, exportPath);
case ClassIDType.MonoBehaviour:
return ExportMonoBehaviour(item, exportPath);
case ClassIDType.Font:
return ExportFont(item, exportPath);
case ClassIDType.Mesh:
return ExportMesh(item, exportPath);
case ClassIDType.VideoClip:
return ExportVideoClip(item, exportPath);
case ClassIDType.MovieTexture:
return ExportMovieTexture(item, exportPath);
case ClassIDType.Sprite:
return ExportSprite(item, exportPath);
case ClassIDType.Animator:
return ExportAnimator(item, exportPath);
case ClassIDType.AnimationClip:
return false;
default:
return ExportRawFile(item, exportPath);
}
}
2020-08-06 13:07:37 +00:00
public static string FixFileName(string str)
{
if (str.Length >= 260) return Path.GetRandomFileName();
return Path.GetInvalidFileNameChars().Aggregate(str, (current, c) => current.Replace(c, '_'));
}
2018-03-01 12:01:25 +00:00
}
}