Some improvements

This commit is contained in:
Perfare 2018-04-21 21:52:15 +08:00
parent 87d6a26232
commit 52ba354dc5
6 changed files with 212 additions and 210 deletions

View File

@ -211,6 +211,7 @@
<Compile Include="StudioClasses\AssetsFile.cs" /> <Compile Include="StudioClasses\AssetsFile.cs" />
<Compile Include="StudioClasses\Texture2DConverter.cs" /> <Compile Include="StudioClasses\Texture2DConverter.cs" />
<Compile Include="StudioClasses\WebFile.cs" /> <Compile Include="StudioClasses\WebFile.cs" />
<Compile Include="TreeViewExtensions.cs" />
<EmbeddedResource Include="AssetStudioForm.resx"> <EmbeddedResource Include="AssetStudioForm.resx">
<DependentUpon>AssetStudioForm.cs</DependentUpon> <DependentUpon>AssetStudioForm.cs</DependentUpon>
<SubType>Designer</SubType> <SubType>Designer</SubType>

View File

@ -211,6 +211,7 @@
<Compile Include="AssetStudioForm.Designer.cs"> <Compile Include="AssetStudioForm.Designer.cs">
<DependentUpon>AssetStudioForm.cs</DependentUpon> <DependentUpon>AssetStudioForm.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="TreeViewExtensions.cs" />
<EmbeddedResource Include="ExportOptions.resx"> <EmbeddedResource Include="ExportOptions.resx">
<DependentUpon>ExportOptions.cs</DependentUpon> <DependentUpon>ExportOptions.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>

View File

@ -30,34 +30,27 @@ namespace AssetStudio
private FMOD.MODE loopMode = FMOD.MODE.LOOP_OFF; private FMOD.MODE loopMode = FMOD.MODE.LOOP_OFF;
private uint FMODlenms; private uint FMODlenms;
private float FMODVolume = 0.8f; private float FMODVolume = 0.8f;
private float FMODfrequency;
private Bitmap imageTexture; private Bitmap imageTexture;
#region OpenTK variables #region OpenTK
int pgmID, pgmColorID, pgmBlackID; private int pgmID, pgmColorID, pgmBlackID;
int attributeVertexPosition; private int attributeVertexPosition;
int attributeNormalDirection; private int attributeNormalDirection;
int attributeVertexColor; private int attributeVertexColor;
int uniformModelMatrix; private int uniformModelMatrix;
int uniformViewMatrix; private int uniformViewMatrix;
int vao; private int vao;
int vboPositions; private Vector3[] vertexData;
int vboNormals; private Vector3[] normalData;
int vboColors; private Vector3[] normal2Data;
int vboModelMatrix; private Vector4[] colorData;
int vboViewMatrix; private Matrix4 modelMatrixData;
int eboElements; private Matrix4 viewMatrixData;
Vector3[] vertexData; private int[] indiceData;
Vector3[] normalData; private int wireFrameMode;
Vector3[] normal2Data; private int shadeMode;
Vector4[] colorData; private int normalMode;
Matrix4 modelMatrixData;
Matrix4 viewMatrixData;
int[] indiceData;
int wireFrameMode;
int shadeMode;
int normalMode;
#endregion #endregion
//asset list sorting helpers //asset list sorting helpers
@ -70,8 +63,6 @@ namespace AssetStudio
private int nextGObject; private int nextGObject;
private List<GameObject> treeSrcResults = new List<GameObject>(); private List<GameObject> treeSrcResults = new List<GameObject>();
private PrivateFontCollection pfc = new PrivateFontCollection();
[DllImport("gdi32.dll")] [DllImport("gdi32.dll")]
private static extern IntPtr AddFontMemResourceEx(IntPtr pbFont, uint cbFont, IntPtr pdv, [In] ref uint pcFonts); private static extern IntPtr AddFontMemResourceEx(IntPtr pbFont, uint cbFont, IntPtr pdv, [In] ref uint pcFonts);
@ -176,16 +167,12 @@ namespace AssetStudio
return; return;
} }
bool optionLoadAssetsMenuItem = !dontLoadAssetsMenuItem.Checked; BuildAssetStructures(!dontLoadAssetsMenuItem.Checked, displayAll.Checked, !dontBuildHierarchyMenuItem.Checked, buildClassStructuresMenuItem.Checked,
bool optionDisplayAll = displayAll.Checked; displayOriginalName.Checked, out var fileNodes);
bool optionBuildHierarchyMenuItem = !dontBuildHierarchyMenuItem.Checked;
bool optionBuildClassStructuresMenuItem = buildClassStructuresMenuItem.Checked;
BuildAssetStructures(optionLoadAssetsMenuItem, optionDisplayAll, optionBuildHierarchyMenuItem, optionBuildClassStructuresMenuItem, displayOriginalName.Checked);
BeginInvoke(new Action(() => BeginInvoke(new Action(() =>
{ {
if (productName != "") if (!string.IsNullOrEmpty(productName))
{ {
Text = $"AssetStudio - {productName} - {assetsfileList[0].m_Version} - {assetsfileList[0].platformStr}"; Text = $"AssetStudio - {productName} - {assetsfileList[0].m_Version} - {assetsfileList[0].platformStr}";
} }
@ -203,7 +190,10 @@ namespace AssetStudio
{ {
sceneTreeView.BeginUpdate(); sceneTreeView.BeginUpdate();
sceneTreeView.Nodes.AddRange(fileNodes.ToArray()); sceneTreeView.Nodes.AddRange(fileNodes.ToArray());
fileNodes.Clear(); foreach (TreeNode node in sceneTreeView.Nodes)
{
node.HideCheckBox();
}
sceneTreeView.EndUpdate(); sceneTreeView.EndUpdate();
} }
if (buildClassStructuresMenuItem.Checked) if (buildClassStructuresMenuItem.Checked)
@ -676,7 +666,6 @@ namespace AssetStudio
assetInfoLabel.Text = null; assetInfoLabel.Text = null;
textPreviewBox.Visible = false; textPreviewBox.Visible = false;
fontPreviewBox.Visible = false; fontPreviewBox.Visible = false;
pfc.Dispose();
FMODpanel.Visible = false; FMODpanel.Visible = false;
glControl1.Visible = false; glControl1.Visible = false;
lastLoadedAsset = null; lastLoadedAsset = null;
@ -759,10 +748,10 @@ namespace AssetStudio
FMODpanel.Visible = true; FMODpanel.Visible = true;
result = channel.getFrequency(out FMODfrequency); result = channel.getFrequency(out var frequency);
if (ERRCHECK(result)) { break; } if (ERRCHECK(result)) { break; }
FMODinfoLabel.Text = FMODfrequency + " Hz"; FMODinfoLabel.Text = frequency + " Hz";
FMODtimerLabel.Text = $"0:0.0 / {FMODlenms / 1000 / 60}:{FMODlenms / 1000 % 60}.{FMODlenms / 10 % 100}"; FMODtimerLabel.Text = $"0:0.0 / {FMODlenms / 1000 / 60}:{FMODlenms / 1000 % 60}.{FMODlenms / 10 % 100}";
break; break;
} }
@ -808,38 +797,38 @@ namespace AssetStudio
var re = AddFontMemResourceEx(data, (uint)m_Font.m_FontData.Length, IntPtr.Zero, ref cFonts); var re = AddFontMemResourceEx(data, (uint)m_Font.m_FontData.Length, IntPtr.Zero, ref cFonts);
if (re != IntPtr.Zero) if (re != IntPtr.Zero)
{ {
pfc = new PrivateFontCollection(); using (var pfc = new PrivateFontCollection())
pfc.AddMemoryFont(data, m_Font.m_FontData.Length);
Marshal.FreeCoTaskMem(data);
if (pfc.Families.Length > 0)
{ {
//textPreviewBox.Font = new Font(pfc.Families[0], 16, FontStyle.Regular); pfc.AddMemoryFont(data, m_Font.m_FontData.Length);
//textPreviewBox.Text = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWYZ\r\n1234567890.:,;'\"(!?)+-*/=\r\nThe quick brown fox jumps over the lazy dog. 1234567890"; Marshal.FreeCoTaskMem(data);
fontPreviewBox.SelectionStart = 0; if (pfc.Families.Length > 0)
fontPreviewBox.SelectionLength = 80; {
fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 16, FontStyle.Regular); fontPreviewBox.SelectionStart = 0;
fontPreviewBox.SelectionStart = 81; fontPreviewBox.SelectionLength = 80;
fontPreviewBox.SelectionLength = 56; fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 16, FontStyle.Regular);
fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 12, FontStyle.Regular); fontPreviewBox.SelectionStart = 81;
fontPreviewBox.SelectionStart = 138; fontPreviewBox.SelectionLength = 56;
fontPreviewBox.SelectionLength = 56; fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 12, FontStyle.Regular);
fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 18, FontStyle.Regular); fontPreviewBox.SelectionStart = 138;
fontPreviewBox.SelectionStart = 195; fontPreviewBox.SelectionLength = 56;
fontPreviewBox.SelectionLength = 56; fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 18, FontStyle.Regular);
fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 24, FontStyle.Regular); fontPreviewBox.SelectionStart = 195;
fontPreviewBox.SelectionStart = 252; fontPreviewBox.SelectionLength = 56;
fontPreviewBox.SelectionLength = 56; fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 24, FontStyle.Regular);
fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 36, FontStyle.Regular); fontPreviewBox.SelectionStart = 252;
fontPreviewBox.SelectionStart = 309; fontPreviewBox.SelectionLength = 56;
fontPreviewBox.SelectionLength = 56; fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 36, FontStyle.Regular);
fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 48, FontStyle.Regular); fontPreviewBox.SelectionStart = 309;
fontPreviewBox.SelectionStart = 366; fontPreviewBox.SelectionLength = 56;
fontPreviewBox.SelectionLength = 56; fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 48, FontStyle.Regular);
fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 60, FontStyle.Regular); fontPreviewBox.SelectionStart = 366;
fontPreviewBox.SelectionStart = 423; fontPreviewBox.SelectionLength = 56;
fontPreviewBox.SelectionLength = 55; fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 60, FontStyle.Regular);
fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 72, FontStyle.Regular); fontPreviewBox.SelectionStart = 423;
fontPreviewBox.Visible = true; fontPreviewBox.SelectionLength = 55;
fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 72, FontStyle.Regular);
fontPreviewBox.Visible = true;
}
} }
break; break;
} }
@ -1576,20 +1565,20 @@ namespace AssetStudio
GL.DeleteVertexArray(vao); GL.DeleteVertexArray(vao);
GL.GenVertexArrays(1, out vao); GL.GenVertexArrays(1, out vao);
GL.BindVertexArray(vao); GL.BindVertexArray(vao);
createVBO(out vboPositions, vertexData, attributeVertexPosition); createVBO(out var vboPositions, vertexData, attributeVertexPosition);
if (normalMode == 0) if (normalMode == 0)
{ {
createVBO(out vboNormals, normal2Data, attributeNormalDirection); createVBO(out var vboNormals, normal2Data, attributeNormalDirection);
} }
else else
{ {
if (normalData != null) if (normalData != null)
createVBO(out vboNormals, normalData, attributeNormalDirection); createVBO(out var vboNormals, normalData, attributeNormalDirection);
} }
createVBO(out vboColors, colorData, attributeVertexColor); createVBO(out var vboColors, colorData, attributeVertexColor);
createVBO(out vboModelMatrix, modelMatrixData, uniformModelMatrix); createVBO(out var vboModelMatrix, modelMatrixData, uniformModelMatrix);
createVBO(out vboViewMatrix, viewMatrixData, uniformViewMatrix); createVBO(out var vboViewMatrix, viewMatrixData, uniformViewMatrix);
createEBO(out eboElements, indiceData); createEBO(out var eboElements, indiceData);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0); GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.BindVertexArray(0); GL.BindVertexArray(0);
} }
@ -1826,7 +1815,7 @@ namespace AssetStudio
var savePath = saveFolderDialog1.Folder + "\\"; var savePath = saveFolderDialog1.Folder + "\\";
progressBar1.Value = 0; progressBar1.Value = 0;
progressBar1.Maximum = sceneTreeView.Nodes.Count; progressBar1.Maximum = sceneTreeView.Nodes.Count;
ExportSplitObjectsNew(savePath, sceneTreeView.Nodes); ExportSplitObjects(savePath, sceneTreeView.Nodes, true);
} }
} }
else else

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Web.Script.Serialization;
using static AssetStudio.Studio; using static AssetStudio.Studio;
using static AssetStudio.Exporter; using static AssetStudio.Exporter;
@ -13,6 +14,15 @@ namespace AssetStudio
public static void WriteFBX(string FBXfile, List<GameObject> gameObjects) public static void WriteFBX(string FBXfile, List<GameObject> gameObjects)
{ {
var timestamp = DateTime.Now; var timestamp = DateTime.Now;
Dictionary<string, Dictionary<string, string>> jsonMats = null;
if (File.Exists(mainPath + "\\materials.json"))
{
using (var reader = File.OpenText(mainPath + "\\materials.json"))
{
var matLine = reader.ReadToEnd();
jsonMats = new JavaScriptSerializer().Deserialize<Dictionary<string, Dictionary<string, string>>>(matLine);
}
}
using (StreamWriter FBXwriter = new StreamWriter(FBXfile)) using (StreamWriter FBXwriter = new StreamWriter(FBXfile))
{ {

View File

@ -5,7 +5,6 @@ using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Web.Script.Serialization;
using System.Windows.Forms; using System.Windows.Forms;
using static AssetStudio.Exporter; using static AssetStudio.Exporter;
@ -19,13 +18,9 @@ namespace AssetStudio
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
public static string productName = "";
public static string mainPath = "";
public static List<GameObject> fileNodes = new List<GameObject>();
public static Dictionary<string, Dictionary<string, string>> jsonMats;
public static Dictionary<string, SortedDictionary<int, ClassStruct>> AllClassStructures = new Dictionary<string, SortedDictionary<int, ClassStruct>>(); public static Dictionary<string, SortedDictionary<int, ClassStruct>> AllClassStructures = new Dictionary<string, SortedDictionary<int, ClassStruct>>();
public static string mainPath;
public static string productName = "";
//UI //UI
public static Action<int> SetProgressBarValue; public static Action<int> SetProgressBarValue;
@ -154,10 +149,12 @@ namespace AssetStudio
return extractedCount; return extractedCount;
} }
public static void BuildAssetStructures(bool loadAssetsMenuItem, bool displayAll, bool buildHierarchyMenuItem, bool buildClassStructuresMenuItem, bool displayOriginalName) public static void BuildAssetStructures(bool loadAssets, bool displayAll, bool buildHierarchy, bool buildClassStructures, bool displayOriginalName, out List<GameObject> fileNodes)
{ {
fileNodes = null;
#region first loop - read asset data & create list #region first loop - read asset data & create list
if (loadAssetsMenuItem) if (loadAssets)
{ {
SetProgressBarValue(0); SetProgressBarValue(0);
SetProgressBarMaximum(assetsfileList.Sum(x => x.preloadTable.Values.Count)); SetProgressBarMaximum(assetsfileList.Sum(x => x.preloadTable.Values.Count));
@ -325,115 +322,107 @@ namespace AssetStudio
#endregion #endregion
#region second loop - build tree structure #region second loop - build tree structure
fileNodes = new List<GameObject>(); if (buildHierarchy)
if (buildHierarchyMenuItem)
{ {
SetProgressBarValue(0); fileNodes = new List<GameObject>();
SetProgressBarMaximum(assetsfileList.Sum(x => x.GameObjectList.Values.Count)); var gameObjectCount = assetsfileList.Sum(x => x.GameObjectList.Values.Count);
StatusStripUpdate("Building tree structure..."); if (gameObjectCount > 0)
foreach (var assetsFile in assetsfileList)
{ {
GameObject fileNode = new GameObject(null); SetProgressBarValue(0);
fileNode.Text = Path.GetFileName(assetsFile.filePath); SetProgressBarMaximum(gameObjectCount);
fileNode.m_Name = "RootNode"; StatusStripUpdate("Building tree structure...");
foreach (var m_GameObject in assetsFile.GameObjectList.Values) foreach (var assetsFile in assetsfileList)
{ {
foreach (var m_Component in m_GameObject.m_Components) GameObject fileNode = new GameObject(null);
fileNode.Text = Path.GetFileName(assetsFile.filePath);
fileNode.m_Name = "RootNode";
foreach (var m_GameObject in assetsFile.GameObjectList.Values)
{ {
if (m_Component.m_FileID >= 0 && m_Component.m_FileID < assetsfileList.Count) foreach (var m_Component in m_GameObject.m_Components)
{ {
var sourceFile = assetsfileList[m_Component.m_FileID]; if (m_Component.m_FileID >= 0 && m_Component.m_FileID < assetsfileList.Count)
if (sourceFile.preloadTable.TryGetValue(m_Component.m_PathID, out var asset))
{ {
switch (asset.Type) var sourceFile = assetsfileList[m_Component.m_FileID];
if (sourceFile.preloadTable.TryGetValue(m_Component.m_PathID, out var asset))
{ {
case ClassIDReference.Transform: switch (asset.Type)
{ {
m_GameObject.m_Transform = m_Component; case ClassIDReference.Transform:
break;
}
case ClassIDReference.MeshRenderer:
{
m_GameObject.m_MeshRenderer = m_Component;
break;
}
case ClassIDReference.MeshFilter:
{
m_GameObject.m_MeshFilter = m_Component;
if (assetsfileList.TryGetPD(m_Component, out var assetPreloadData))
{ {
var m_MeshFilter = new MeshFilter(assetPreloadData); m_GameObject.m_Transform = m_Component;
if (assetsfileList.TryGetPD(m_MeshFilter.m_Mesh, out assetPreloadData)) break;
{
assetPreloadData.gameObject = m_GameObject;
}
} }
break; case ClassIDReference.MeshRenderer:
}
case ClassIDReference.SkinnedMeshRenderer:
{
m_GameObject.m_SkinnedMeshRenderer = m_Component;
if (assetsfileList.TryGetPD(m_Component, out var assetPreloadData))
{ {
var m_SkinnedMeshRenderer = new SkinnedMeshRenderer(assetPreloadData); m_GameObject.m_MeshRenderer = m_Component;
if (assetsfileList.TryGetPD(m_SkinnedMeshRenderer.m_Mesh, out assetPreloadData)) break;
{
assetPreloadData.gameObject = m_GameObject;
}
} }
break; case ClassIDReference.MeshFilter:
} {
case ClassIDReference.Animator: m_GameObject.m_MeshFilter = m_Component;
{ if (assetsfileList.TryGetPD(m_Component, out var assetPreloadData))
m_GameObject.m_Animator = m_Component; {
asset.Text = m_GameObject.asset.Text; var m_MeshFilter = new MeshFilter(assetPreloadData);
break; if (assetsfileList.TryGetPD(m_MeshFilter.m_Mesh, out assetPreloadData))
} {
assetPreloadData.gameObject = m_GameObject;
}
}
break;
}
case ClassIDReference.SkinnedMeshRenderer:
{
m_GameObject.m_SkinnedMeshRenderer = m_Component;
if (assetsfileList.TryGetPD(m_Component, out var assetPreloadData))
{
var m_SkinnedMeshRenderer = new SkinnedMeshRenderer(assetPreloadData);
if (assetsfileList.TryGetPD(m_SkinnedMeshRenderer.m_Mesh, out assetPreloadData))
{
assetPreloadData.gameObject = m_GameObject;
}
}
break;
}
case ClassIDReference.Animator:
{
m_GameObject.m_Animator = m_Component;
asset.Text = m_GameObject.asset.Text;
break;
}
}
} }
} }
} }
}
var parentNode = fileNode; var parentNode = fileNode;
if (assetsfileList.TryGetTransform(m_GameObject.m_Transform, out var m_Transform)) if (assetsfileList.TryGetTransform(m_GameObject.m_Transform, out var m_Transform))
{
if (assetsfileList.TryGetTransform(m_Transform.m_Father, out var m_Father))
{ {
//GameObject Parent; if (assetsfileList.TryGetTransform(m_Transform.m_Father, out var m_Father))
if (assetsfileList.TryGetGameObject(m_Father.m_GameObject, out parentNode))
{ {
//parentNode = Parent; if (assetsfileList.TryGetGameObject(m_Father.m_GameObject, out parentNode))
{
}
} }
} }
parentNode.Nodes.Add(m_GameObject);
ProgressBarPerformStep();
} }
parentNode.Nodes.Add(m_GameObject); if (fileNode.Nodes.Count > 0)
ProgressBarPerformStep(); {
fileNodes.Add(fileNode);
}
} }
if (fileNode.Nodes.Count > 0)
{
fileNodes.Add(fileNode);
}
}
if (File.Exists(mainPath + "\\materials.json"))
{
string matLine;
using (StreamReader reader = File.OpenText(mainPath + "\\materials.json"))
{
matLine = reader.ReadToEnd();
}
jsonMats = new JavaScriptSerializer().Deserialize<Dictionary<string, Dictionary<string, string>>>(matLine);
} }
} }
#endregion #endregion
#region build list of class strucutres #region build list of class strucutres
if (buildClassStructuresMenuItem) if (buildClassStructures)
{ {
//group class structures by versionv //group class structures by versionv
foreach (var assetsFile in assetsfileList) foreach (var assetsFile in assetsfileList)
@ -595,7 +584,7 @@ namespace AssetStudio
}); });
} }
public static void ExportSplitObjects(string savePath, TreeNodeCollection nodes) public static void ExportSplitObjects(string savePath, TreeNodeCollection nodes, bool isNew = false)
{ {
ThreadPool.QueueUserWorkItem(state => ThreadPool.QueueUserWorkItem(state =>
{ {
@ -629,7 +618,10 @@ namespace AssetStudio
Directory.CreateDirectory(targetPath); Directory.CreateDirectory(targetPath);
//导出FBX //导出FBX
StatusStripUpdate($"Exporting {filename}.fbx"); StatusStripUpdate($"Exporting {filename}.fbx");
FBXExporter.WriteFBX($"{targetPath}{filename}.fbx", gameObjects); if (isNew)
ExportGameObject((GameObject)j, targetPath);
else
FBXExporter.WriteFBX($"{targetPath}{filename}.fbx", gameObjects);
StatusStripUpdate($"Finished exporting {filename}.fbx"); StatusStripUpdate($"Finished exporting {filename}.fbx");
} }
ProgressBarPerformStep(); ProgressBarPerformStep();
@ -637,48 +629,6 @@ namespace AssetStudio
}); });
} }
public static void ExportSplitObjectsNew(string savePath, TreeNodeCollection nodes)
{
ThreadPool.QueueUserWorkItem(state =>
{
foreach (TreeNode node in nodes)
{
//遍历一级子节点
foreach (TreeNode j in node.Nodes)
{
//收集所有子节点
var gameObjects = new List<GameObject>();
CollectNode(j, gameObjects);
//跳过一些不需要导出的object
if (gameObjects.All(x => x.m_SkinnedMeshRenderer == null && x.m_MeshFilter == null))
continue;
//处理非法文件名
var filename = FixFileName(j.Text);
//每个文件存放在单独的文件夹
var targetPath = $"{savePath}{filename}\\";
//重名文件处理
for (int i = 1; ; i++)
{
if (Directory.Exists(targetPath))
{
targetPath = $"{savePath}{filename} ({i})\\";
}
else
{
break;
}
}
Directory.CreateDirectory(targetPath);
//导出FBX
StatusStripUpdate($"Exporting {j.Text}.fbx");
ExportGameObject((GameObject)j, targetPath);
StatusStripUpdate($"Finished exporting {j.Text}.fbx");
}
ProgressBarPerformStep();
}
});
}
private static void CollectNode(TreeNode node, List<GameObject> gameObjects) private static void CollectNode(TreeNode node, List<GameObject> gameObjects)
{ {
gameObjects.Add((GameObject)node); gameObjects.Add((GameObject)node);

View File

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
namespace AssetStudio
{
public static class TreeViewExtensions
{
private const int TVIF_STATE = 0x8;
private const int TVIS_STATEIMAGEMASK = 0xF000;
private const int TV_FIRST = 0x1100;
private const int TVM_SETITEM = TV_FIRST + 63;
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Auto)]
private struct TVITEM
{
public int mask;
public IntPtr hItem;
public int state;
public int stateMask;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpszText;
public int cchTextMax;
public int iImage;
public int iSelectedImage;
public int cChildren;
public IntPtr lParam;
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref TVITEM lParam);
/// <summary>
/// Hides the checkbox for the specified node on a TreeView control.
/// </summary>
public static void HideCheckBox(this TreeNode node)
{
var tvi = new TVITEM
{
hItem = node.Handle,
mask = TVIF_STATE,
stateMask = TVIS_STATEIMAGEMASK,
state = 0
};
SendMessage(node.TreeView.Handle, TVM_SETITEM, IntPtr.Zero, ref tvi);
}
}
}